diff --git a/.gitignore b/.gitignore index f48d43c..35206c6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /qtwebengine-opensource-src-5.9.1-clean.tar.xz /qtwebengine-opensource-src-5.9.2-clean.tar.xz /qtwebengine-opensource-src-5.9.3-clean.tar.xz +/qtwebengine-everywhere-src-5.10.0-clean.tar.xz diff --git a/clean_qtwebengine.sh b/clean_qtwebengine.sh index 084a619..cc3fe6a 100755 --- a/clean_qtwebengine.sh +++ b/clean_qtwebengine.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2015-2016 Kevin Kofler +# Copyright 2015-2017 Kevin Kofler # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including @@ -21,11 +21,11 @@ if [ -z "$1" ] ; then echo "usage: ./clean_qtwebengine.sh VERSION" - echo "e.g.: ./clean_qtwebengine.sh 5.7.0" + echo "e.g.: ./clean_qtwebengine.sh 5.10.0" exit 1 fi -DIRNAME="qtwebengine-opensource-src-$1" +DIRNAME="qtwebengine-everywhere-src-$1" echo "removing $DIRNAME" rm -rf "$DIRNAME" || exit $? diff --git a/get_free_ffmpeg_source_files.py b/get_free_ffmpeg_source_files.py index 5a0e421..76c73ae 100755 --- a/get_free_ffmpeg_source_files.py +++ b/get_free_ffmpeg_source_files.py @@ -60,7 +60,7 @@ def parse_ffmpeg_gyni_file(gyni_path, arch_not_arm): if inserted: break limitations = ['ffmpeg_branding == "Chrome"', 'ffmpeg_branding == "ChromeOS"'] - if ('is_linux' in condition) and not any(limitation in condition for limitation in limitations): + if ('use_linux_config' in condition) and not any(limitation in condition for limitation in limitations): if (arch_not_arm): if ('x64' in condition) or ('x86' in condition): parse_sources (block[1], output_sources, arch_not_arm) @@ -69,6 +69,10 @@ def parse_ffmpeg_gyni_file(gyni_path, arch_not_arm): parse_sources (block[1], output_sources, arch_not_arm) inserted = True + if len(output_sources) == 0: + sys.stderr.write("Something went wrong, no sources parsed!\n") + sys.exit(1) + print ' '.join(output_sources) diff --git a/qt5-qtwebengine.spec b/qt5-qtwebengine.spec index fe97339..05ca77d 100644 --- a/qt5-qtwebengine.spec +++ b/qt5-qtwebengine.spec @@ -10,14 +10,10 @@ %global docs 1 %endif -%if 0%{?fedora} > 24 # need libvpx >= 1.6.0 %global use_system_libvpx 1 -%endif -%if 0%{?fedora} > 23 -# need libwebp >= 0.5.1 +# need libwebp >= 0.6.0 %global use_system_libwebp 1 -%endif # NEON support on ARM (detected at runtime) - disable this if you are hitting # FTBFS due to e.g. GCC bug https://bugzilla.redhat.com/show_bug.cgi?id=1282495 @@ -55,8 +51,8 @@ Summary: Qt5 - QtWebEngine components Name: qt5-qtwebengine -Version: 5.9.3 -Release: 5%{?dist} +Version: 5.10.0 +Release: 1%{?dist} # See LICENSE.GPL LICENSE.LGPL LGPL_EXCEPTION.txt, for details # See also http://qt-project.org/doc/qt-5.0/qtdoc/licensing.html @@ -64,9 +60,9 @@ Release: 5%{?dist} License: (LGPLv2 with exceptions or GPLv3 with exceptions) and BSD and LGPLv2+ and ASL 2.0 and IJG and MIT and GPLv2+ and ISC and OpenSSL and (MPLv1.1 or GPLv2 or LGPLv2) URL: http://www.qt.io # cleaned tarball with patent-encumbered codecs removed from the bundled FFmpeg -# wget http://download.qt.io/official_releases/qt/5.9/5.9.3/submodules/qtwebengine-opensource-src-5.9.3.tar.xz -# ./clean_qtwebengine.sh 5.9.3 -Source0: qtwebengine-opensource-src-%{version}-clean.tar.xz +# wget http://download.qt.io/official_releases/qt/5.10/5.10.0/submodules/qtwebengine-everywhere-src-5.10.0.tar.xz +# ./clean_qtwebengine.sh 5.10.0 +Source0: qtwebengine-everywhere-src-%{version}-clean.tar.xz # cleanup scripts used above Source1: clean_qtwebengine.sh Source2: clean_ffmpeg.sh @@ -74,7 +70,7 @@ Source3: get_free_ffmpeg_source_files.py # macros Source10: macros.qt5-qtwebengine # some tweaks to linux.pri (system yasm, link libpci, run unbundling script) -Patch0: qtwebengine-opensource-src-5.9.2-linux-pri.patch +Patch0: qtwebengine-everywhere-src-5.10.0-linux-pri.patch # quick hack to avoid checking for the nonexistent icudtl.dat and silence the # resulting warnings - not upstreamable as is because it removes the fallback # mechanism for the ICU data directory (which is not used in our builds because @@ -89,18 +85,18 @@ Patch3: qtwebengine-opensource-src-5.9.0-no-neon.patch # use the system NSPR prtime (based on Debian patch) # We already depend on NSPR, so it is useless to copy these functions here. # Debian uses this just fine, and I don't see relevant modifications either. -Patch4: qtwebengine-opensource-src-5.9.0-system-nspr-prtime.patch +Patch4: qtwebengine-everywhere-src-5.10.0-system-nspr-prtime.patch # use the system ICU UTF functions # We already depend on ICU, so it is useless to copy these functions here. # I checked the history of that directory, and other than the renames I am # undoing, there were no modifications at all. Must be applied after Patch4. -Patch5: qtwebengine-opensource-src-5.9.0-system-icu-utf.patch +Patch5: qtwebengine-everywhere-src-5.10.0-system-icu-utf.patch # do not require SSE2 on i686 # cumulative revert of upstream reviews 187423002, 308003004, 511773002 (parts -# relevant to QtWebEngine only), 516543004, 1152053004 and 1161853008, along -# with some custom fixes and improvements +# relevant to QtWebEngine only), 516543004, 1152053004 and 1161853008, and V8 +# Gerrit review 575756, along with some custom fixes and improvements # also build V8 shared and twice on i686 (once for x87, once for SSE2) -Patch6: qtwebengine-opensource-src-5.9.1-no-sse2.patch +Patch6: qtwebengine-everywhere-src-5.10.0-no-sse2.patch # fix missing ARM -mfpu setting Patch9: qtwebengine-opensource-src-5.9.2-arm-fpu-fix.patch # remove Android dependencies from openmax_dl ARM NEON detection (detect.c) @@ -108,24 +104,16 @@ Patch10: qtwebengine-opensource-src-5.9.0-openmax-dl-neon.patch # restore NEON runtime detection in Skia: revert upstream review 1952953004, # restore the non-Android Linux NEON runtime detection code lost in upstream # review 1890483002, also add VFPv4 runtime detection -Patch11: qtwebengine-opensource-src-5.9.0-skia-neon.patch +Patch11: qtwebengine-everywhere-src-5.10.0-skia-neon.patch # webrtc: enable the CPU feature detection for ARM Linux also for Chromium Patch12: qtwebengine-opensource-src-5.9.0-webrtc-neon-detect.patch # Force verbose output from the GN bootstrap process -Patch21: qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose.patch -# Fix FTBFS with Qt 5.7 -Patch22: qtwebengine-opensource-src-5.9.2-qt57.patch +Patch21: qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose.patch # drop support for obsolete Unicode "aspirational scripts" (dropped in UTS 31), # fixes #error with ICU >= 60 (which was a reminder to double-check the list) # see: http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts # backport of: https://chromium-review.googlesource.com/c/chromium/src/+/731871 -# For 5.10, refetch the patch instead of forward-porting the backport. -Patch100: qtwebengine-opensource-src-5.9.3-no-aspirational-scripts.patch - -%if 0%{?fedora} && 0%{?fedora} < 25 -# work around missing qt5_qtwebengine_arches macro on F24 -%{!?qt5_qtwebengine_arches:%global qt5_qtwebengine_arches %{ix86} x86_64 %{arm} aarch64 mips mipsel mips64el} -%endif +Patch100: qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts.patch # handled by qt5-srpm-macros, which defines %%qt5_qtwebengine_arches ExclusiveArch: %{qt5_qtwebengine_arches} @@ -212,11 +200,11 @@ BuildRequires: pkgconfig(vpx) >= 1.6.0 # Of course, Chromium itself is bundled. It cannot be unbundled because it is # not a library, but forked (modified) application code. -# Some security fixes (up to version 62.0.3202.89) are backported, see: -# http://code.qt.io/cgit/qt/qtwebengine-chromium.git/log/?h=56-based -# see dist/changes-5.9.3 for the version numbers (base, security fixes) and for +# Some security fixes (up to version 62.0.3202.94) are backported, see: +# http://code.qt.io/cgit/qt/qtwebengine-chromium.git/log/?h=61-based +# see dist/changes-5.10.0 for the version numbers (base, security fixes) and for # a list of CVEs fixed by the added security backports -Provides: bundled(chromium) = 56.0.2924.122 +Provides: bundled(chromium) = 61.0.3163.140 # Bundled in src/3rdparty/chromium/third_party: # Check src/3rdparty/chromium/third_party/*/README.chromium for version numbers, @@ -236,32 +224,31 @@ Provides: bundled(brotli) # out. See clean_qtwebengine.sh, clean_ffmpeg.sh, and # get_free_ffmpeg_source_files.py. # see src/3rdparty/chromium/third_party/ffmpeg/Changelog for the version number -Provides: bundled(ffmpeg) = 3.1 -Provides: bundled(hunspell) = 1.3.2 +Provides: bundled(ffmpeg) = 3.3 +Provides: bundled(hunspell) = 1.6.0 Provides: bundled(iccjpeg) # bundled as "khronos", headers only Provides: bundled(khronos_headers) # bundled as "leveldatabase" -Provides: bundled(leveldb) -Provides: bundled(libjingle) = 12750 +Provides: bundled(leveldb) = 1.20 +# bundled as "libjingle_xmpp" +Provides: bundled(libjingle) # see src/3rdparty/chromium/third_party/libsrtp/CHANGES for the version number -Provides: bundled(libsrtp) = 1.5.2 +Provides: bundled(libsrtp) = 2.1.0 %if !0%{?use_system_libvpx} Provides: bundled(libvpx) = 1.6.0 %endif %if !0%{?use_system_libwebp} -Provides: bundled(libwebp) = 0.5.1 +Provides: bundled(libwebp) = 0.6.0 %endif +# bundled as "libxml" # see src/3rdparty/chromium/third_party/libxml/linux/include/libxml/xmlversion.h Provides: bundled(libxml2) = 2.9.4 -# see src/3rdparty/chromium/third_party/libxslt/libxslt/xsltconfig.h for version +# see src/3rdparty/chromium/third_party/libxslt/linux/config.h for version Provides: bundled(libxslt) = 1.1.29 Provides: bundled(libXNVCtrl) = 302.17 -Provides: bundled(libyuv) = 1634 +Provides: bundled(libyuv) = 1658 Provides: bundled(modp_b64) -Provides: bundled(mojo) -# headers only -Provides: bundled(npapi) Provides: bundled(openmax_dl) = 1.0.2 Provides: bundled(ots) # see src/3rdparty/chromium/third_party/protobuf/CHANGES.txt for the version @@ -271,12 +258,14 @@ Provides: bundled(sfntly) Provides: bundled(skia) # bundled as "smhasher" Provides: bundled(SMHasher) = 0-0.1.svn147 -Provides: bundled(sqlite) = 3.10.2 +Provides: bundled(sqlite) = 3.20 Provides: bundled(usrsctp) Provides: bundled(webrtc) = 90 + %ifarch %{ix86} x86_64 +# bundled by ffmpeg and libvpx: # header (for assembly) only -Provides: bundled(x86inc) = 0 +Provides: bundled(x86inc) %endif # Bundled in src/3rdparty/chromium/base/third_party: @@ -305,8 +294,9 @@ Provides: bundled(mozilla_security_manager) = 1.9.2 Provides: bundled(nsURLParsers) # Bundled outside of third_party, apparently not considered as such by Chromium: +Provides: bundled(mojo) # see src/3rdparty/chromium/v8/include/v8_version.h for the version number -Provides: bundled(v8) = 5.6.326.55 +Provides: bundled(v8) = 6.1.534.44 # bundled by v8 (src/3rdparty/chromium/v8/src/base/ieee754.cc) # The version number is 5.3, the last version that upstream released, years ago: # http://www.netlib.org/fdlibm/readme @@ -351,7 +341,7 @@ BuildArch: noarch %prep -%setup -q -n %{qt_module}-opensource-src-%{version}%{?prerelease:-%{prerelease}} +%setup -q -n %{qt_module}-everywhere-src-%{version}%{?prerelease:-%{prerelease}} %patch0 -p1 -b .linux-pri %patch1 -p1 -b .no-icudtl-dat %patch2 -p1 -b .fix-extractcflag @@ -366,7 +356,6 @@ BuildArch: noarch %patch11 -p1 -b .skia-neon %patch12 -p1 -b .webrtc-neon-detect %patch21 -p1 -b .gn-bootstrap-verbose -%patch22 -p1 -b .qt57 %patch100 -p1 -b .no-aspirational-scripts # fix // in #include in content/renderer/gpu to avoid debugedit failure sed -i -e 's!gpu//!gpu/!g' \ @@ -417,7 +406,7 @@ mkdir %{_target_platform} pushd %{_target_platform} %{qmake_qt5} CONFIG+="%{debug_config}" \ - WEBENGINE_CONFIG+="use_system_icu use_system_re2 use_spellchecker" .. + QMAKE_EXTRA_ARGS+="-system-webengine-icu" .. make %{?_smp_mflags} @@ -573,6 +562,19 @@ done %changelog +* Mon Dec 25 2017 Kevin Kofler - 5.10.0-1 +- Update to 5.10.0 +- Update version numbers of bundled stuff +- Drop support for Fedora < 26 (in particular, WEBENGINE_CONFIG F25 workarounds) +- Drop qt57 patch, support for Qt 5.7 was completely dropped upstream +- Update get_free_ffmpeg_source_files.py from Fedora Chromium packaging +- clean_qtwebengine.sh: Update for the changed tarball naming scheme +- Use QMAKE_EXTRA_ARGS instead of the removed WEBENGINE_CONFIG +- Rebase linux-pri, system-nspr-prtime, system-icu-utf, no-sse2, skia-neon and + gn-bootstrap-verbose patches +- In particular, restore the removed V8 x87 backend in the no-sse2 patch +- Re-backport no-aspirational-scripts from upstream (undo 5.9 backport) + * Tue Dec 19 2017 Rex Dieter - 5.9.3-5 - properly escape newline in lesser_version hack diff --git a/qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose.patch b/qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose.patch new file mode 100644 index 0000000..cac2e56 --- /dev/null +++ b/qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose.patch @@ -0,0 +1,12 @@ +diff -ur qtwebengine-everywhere-src-5.10.0/src/buildtools/gn.pro qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose/src/buildtools/gn.pro +--- qtwebengine-everywhere-src-5.10.0/src/buildtools/gn.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-gn-bootstrap-verbose/src/buildtools/gn.pro 2017-12-25 18:51:46.953799125 +0100 +@@ -25,7 +25,7 @@ + gn_args = $$replace(gn_args, "use_incremental_linking=true ", "") + } + +- gn_configure = $$system_quote($$gn_bootstrap) --shadow --gn-gen-args=$$gn_args $$ninja_path ++ gn_configure = $$system_quote($$gn_bootstrap) --verbose --shadow --gn-gen-args=$$gn_args $$ninja_path + !system("cd $$system_quote($$system_path($$dirname(out))) && $$pythonPathForSystem() $$gn_configure") { + error("GN build error!") + } diff --git a/qtwebengine-opensource-src-5.9.2-linux-pri.patch b/qtwebengine-everywhere-src-5.10.0-linux-pri.patch similarity index 58% rename from qtwebengine-opensource-src-5.9.2-linux-pri.patch rename to qtwebengine-everywhere-src-5.10.0-linux-pri.patch index ac7b583..162f63e 100644 --- a/qtwebengine-opensource-src-5.9.2-linux-pri.patch +++ b/qtwebengine-everywhere-src-5.10.0-linux-pri.patch @@ -1,9 +1,9 @@ -diff -up qtwebengine-opensource-src-5.9.2/src/core/config/linux.pri.linux-pri qtwebengine-opensource-src-5.9.2/src/core/config/linux.pri ---- qtwebengine-opensource-src-5.9.2/src/core/config/linux.pri.linux-pri 2017-10-09 15:08:43.206663093 -0500 -+++ qtwebengine-opensource-src-5.9.2/src/core/config/linux.pri 2017-10-09 15:09:52.248208321 -0500 -@@ -153,3 +153,19 @@ host_build { - use?(system_re2): gn_args += use_system_re2=true - #use?(system_protobuf): gn_args += use_system_protobuf=true +diff -ur qtwebengine-everywhere-src-5.10.0/src/core/config/linux.pri qtwebengine-everywhere-src-5.10.0-linux-pri/src/core/config/linux.pri +--- qtwebengine-everywhere-src-5.10.0/src/core/config/linux.pri 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-linux-pri/src/core/config/linux.pri 2017-12-25 12:07:40.262411459 +0100 +@@ -157,3 +157,19 @@ + #qtConfig(webengine-system-jsoncpp): gn_args += use_system_jsoncpp=true + #qtConfig(webengine-system-libsrtp: gn_args += use_system_libsrtp=true } + +# yasm is only used on x86, and passing use_system_yasm makes the build fail on diff --git a/qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts.patch b/qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts.patch new file mode 100644 index 0000000..967f452 --- /dev/null +++ b/qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts.patch @@ -0,0 +1,86 @@ +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/components/url_formatter/idn_spoof_checker.cc qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/idn_spoof_checker.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/components/url_formatter/idn_spoof_checker.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/idn_spoof_checker.cc 2017-12-25 19:38:17.621271052 +0100 +@@ -331,39 +331,6 @@ + const icu::UnicodeSet* inclusion_set = uspoof_getInclusionUnicodeSet(status); + allowed_set.addAll(*inclusion_set); + +-// Five aspirational scripts are taken from UTR 31 Table 6 at +-// http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts . +-// Not all the characters of aspirational scripts are suitable for +-// identifiers. Therefore, only characters belonging to +-// [:Identifier_Type=Aspirational:] (listed in 'Status/Type=Aspirational' +-// section at +-// http://www.unicode.org/Public/security/latest/xidmodifications.txt) are +-// are added to the allowed set. The list has to be updated when a new +-// version of Unicode is released. The current version is 9.0.0 and ICU 60 +-// will have Unicode 10.0 data. +-#if U_ICU_VERSION_MAJOR_NUM < 60 +- const icu::UnicodeSet aspirational_scripts( +- icu::UnicodeString( +- // Unified Canadian Syllabics +- "[\\u1401-\\u166C\\u166F-\\u167F" +- // Mongolian +- "\\u1810-\\u1819\\u1820-\\u1877\\u1880-\\u18AA" +- // Unified Canadian Syllabics +- "\\u18B0-\\u18F5" +- // Tifinagh +- "\\u2D30-\\u2D67\\u2D7F" +- // Yi +- "\\uA000-\\uA48C" +- // Miao +- "\\U00016F00-\\U00016F44\\U00016F50-\\U00016F7E" +- "\\U00016F8F-\\U00016F9F]", +- -1, US_INV), +- *status); +- allowed_set.addAll(aspirational_scripts); +-#else +-#error "Update aspirational_scripts per Unicode 10.0" +-#endif +- + // The sections below refer to Mozilla's IDN blacklist: + // http://kb.mozillazine.org/Network.IDN.blacklist_chars + // +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc 2017-12-25 19:38:17.621271052 +0100 +@@ -132,22 +132,24 @@ + {"xn---123-kbjl2j0bl2k.in", L"\x0939\x093f\x0928\x094d\x0926\x0940-123.in", + true}, + +- // 5 Aspirational scripts ++ // What used to be 5 Aspirational scripts in the earlier versions of UAX 31. ++ // UAX 31 does not define aspirational scripts any more. ++ // See http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts . + // Unifieid Canadian Syllabary +- {"xn--dfe0tte.ca", L"\x1456\x14c2\x14ef.ca", true}, ++ {"xn--dfe0tte.ca", L"\x1456\x14c2\x14ef.ca", false}, + // Tifinagh + {"xn--4ljxa2bb4a6bxb.ma", L"\x2d5c\x2d49\x2d3c\x2d49\x2d4f\x2d30\x2d56.ma", +- true}, ++ false}, + // Tifinagh with a disallowed character(U+2D6F) + {"xn--hmjzaby5d5f.ma", L"\x2d5c\x2d49\x2d3c\x2d6f\x2d49\x2d4f.ma", false}, + // Yi +- {"xn--4o7a6e1x64c.cn", L"\xa188\xa320\xa071\xa0b7.cn", true}, ++ {"xn--4o7a6e1x64c.cn", L"\xa188\xa320\xa071\xa0b7.cn", false}, + // Mongolian - 'ordu' (place, camp) +- {"xn--56ec8bp.cn", L"\x1823\x1837\x1833\x1824.cn", true}, ++ {"xn--56ec8bp.cn", L"\x1823\x1837\x1833\x1824.cn", false}, + // Mongolian with a disallowed character + {"xn--95e5de3ds.cn", L"\x1823\x1837\x1804\x1833\x1824.cn", false}, + // Miao/Pollad +- {"xn--2u0fpf0a.cn", L"\U00016f04\U00016f62\U00016f59.cn", true}, ++ {"xn--2u0fpf0a.cn", L"\U00016f04\U00016f62\U00016f59.cn", false}, + + // Script mixing tests + // The following script combinations are allowed. +@@ -606,7 +608,7 @@ + L"a\x144a" + L"b.com", + false}, +- {"xn--xcec9s.com", L"\x1401\x144a\x1402.com", true}, ++ {"xn--xcec9s.com", L"\x1401\x144a\x1402.com", false}, + + // Custom dangerous patterns + // Two Katakana-Hiragana combining mark in a row diff --git a/qtwebengine-everywhere-src-5.10.0-no-sse2.patch b/qtwebengine-everywhere-src-5.10.0-no-sse2.patch new file mode 100644 index 0000000..a7d40dc --- /dev/null +++ b/qtwebengine-everywhere-src-5.10.0-no-sse2.patch @@ -0,0 +1,30353 @@ +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webengine/customdialogs/customdialogs.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/customdialogs/customdialogs.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webengine/customdialogs/customdialogs.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/customdialogs/customdialogs.pro 2017-12-25 12:48:31.714986364 +0100 +@@ -1,5 +1,7 @@ + QT += webengine + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + server.h + +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webengine/minimal/minimal.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/minimal/minimal.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webengine/minimal/minimal.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/minimal/minimal.pro 2017-12-25 12:48:31.752985827 +0100 +@@ -2,6 +2,8 @@ + + QT += webengine + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + SOURCES += main.cpp + + RESOURCES += qml.qrc +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webengine/quicknanobrowser/quicknanobrowser.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/quicknanobrowser/quicknanobrowser.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webengine/quicknanobrowser/quicknanobrowser.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/quicknanobrowser/quicknanobrowser.pro 2017-12-25 12:48:31.815984938 +0100 +@@ -20,5 +20,7 @@ + QT += widgets # QApplication is required to get native styling with QtQuickControls + } + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + target.path = $$[QT_INSTALL_EXAMPLES]/webengine/quicknanobrowser + INSTALLS += target +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webengine/recipebrowser/recipebrowser.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/recipebrowser/recipebrowser.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webengine/recipebrowser/recipebrowser.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webengine/recipebrowser/recipebrowser.pro 2017-12-25 12:48:31.937983215 +0100 +@@ -2,6 +2,8 @@ + + QT += quick qml quickcontrols2 webengine + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + cross_compile { + posix|qnx|linux: DEFINES += QTWEBENGINE_RECIPE_BROWSER_EMBEDDED + } +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro 2017-12-25 12:48:31.938983201 +0100 +@@ -1,5 +1,7 @@ + QT += webenginewidgets + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS = mainwindow.h + SOURCES = main.cpp \ + mainwindow.cpp +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro 2017-12-25 12:48:32.492975378 +0100 +@@ -3,6 +3,8 @@ + TEMPLATE = app + CONFIG += c++11 + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + SOURCES += \ + main.cpp\ + mainwindow.cpp +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/html2pdf/html2pdf.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/html2pdf/html2pdf.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/html2pdf/html2pdf.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/html2pdf/html2pdf.pro 2017-12-25 12:49:15.954361683 +0100 +@@ -2,6 +2,8 @@ + + QT += webenginewidgets + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + SOURCES += html2pdf.cpp + + target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/html2pdf +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/maps/maps.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/maps/maps.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/maps/maps.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/maps/maps.pro 2017-12-25 12:49:16.125359268 +0100 +@@ -2,6 +2,8 @@ + + QT += webenginewidgets + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + mainwindow.h + +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/markdowneditor/markdowneditor.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/markdowneditor/markdowneditor.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/markdowneditor/markdowneditor.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/markdowneditor/markdowneditor.pro 2017-12-25 12:49:16.187358393 +0100 +@@ -3,6 +3,8 @@ + QT += webenginewidgets webchannel + CONFIG += c++11 + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + mainwindow.h \ + previewpage.h \ +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/minimal/minimal.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/minimal/minimal.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/minimal/minimal.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/minimal/minimal.pro 2017-12-25 12:49:16.247357545 +0100 +@@ -2,6 +2,8 @@ + + QT += webenginewidgets + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + SOURCES += main.cpp + + target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/minimal +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/simplebrowser/simplebrowser.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/simplebrowser/simplebrowser.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/simplebrowser/simplebrowser.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/simplebrowser/simplebrowser.pro 2017-12-25 12:49:16.314356599 +0100 +@@ -3,6 +3,8 @@ + QT += webenginewidgets + CONFIG += c++11 + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + browser.h \ + browserwindow.h \ +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/spellchecker/spellchecker.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/spellchecker/spellchecker.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/spellchecker/spellchecker.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/spellchecker/spellchecker.pro 2017-12-25 12:49:16.314356599 +0100 +@@ -9,6 +9,8 @@ + error("Spellcheck example can not be built when using native OS dictionaries.") + } + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + webview.h + +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/stylesheetbrowser/stylesheetbrowser.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/stylesheetbrowser/stylesheetbrowser.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/stylesheetbrowser/stylesheetbrowser.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/stylesheetbrowser/stylesheetbrowser.pro 2017-12-25 12:50:32.558279999 +0100 +@@ -3,6 +3,8 @@ + QT += webenginewidgets + CONFIG += c++11 + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + mainwindow.h \ + stylesheetdialog.h +diff -Nur qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/videoplayer/videoplayer.pro qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/videoplayer/videoplayer.pro +--- qtwebengine-everywhere-src-5.10.0/examples/webenginewidgets/videoplayer/videoplayer.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/examples/webenginewidgets/videoplayer/videoplayer.pro 2017-12-25 12:49:16.314356599 +0100 +@@ -2,6 +2,8 @@ + + QT += webenginewidgets + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release ++ + HEADERS += \ + mainwindow.h \ + fullscreenwindow.h \ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/config/compiler/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/config/compiler/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/config/compiler/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/config/compiler/BUILD.gn 2017-12-25 12:49:16.315356585 +0100 +@@ -600,13 +600,6 @@ + } else if (current_cpu == "x86") { + cflags += [ "-m32" ] + ldflags += [ "-m32" ] +- if (!is_nacl) { +- cflags += [ +- "-msse2", +- "-mfpmath=sse", +- "-mmmx", +- ] +- } + } else if (current_cpu == "arm") { + if (is_clang && !is_android && !is_nacl) { + cflags += [ "--target=arm-linux-gnueabihf" ] +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/config/v8_target_cpu.gni qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/config/v8_target_cpu.gni +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/config/v8_target_cpu.gni 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/config/v8_target_cpu.gni 2017-12-25 12:49:16.315356585 +0100 +@@ -59,3 +59,11 @@ + # It should never be explicitly set by the user. + v8_current_cpu = v8_target_cpu + } ++ ++if (v8_current_cpu == "x86") { ++ # If we are not building for the x86_sse2 toolchain, we actually want to build ++ # the "x87" backend instead. ++ if (current_toolchain != "//build/toolchain/linux:x86_sse2") { ++ v8_current_cpu = "x87" ++ } ++} +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni 2017-12-25 12:49:16.454354623 +0100 +@@ -266,6 +266,10 @@ + enable_linker_map = defined(invoker.enable_linker_map) && + invoker.enable_linker_map && generate_linker_map + ++ if (defined(invoker.shlib_subdir)) { ++ shlib_subdir = invoker.shlib_subdir ++ } ++ + # These library switches can apply to all tools below. + lib_switch = "-l" + lib_dir_switch = "-L" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn 2017-12-25 12:49:16.454354623 +0100 +@@ -110,6 +110,26 @@ + } + } + ++gcc_toolchain("x86_sse2") { ++ cc = "gcc" ++ cxx = "g++" ++ ++ readelf = "readelf" ++ nm = "nm" ++ ar = "ar" ++ ld = cxx ++ ++ extra_cflags = "-msse2 -mfpmath=sse" ++ extra_cxxflags = "-msse2 -mfpmath=sse" ++ shlib_subdir = "lib/sse2" ++ ++ toolchain_args = { ++ current_cpu = "x86" ++ current_os = "linux" ++ is_clang = false ++ } ++} ++ + clang_toolchain("clang_x64") { + # Output linker map files for binary size analysis. + enable_linker_map = true +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/cc/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/cc/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/cc/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/cc/BUILD.gn 2017-12-25 13:16:20.896994372 +0100 +@@ -445,13 +445,6 @@ + "trees/tree_synchronizer.h", + ] + +- if (current_cpu == "x86" || current_cpu == "x64") { +- sources += [ +- "raster/texture_compressor_etc1_sse.cc", +- "raster/texture_compressor_etc1_sse.h", +- ] +- } +- + # TODO(khushalsagar): Remove once crbug.com/683263 is fixed. + configs = [ "//build/config/compiler:no_size_t_to_int_warning" ] + +@@ -463,6 +456,7 @@ + deps = [ + "//base", + "//base/third_party/dynamic_annotations", ++ "//cc:cc_opts", + "//cc/paint", + "//components/viz/common", + "//gpu", +@@ -493,6 +487,36 @@ + } + } + ++source_set("cc_opts") { ++ public_deps = [ ++ "//cc:cc_opts_sse", ++ ] ++} ++ ++source_set("cc_opts_sse") { ++ if (current_cpu == "x86" || current_cpu == "x64") { ++ deps = [ ++ "//base", ++ ] ++ ++ defines = [ "CC_IMPLEMENTATION=1" ] ++ ++ if (!is_debug && (is_win || is_android)) { ++ configs -= [ "//build/config/compiler:optimize" ] ++ configs += [ "//build/config/compiler:optimize_max" ] ++ } ++ ++ sources = [ ++ "raster/texture_compressor.h", ++ "raster/texture_compressor_etc1.h", ++ "raster/texture_compressor_etc1_sse.cc", ++ "raster/texture_compressor_etc1_sse.h", ++ ] ++ ++ cflags = [ "-msse2" ] ++ } ++} ++ + cc_static_library("test_support") { + testonly = true + sources = [ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/content/renderer/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/content/renderer/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/content/renderer/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/content/renderer/BUILD.gn 2017-12-25 12:49:16.454354623 +0100 +@@ -514,6 +514,13 @@ + "//ui/surface", + "//v8", + ] ++ ++ if (current_cpu == "x86") { ++ deps += [ ++ "//v8(//build/toolchain/linux:x86_sse2)", ++ ] ++ } ++ + allow_circular_includes_from = [] + + if (use_aura && !use_qt) { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/BUILD.gn 2017-12-25 13:30:14.473844548 +0100 +@@ -344,6 +344,12 @@ + defines += [ "DISABLE_USER_INPUT_MONITOR" ] + } + ++ if (current_cpu == "x86" || current_cpu == "x64") { ++ deps += [ ++ ":media_sse", ++ ] ++ } ++ + if (is_linux || is_win) { + sources += [ + "keyboard_event_counter.cc", +@@ -366,6 +372,21 @@ + ] + } + ++if (current_cpu == "x86" || current_cpu == "x64") { ++ source_set("media_sse") { ++ sources = [ ++ "sinc_resampler_sse.cc", ++ ] ++ configs += [ ++ "//media:media_config", ++ "//media:media_implementation", ++ ] ++ if (!is_win) { ++ cflags = [ "-msse" ] ++ } ++ } ++} ++ + if (is_android) { + java_cpp_enum("java_enums") { + sources = [ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/media.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/media.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/media.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/media.cc 2017-12-25 13:32:19.234052101 +0100 +@@ -10,6 +10,8 @@ + #include "base/metrics/field_trial.h" + #include "base/trace_event/trace_event.h" + #include "media/base/media_switches.h" ++#include "media/base/sinc_resampler.h" ++#include "media/base/vector_math.h" + #include "third_party/libyuv/include/libyuv.h" + + #if defined(OS_ANDROID) +@@ -30,6 +32,9 @@ + TRACE_EVENT_WARMUP_CATEGORY("audio"); + TRACE_EVENT_WARMUP_CATEGORY("media"); + ++ // Perform initialization of libraries which require runtime CPU detection. ++ vector_math::Initialize(); ++ SincResampler::InitializeCPUSpecificFeatures(); + libyuv::InitCpuFlags(); + + #if !defined(MEDIA_DISABLE_FFMPEG) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.cc 2017-12-25 12:57:58.624478849 +0100 +@@ -81,17 +81,12 @@ + #include + #include + ++#include "base/cpu.h" + #include "base/logging.h" + #include "build/build_config.h" + +-#if defined(ARCH_CPU_X86_FAMILY) +-#include +-#define CONVOLVE_FUNC Convolve_SSE +-#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) ++#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + #include +-#define CONVOLVE_FUNC Convolve_NEON +-#else +-#define CONVOLVE_FUNC Convolve_C + #endif + + namespace media { +@@ -112,10 +107,41 @@ + return sinc_scale_factor; + } + ++#undef CONVOLVE_FUNC ++ + static int CalculateChunkSize(int block_size_, double io_ratio) { + return block_size_ / io_ratio; + } + ++// If we know the minimum architecture at compile time, avoid CPU detection. ++// Force NaCl code to use C routines since (at present) nothing there uses these ++// methods and plumbing the -msse built library is non-trivial. ++#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) ++#if defined(__SSE__) ++#define CONVOLVE_FUNC Convolve_SSE ++void SincResampler::InitializeCPUSpecificFeatures() {} ++#else ++// X86 CPU detection required. Functions will be set by ++// InitializeCPUSpecificFeatures(). ++#define CONVOLVE_FUNC g_convolve_proc_ ++ ++typedef float (*ConvolveProc)(const float*, const float*, const float*, double); ++static ConvolveProc g_convolve_proc_ = NULL; ++ ++void SincResampler::InitializeCPUSpecificFeatures() { ++ CHECK(!g_convolve_proc_); ++ g_convolve_proc_ = base::CPU().has_sse() ? Convolve_SSE : Convolve_C; ++} ++#endif ++#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) ++#define CONVOLVE_FUNC Convolve_NEON ++void SincResampler::InitializeCPUSpecificFeatures() {} ++#else ++// Unknown architecture. ++#define CONVOLVE_FUNC Convolve_C ++void SincResampler::InitializeCPUSpecificFeatures() {} ++#endif ++ + SincResampler::SincResampler(double io_sample_rate_ratio, + int request_frames, + const ReadCB& read_cb) +@@ -328,46 +354,7 @@ + kernel_interpolation_factor * sum2); + } + +-#if defined(ARCH_CPU_X86_FAMILY) +-float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, +- const float* k2, +- double kernel_interpolation_factor) { +- __m128 m_input; +- __m128 m_sums1 = _mm_setzero_ps(); +- __m128 m_sums2 = _mm_setzero_ps(); +- +- // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling +- // these loops hurt performance in local testing. +- if (reinterpret_cast(input_ptr) & 0x0F) { +- for (int i = 0; i < kKernelSize; i += 4) { +- m_input = _mm_loadu_ps(input_ptr + i); +- m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); +- m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); +- } +- } else { +- for (int i = 0; i < kKernelSize; i += 4) { +- m_input = _mm_load_ps(input_ptr + i); +- m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); +- m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); +- } +- } +- +- // Linearly interpolate the two "convolutions". +- m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1( +- static_cast(1.0 - kernel_interpolation_factor))); +- m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1( +- static_cast(kernel_interpolation_factor))); +- m_sums1 = _mm_add_ps(m_sums1, m_sums2); +- +- // Sum components together. +- float result; +- m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); +- _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps( +- m_sums2, m_sums2, 1))); +- +- return result; +-} +-#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) ++#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, + const float* k2, + double kernel_interpolation_factor) { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.h 2017-12-25 12:57:58.798476686 +0100 +@@ -36,6 +36,10 @@ + kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1), + }; + ++ // Selects runtime specific CPU features like SSE. Must be called before ++ // using SincResampler. ++ static void InitializeCPUSpecificFeatures(); ++ + // Callback type for providing more data into the resampler. Expects |frames| + // of data to be rendered into |destination|; zero padded if not enough frames + // are available to satisfy the request. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc 2017-12-25 12:57:58.798476686 +0100 +@@ -4,6 +4,7 @@ + + #include "base/bind.h" + #include "base/bind_helpers.h" ++#include "base/cpu.h" + #include "base/time/time.h" + #include "build/build_config.h" + #include "media/base/sinc_resampler.h" +@@ -61,6 +62,9 @@ + &resampler, SincResampler::Convolve_C, true, "unoptimized_aligned"); + + #if defined(CONVOLVE_FUNC) ++#if defined(ARCH_CPU_X86_FAMILY) ++ ASSERT_TRUE(base::CPU().has_sse()); ++#endif + RunConvolveBenchmark( + &resampler, SincResampler::CONVOLVE_FUNC, true, "optimized_aligned"); + RunConvolveBenchmark( +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_sse.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_sse.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_sse.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_sse.cc 2017-07-01 03:36:35.000000000 +0200 +@@ -0,0 +1,50 @@ ++// Copyright 2013 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "media/base/sinc_resampler.h" ++ ++#include ++ ++namespace media { ++ ++float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, ++ const float* k2, ++ double kernel_interpolation_factor) { ++ __m128 m_input; ++ __m128 m_sums1 = _mm_setzero_ps(); ++ __m128 m_sums2 = _mm_setzero_ps(); ++ ++ // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling ++ // these loops hurt performance in local testing. ++ if (reinterpret_cast(input_ptr) & 0x0F) { ++ for (int i = 0; i < kKernelSize; i += 4) { ++ m_input = _mm_loadu_ps(input_ptr + i); ++ m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); ++ m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); ++ } ++ } else { ++ for (int i = 0; i < kKernelSize; i += 4) { ++ m_input = _mm_load_ps(input_ptr + i); ++ m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); ++ m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); ++ } ++ } ++ ++ // Linearly interpolate the two "convolutions". ++ m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1( ++ static_cast(1.0 - kernel_interpolation_factor))); ++ m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1( ++ static_cast(kernel_interpolation_factor))); ++ m_sums1 = _mm_add_ps(m_sums1, m_sums2); ++ ++ // Sum components together. ++ float result; ++ m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); ++ _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps( ++ m_sums2, m_sums2, 1))); ++ ++ return result; ++} ++ ++} // namespace media +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc 2017-12-25 12:57:58.798476686 +0100 +@@ -10,6 +10,7 @@ + + #include "base/bind.h" + #include "base/bind_helpers.h" ++#include "base/cpu.h" + #include "base/macros.h" + #include "base/strings/string_number_conversions.h" + #include "base/time/time.h" +@@ -166,6 +167,10 @@ + static const double kKernelInterpolationFactor = 0.5; + + TEST(SincResamplerTest, Convolve) { ++#if defined(ARCH_CPU_X86_FAMILY) ++ ASSERT_TRUE(base::CPU().has_sse()); ++#endif ++ + // Initialize a dummy resampler. + MockSource mock_source; + SincResampler resampler( +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math.cc 2017-12-25 12:57:58.799476673 +0100 +@@ -7,12 +7,17 @@ + + #include + ++#include "base/cpu.h" + #include "base/logging.h" + #include "build/build_config.h" + ++namespace media { ++namespace vector_math { ++ ++// If we know the minimum architecture at compile time, avoid CPU detection. + // NaCl does not allow intrinsics. + #if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) +-#include ++#if defined(__SSE__) + // Don't use custom SSE versions where the auto-vectorized C version performs + // better, which is anywhere clang is used. + // TODO(pcc): Linux currently uses ThinLTO which has broken auto-vectorization +@@ -25,20 +30,52 @@ + #define FMUL_FUNC FMUL_C + #endif + #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE ++void Initialize() {} ++#else ++// X86 CPU detection required. Functions will be set by Initialize(). ++#if !defined(__clang__) ++#define FMAC_FUNC g_fmac_proc_ ++#define FMUL_FUNC g_fmul_proc_ ++#else ++#define FMAC_FUNC FMAC_C ++#define FMUL_FUNC FMUL_C ++#endif ++#define EWMAAndMaxPower_FUNC g_ewma_power_proc_ ++ ++#if !defined(__clang__) ++typedef void (*MathProc)(const float src[], float scale, int len, float dest[]); ++static MathProc g_fmac_proc_ = NULL; ++static MathProc g_fmul_proc_ = NULL; ++#endif ++typedef std::pair (*EWMAAndMaxPowerProc)( ++ float initial_value, const float src[], int len, float smoothing_factor); ++static EWMAAndMaxPowerProc g_ewma_power_proc_ = NULL; ++ ++void Initialize() { ++ CHECK(!g_fmac_proc_); ++ CHECK(!g_fmul_proc_); ++ CHECK(!g_ewma_power_proc_); ++ const bool kUseSSE = base::CPU().has_sse(); ++#if !defined(__clang__) ++ g_fmac_proc_ = kUseSSE ? FMAC_SSE : FMAC_C; ++ g_fmul_proc_ = kUseSSE ? FMUL_SSE : FMUL_C; ++#endif ++ g_ewma_power_proc_ = kUseSSE ? EWMAAndMaxPower_SSE : EWMAAndMaxPower_C; ++} ++#endif + #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + #include + #define FMAC_FUNC FMAC_NEON + #define FMUL_FUNC FMUL_NEON + #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON ++void Initialize() {} + #else + #define FMAC_FUNC FMAC_C + #define FMUL_FUNC FMUL_C + #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_C ++void Initialize() {} + #endif + +-namespace media { +-namespace vector_math { +- + void FMAC(const float src[], float scale, int len, float dest[]) { + // Ensure |src| and |dest| are 16-byte aligned. + DCHECK_EQ(0u, reinterpret_cast(src) & (kRequiredAlignment - 1)); +@@ -91,111 +128,6 @@ + return result; + } + +-#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) +-void FMUL_SSE(const float src[], float scale, int len, float dest[]) { +- const int rem = len % 4; +- const int last_index = len - rem; +- __m128 m_scale = _mm_set_ps1(scale); +- for (int i = 0; i < last_index; i += 4) +- _mm_store_ps(dest + i, _mm_mul_ps(_mm_load_ps(src + i), m_scale)); +- +- // Handle any remaining values that wouldn't fit in an SSE pass. +- for (int i = last_index; i < len; ++i) +- dest[i] = src[i] * scale; +-} +- +-void FMAC_SSE(const float src[], float scale, int len, float dest[]) { +- const int rem = len % 4; +- const int last_index = len - rem; +- __m128 m_scale = _mm_set_ps1(scale); +- for (int i = 0; i < last_index; i += 4) { +- _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i), +- _mm_mul_ps(_mm_load_ps(src + i), m_scale))); +- } +- +- // Handle any remaining values that wouldn't fit in an SSE pass. +- for (int i = last_index; i < len; ++i) +- dest[i] += src[i] * scale; +-} +- +-// Convenience macro to extract float 0 through 3 from the vector |a|. This is +-// needed because compilers other than clang don't support access via +-// operator[](). +-#define EXTRACT_FLOAT(a, i) \ +- (i == 0 ? \ +- _mm_cvtss_f32(a) : \ +- _mm_cvtss_f32(_mm_shuffle_ps(a, a, i))) +- +-std::pair EWMAAndMaxPower_SSE( +- float initial_value, const float src[], int len, float smoothing_factor) { +- // When the recurrence is unrolled, we see that we can split it into 4 +- // separate lanes of evaluation: +- // +- // y[n] = a(S[n]^2) + (1-a)(y[n-1]) +- // = a(S[n]^2) + (1-a)^1(aS[n-1]^2) + (1-a)^2(aS[n-2]^2) + ... +- // = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) +- // +- // where z[n] = a(S[n]^2) + (1-a)^4(z[n-4]) + (1-a)^8(z[n-8]) + ... +- // +- // Thus, the strategy here is to compute z[n], z[n-1], z[n-2], and z[n-3] in +- // each of the 4 lanes, and then combine them to give y[n]. +- +- const int rem = len % 4; +- const int last_index = len - rem; +- +- const __m128 smoothing_factor_x4 = _mm_set_ps1(smoothing_factor); +- const float weight_prev = 1.0f - smoothing_factor; +- const __m128 weight_prev_x4 = _mm_set_ps1(weight_prev); +- const __m128 weight_prev_squared_x4 = +- _mm_mul_ps(weight_prev_x4, weight_prev_x4); +- const __m128 weight_prev_4th_x4 = +- _mm_mul_ps(weight_prev_squared_x4, weight_prev_squared_x4); +- +- // Compute z[n], z[n-1], z[n-2], and z[n-3] in parallel in lanes 3, 2, 1 and +- // 0, respectively. +- __m128 max_x4 = _mm_setzero_ps(); +- __m128 ewma_x4 = _mm_setr_ps(0.0f, 0.0f, 0.0f, initial_value); +- int i; +- for (i = 0; i < last_index; i += 4) { +- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_4th_x4); +- const __m128 sample_x4 = _mm_load_ps(src + i); +- const __m128 sample_squared_x4 = _mm_mul_ps(sample_x4, sample_x4); +- max_x4 = _mm_max_ps(max_x4, sample_squared_x4); +- // Note: The compiler optimizes this to a single multiply-and-accumulate +- // instruction: +- ewma_x4 = _mm_add_ps(ewma_x4, +- _mm_mul_ps(sample_squared_x4, smoothing_factor_x4)); +- } +- +- // y[n] = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) +- float ewma = EXTRACT_FLOAT(ewma_x4, 3); +- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); +- ewma += EXTRACT_FLOAT(ewma_x4, 2); +- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); +- ewma += EXTRACT_FLOAT(ewma_x4, 1); +- ewma_x4 = _mm_mul_ss(ewma_x4, weight_prev_x4); +- ewma += EXTRACT_FLOAT(ewma_x4, 0); +- +- // Fold the maximums together to get the overall maximum. +- max_x4 = _mm_max_ps(max_x4, +- _mm_shuffle_ps(max_x4, max_x4, _MM_SHUFFLE(3, 3, 1, 1))); +- max_x4 = _mm_max_ss(max_x4, _mm_shuffle_ps(max_x4, max_x4, 2)); +- +- std::pair result(ewma, EXTRACT_FLOAT(max_x4, 0)); +- +- // Handle remaining values at the end of |src|. +- for (; i < len; ++i) { +- result.first *= weight_prev; +- const float sample = src[i]; +- const float sample_squared = sample * sample; +- result.first += sample_squared * smoothing_factor; +- result.second = std::max(result.second, sample_squared); +- } +- +- return result; +-} +-#endif +- + #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + void FMAC_NEON(const float src[], float scale, int len, float dest[]) { + const int rem = len % 4; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math.h 2017-12-25 12:57:58.799476673 +0100 +@@ -15,6 +15,11 @@ + // Required alignment for inputs and outputs to all vector math functions + enum { kRequiredAlignment = 16 }; + ++// Selects runtime specific optimizations such as SSE. Must be called prior to ++// calling FMAC() or FMUL(). Called during media library initialization; most ++// users should never have to call this. ++MEDIA_EXPORT void Initialize(); ++ + // Multiply each element of |src| (up to |len|) by |scale| and add to |dest|. + // |src| and |dest| must be aligned by kRequiredAlignment. + MEDIA_EXPORT void FMAC(const float src[], float scale, int len, float dest[]); +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_perftest.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_perftest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_perftest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_perftest.cc 2017-12-25 12:57:58.800476661 +0100 +@@ -5,6 +5,7 @@ + #include + + #include "base/macros.h" ++#include "base/cpu.h" + #include "base/memory/aligned_memory.h" + #include "base/time/time.h" + #include "build/build_config.h" +@@ -82,15 +83,11 @@ + DISALLOW_COPY_AND_ASSIGN(VectorMathPerfTest); + }; + +-// Define platform dependent function names for SIMD optimized methods. ++// Define platform independent function name for FMAC* perf tests. + #if defined(ARCH_CPU_X86_FAMILY) + #define FMAC_FUNC FMAC_SSE +-#define FMUL_FUNC FMUL_SSE +-#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE + #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + #define FMAC_FUNC FMAC_NEON +-#define FMUL_FUNC FMUL_NEON +-#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON + #endif + + // Benchmark for each optimized vector_math::FMAC() method. +@@ -99,6 +96,9 @@ + RunBenchmark( + vector_math::FMAC_C, true, "vector_math_fmac", "unoptimized"); + #if defined(FMAC_FUNC) ++#if defined(ARCH_CPU_X86_FAMILY) ++ ASSERT_TRUE(base::CPU().has_sse()); ++#endif + // Benchmark FMAC_FUNC() with unaligned size. + ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / + sizeof(float)), 0U); +@@ -112,12 +112,24 @@ + #endif + } + ++#undef FMAC_FUNC ++ ++// Define platform independent function name for FMULBenchmark* tests. ++#if defined(ARCH_CPU_X86_FAMILY) ++#define FMUL_FUNC FMUL_SSE ++#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) ++#define FMUL_FUNC FMUL_NEON ++#endif ++ + // Benchmark for each optimized vector_math::FMUL() method. + TEST_F(VectorMathPerfTest, FMUL) { + // Benchmark FMUL_C(). + RunBenchmark( + vector_math::FMUL_C, true, "vector_math_fmul", "unoptimized"); + #if defined(FMUL_FUNC) ++#if defined(ARCH_CPU_X86_FAMILY) ++ ASSERT_TRUE(base::CPU().has_sse()); ++#endif + // Benchmark FMUL_FUNC() with unaligned size. + ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / + sizeof(float)), 0U); +@@ -131,6 +143,14 @@ + #endif + } + ++#undef FMUL_FUNC ++ ++#if defined(ARCH_CPU_X86_FAMILY) ++#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE ++#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) ++#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON ++#endif ++ + // Benchmark for each optimized vector_math::EWMAAndMaxPower() method. + TEST_F(VectorMathPerfTest, EWMAAndMaxPower) { + // Benchmark EWMAAndMaxPower_C(). +@@ -139,6 +159,9 @@ + "vector_math_ewma_and_max_power", + "unoptimized"); + #if defined(EWMAAndMaxPower_FUNC) ++#if defined(ARCH_CPU_X86_FAMILY) ++ ASSERT_TRUE(base::CPU().has_sse()); ++#endif + // Benchmark EWMAAndMaxPower_FUNC() with unaligned size. + ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / + sizeof(float)), 0U); +@@ -156,4 +179,6 @@ + #endif + } + ++#undef EWMAAndMaxPower_FUNC ++ + } // namespace media +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_sse.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_sse.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_sse.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_sse.cc 2017-07-01 03:36:35.000000000 +0200 +@@ -0,0 +1,118 @@ ++// Copyright 2013 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "media/base/vector_math_testing.h" ++ ++#include ++ ++#include // NOLINT ++ ++namespace media { ++namespace vector_math { ++ ++void FMUL_SSE(const float src[], float scale, int len, float dest[]) { ++ const int rem = len % 4; ++ const int last_index = len - rem; ++ __m128 m_scale = _mm_set_ps1(scale); ++ for (int i = 0; i < last_index; i += 4) ++ _mm_store_ps(dest + i, _mm_mul_ps(_mm_load_ps(src + i), m_scale)); ++ ++ // Handle any remaining values that wouldn't fit in an SSE pass. ++ for (int i = last_index; i < len; ++i) ++ dest[i] = src[i] * scale; ++} ++ ++void FMAC_SSE(const float src[], float scale, int len, float dest[]) { ++ const int rem = len % 4; ++ const int last_index = len - rem; ++ __m128 m_scale = _mm_set_ps1(scale); ++ for (int i = 0; i < last_index; i += 4) { ++ _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i), ++ _mm_mul_ps(_mm_load_ps(src + i), m_scale))); ++ } ++ ++ // Handle any remaining values that wouldn't fit in an SSE pass. ++ for (int i = last_index; i < len; ++i) ++ dest[i] += src[i] * scale; ++} ++ ++// Convenience macro to extract float 0 through 3 from the vector |a|. This is ++// needed because compilers other than clang don't support access via ++// operator[](). ++#define EXTRACT_FLOAT(a, i) \ ++ (i == 0 ? \ ++ _mm_cvtss_f32(a) : \ ++ _mm_cvtss_f32(_mm_shuffle_ps(a, a, i))) ++ ++std::pair EWMAAndMaxPower_SSE( ++ float initial_value, const float src[], int len, float smoothing_factor) { ++ // When the recurrence is unrolled, we see that we can split it into 4 ++ // separate lanes of evaluation: ++ // ++ // y[n] = a(S[n]^2) + (1-a)(y[n-1]) ++ // = a(S[n]^2) + (1-a)^1(aS[n-1]^2) + (1-a)^2(aS[n-2]^2) + ... ++ // = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) ++ // ++ // where z[n] = a(S[n]^2) + (1-a)^4(z[n-4]) + (1-a)^8(z[n-8]) + ... ++ // ++ // Thus, the strategy here is to compute z[n], z[n-1], z[n-2], and z[n-3] in ++ // each of the 4 lanes, and then combine them to give y[n]. ++ ++ const int rem = len % 4; ++ const int last_index = len - rem; ++ ++ const __m128 smoothing_factor_x4 = _mm_set_ps1(smoothing_factor); ++ const float weight_prev = 1.0f - smoothing_factor; ++ const __m128 weight_prev_x4 = _mm_set_ps1(weight_prev); ++ const __m128 weight_prev_squared_x4 = ++ _mm_mul_ps(weight_prev_x4, weight_prev_x4); ++ const __m128 weight_prev_4th_x4 = ++ _mm_mul_ps(weight_prev_squared_x4, weight_prev_squared_x4); ++ ++ // Compute z[n], z[n-1], z[n-2], and z[n-3] in parallel in lanes 3, 2, 1 and ++ // 0, respectively. ++ __m128 max_x4 = _mm_setzero_ps(); ++ __m128 ewma_x4 = _mm_setr_ps(0.0f, 0.0f, 0.0f, initial_value); ++ int i; ++ for (i = 0; i < last_index; i += 4) { ++ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_4th_x4); ++ const __m128 sample_x4 = _mm_load_ps(src + i); ++ const __m128 sample_squared_x4 = _mm_mul_ps(sample_x4, sample_x4); ++ max_x4 = _mm_max_ps(max_x4, sample_squared_x4); ++ // Note: The compiler optimizes this to a single multiply-and-accumulate ++ // instruction: ++ ewma_x4 = _mm_add_ps(ewma_x4, ++ _mm_mul_ps(sample_squared_x4, smoothing_factor_x4)); ++ } ++ ++ // y[n] = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) ++ float ewma = EXTRACT_FLOAT(ewma_x4, 3); ++ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); ++ ewma += EXTRACT_FLOAT(ewma_x4, 2); ++ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); ++ ewma += EXTRACT_FLOAT(ewma_x4, 1); ++ ewma_x4 = _mm_mul_ss(ewma_x4, weight_prev_x4); ++ ewma += EXTRACT_FLOAT(ewma_x4, 0); ++ ++ // Fold the maximums together to get the overall maximum. ++ max_x4 = _mm_max_ps(max_x4, ++ _mm_shuffle_ps(max_x4, max_x4, _MM_SHUFFLE(3, 3, 1, 1))); ++ max_x4 = _mm_max_ss(max_x4, _mm_shuffle_ps(max_x4, max_x4, 2)); ++ ++ std::pair result(ewma, EXTRACT_FLOAT(max_x4, 0)); ++ ++ // Handle remaining values at the end of |src|. ++ for (; i < len; ++i) { ++ result.first *= weight_prev; ++ const float sample = src[i]; ++ const float sample_squared = sample * sample; ++ result.first += sample_squared * smoothing_factor; ++ result.second = std::max(result.second, sample_squared); ++ } ++ ++ return result; ++} ++ ++} // namespace vector_math ++} // namespace media +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_testing.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_testing.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_testing.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_testing.h 2017-12-25 12:57:58.800476661 +0100 +@@ -19,7 +19,7 @@ + MEDIA_EXPORT std::pair EWMAAndMaxPower_C( + float initial_value, const float src[], int len, float smoothing_factor); + +-#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) ++#if defined(ARCH_CPU_X86_FAMILY) + MEDIA_EXPORT void FMAC_SSE(const float src[], float scale, int len, + float dest[]); + MEDIA_EXPORT void FMUL_SSE(const float src[], float scale, int len, +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_unittest.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_unittest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/base/vector_math_unittest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/base/vector_math_unittest.cc 2017-12-25 12:57:58.800476661 +0100 +@@ -9,6 +9,7 @@ + #include + + #include "base/macros.h" ++#include "base/cpu.h" + #include "base/memory/aligned_memory.h" + #include "base/strings/string_number_conversions.h" + #include "base/strings/stringize_macros.h" +@@ -78,6 +79,7 @@ + + #if defined(ARCH_CPU_X86_FAMILY) + { ++ ASSERT_TRUE(base::CPU().has_sse()); + SCOPED_TRACE("FMAC_SSE"); + FillTestVectors(kInputFillValue, kOutputFillValue); + vector_math::FMAC_SSE( +@@ -119,6 +121,7 @@ + + #if defined(ARCH_CPU_X86_FAMILY) + { ++ ASSERT_TRUE(base::CPU().has_sse()); + SCOPED_TRACE("FMUL_SSE"); + FillTestVectors(kInputFillValue, kOutputFillValue); + vector_math::FMUL_SSE( +@@ -227,6 +230,7 @@ + + #if defined(ARCH_CPU_X86_FAMILY) + { ++ ASSERT_TRUE(base::CPU().has_sse()); + SCOPED_TRACE("EWMAAndMaxPower_SSE"); + const std::pair& result = vector_math::EWMAAndMaxPower_SSE( + initial_value_, data_.get(), data_len_, smoothing_factor_); +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/BUILD.gn 2017-12-25 13:38:30.438718953 +0100 +@@ -534,6 +534,26 @@ + "//base", + "//ui/gfx/geometry", + ] ++ if (current_cpu == "x86" || current_cpu == "x64") { ++ deps += [ ++ ":shared_memory_support_sse", ++ ] ++ } ++} ++ ++if (current_cpu == "x86" || current_cpu == "x64") { ++ source_set("shared_memory_support_sse") { ++ sources = [ ++ "base/vector_math_sse.cc", ++ ] ++ configs += [ ++ "//media:media_config", ++ "//media:media_implementation", ++ ] ++ if (!is_win) { ++ cflags = [ "-msse" ] ++ } ++ } + } + + # TODO(watk): Refactor tests that could be made to run on Android. See +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/filters/wsola_internals.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/filters/wsola_internals.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/media/filters/wsola_internals.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/media/filters/wsola_internals.cc 2017-12-25 12:58:07.760365227 +0100 +@@ -15,7 +15,7 @@ + #include "base/logging.h" + #include "media/base/audio_bus.h" + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE2__) + #define USE_SIMD 1 + #include + #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/BUILD.gn 2017-12-25 13:45:09.341998517 +0100 +@@ -257,17 +257,6 @@ + "ext/platform_canvas.h", + ] + } +- if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) { +- sources += [ +- "ext/convolver_SSE2.cc", +- "ext/convolver_SSE2.h", +- ] +- } else if (current_cpu == "mipsel" && mips_dsp_rev >= 2) { +- sources += [ +- "ext/convolver_mips_dspr2.cc", +- "ext/convolver_mips_dspr2.h", +- ] +- } + + if (!is_fuchsia) { + sources -= [ +@@ -522,6 +511,31 @@ + } + } + if (current_cpu == "x86" || current_cpu == "x64") { ++ source_set("skia_opts_sse2") { ++ sources = skia_opts.sse2_sources + ++ [ ++ # Chrome-specific. ++ "ext/convolver_SSE2.cc", ++ "ext/convolver_SSE2.h", ++ ] ++ sources -= [ ++ # Detection code must not be built with -msse2 ++ "//third_party/skia/src/opts/opts_check_x86.cpp", ++ ] ++ if (!is_win || is_clang) { ++ cflags = [ "-msse2" ] ++ } ++ if (is_win) { ++ defines = [ "SK_CPU_SSE_LEVEL=20" ] ++ } ++ visibility = [ ":skia_opts" ] ++ configs -= [ "//build/config/compiler:chromium_code" ] ++ configs += [ ++ ":skia_config", ++ ":skia_library_config", ++ "//build/config/compiler:no_chromium_code", ++ ] ++ } + source_set("skia_opts_sse3") { + sources = skia_opts.ssse3_sources + if (!is_win || is_clang) { +@@ -626,10 +640,13 @@ + ] + + if (current_cpu == "x86" || current_cpu == "x64") { +- sources = skia_opts.sse2_sources ++ sources = [ ++ "//third_party/skia/src/opts/opts_check_x86.cpp", ++ ] + deps += [ + ":skia_opts_avx", + ":skia_opts_hsw", ++ ":skia_opts_sse2", + ":skia_opts_sse3", + ":skia_opts_sse41", + ":skia_opts_sse42", +@@ -664,6 +681,13 @@ + + if (mips_dsp_rev >= 1) { + sources = skia_opts.mips_dsp_sources ++ if (mips_dsp_rev >= 2) { ++ sources += [ ++ # Chrome-specific. ++ "ext/convolver_mips_dspr2.cc", ++ "ext/convolver_mips_dspr2.h", ++ ] ++ } + } else { + sources = skia_opts.none_sources + } +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/ext/convolver.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/ext/convolver.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/ext/convolver.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/ext/convolver.cc 2017-12-25 13:05:23.911940902 +0100 +@@ -362,10 +362,13 @@ + + void SetupSIMD(ConvolveProcs *procs) { + #ifdef SIMD_SSE2 +- procs->extra_horizontal_reads = 3; +- procs->convolve_vertically = &ConvolveVertically_SSE2; +- procs->convolve_4rows_horizontally = &Convolve4RowsHorizontally_SSE2; +- procs->convolve_horizontally = &ConvolveHorizontally_SSE2; ++ base::CPU cpu; ++ if (cpu.has_sse2()) { ++ procs->extra_horizontal_reads = 3; ++ procs->convolve_vertically = &ConvolveVertically_SSE2; ++ procs->convolve_4rows_horizontally = &Convolve4RowsHorizontally_SSE2; ++ procs->convolve_horizontally = &ConvolveHorizontally_SSE2; ++ } + #elif defined SIMD_MIPS_DSPR2 + procs->extra_horizontal_reads = 3; + procs->convolve_vertically = &ConvolveVertically_mips_dspr2; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/ext/convolver.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/ext/convolver.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/ext/convolver.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/skia/ext/convolver.h 2017-12-25 13:05:23.951940405 +0100 +@@ -11,6 +11,7 @@ + #include + + #include "build/build_config.h" ++#include "base/cpu.h" + #include "third_party/skia/include/core/SkSize.h" + #include "third_party/skia/include/core/SkTypes.h" + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/BUILD.gn 2017-12-25 13:05:23.951940405 +0100 +@@ -192,6 +192,26 @@ + public_deps = [ + ":angle_common", + ] ++ ++ if (current_cpu == "x86") { ++ deps = [ ++ ":angle_image_util_x86_sse2", ++ ] ++ } ++} ++ ++source_set("angle_image_util_x86_sse2") { ++ configs -= angle_undefine_configs ++ configs += [ ":internal_config" ] ++ ++ deps = [ ++ ":angle_common", ++ ] ++ ++ sources = [ ++ "src/image_util/loadimage_SSE2.cpp", ++ ] ++ cflags = [ "-msse2", "-mfpmath=sse" ] + } + + config("angle_gpu_info_util_config") { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h 2017-12-25 13:05:23.951940405 +0100 +@@ -124,9 +124,42 @@ + } + } + +-inline bool supportsSSE2() ++#if defined(ANGLE_USE_SSE) && !defined(__x86_64__) && !defined(__SSE2__) && !defined(_MSC_VER) ++ ++// From the base/cpu.cc in Chromium, to avoid depending on Chromium headers ++ ++#if defined(__pic__) && defined(__i386__) ++ ++static inline void __cpuid(int cpu_info[4], int info_type) { ++ __asm__ volatile ( ++ "mov %%ebx, %%edi\n" ++ "cpuid\n" ++ "xchg %%edi, %%ebx\n" ++ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) ++ : "a"(info_type) ++ ); ++} ++ ++#else ++ ++static inline void __cpuid(int cpu_info[4], int info_type) { ++ __asm__ volatile ( ++ "cpuid\n" ++ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) ++ : "a"(info_type) ++ ); ++} ++ ++#endif ++ ++#endif ++ ++static inline bool supportsSSE2() + { + #if defined(ANGLE_USE_SSE) ++#if defined(__x86_64__) || defined(__SSE2__) ++ return true; ++#else + static bool checked = false; + static bool supports = false; + +@@ -135,7 +168,6 @@ + return supports; + } + +-#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) + { + int info[4]; + __cpuid(info, 0); +@@ -147,9 +179,9 @@ + supports = (info[3] >> 26) & 1; + } + } +-#endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) + checked = true; + return supports; ++#endif // defined(x86_64) || defined(__SSE2__) + #else // defined(ANGLE_USE_SSE) + return false; + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/common/platform.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/platform.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/common/platform.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/platform.h 2017-12-25 13:05:23.951940405 +0100 +@@ -87,7 +87,9 @@ + #include + #define ANGLE_USE_SSE + #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) ++#if defined(__x86_64__) || defined(__SSE2__) + #include ++#endif + #define ANGLE_USE_SSE + #endif + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp 2017-12-25 13:05:23.952940392 +0100 +@@ -12,9 +12,17 @@ + #include "common/platform.h" + #include "image_util/imageformats.h" + ++#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) ++#error SSE2 parts must be built with -msse2 ++#endif ++ + namespace angle + { + ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++namespace SSE2 { ++#endif ++ + void LoadA8ToRGBA8(size_t width, + size_t height, + size_t depth, +@@ -28,6 +36,11 @@ + #if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { ++#if !defined(__x86_64__) && !defined(__SSE2__) ++ angle::SSE2::LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, ++ inputDepthPitch, output, outputRowPitch, ++ outputDepthPitch); ++#else + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) +@@ -68,6 +81,7 @@ + } + } + } ++#endif + + return; + } +@@ -89,6 +103,8 @@ + } + } + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + void LoadA8ToBGRA8(size_t width, + size_t height, + size_t depth, +@@ -584,6 +600,8 @@ + } + } + ++#endif ++ + void LoadRGBA8ToBGRA8(size_t width, + size_t height, + size_t depth, +@@ -597,6 +615,11 @@ + #if defined(ANGLE_USE_SSE) + if (gl::supportsSSE2()) + { ++#if !defined(__x86_64__) && !defined(__SSE2__) ++ angle::SSE2::LoadRGBA8ToBGRA8(width, height, depth, input, ++ inputRowPitch, inputDepthPitch, output, ++ outputRowPitch, outputDepthPitch); ++#else + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) +@@ -641,6 +664,7 @@ + } + } + } ++#endif + + return; + } +@@ -663,6 +687,8 @@ + } + } + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + void LoadRGBA8ToBGRA4(size_t width, + size_t height, + size_t depth, +@@ -1320,4 +1346,10 @@ + } + } + ++#endif ++ ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++} // namespace SSE2 ++#endif ++ + } // namespace angle +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h 2017-12-25 13:05:24.018939571 +0100 +@@ -651,6 +651,32 @@ + size_t outputRowPitch, + size_t outputDepthPitch); + ++#if defined(__i386__) ++namespace SSE2 { ++ ++void LoadA8ToRGBA8(size_t width, ++ size_t height, ++ size_t depth, ++ const uint8_t *input, ++ size_t inputRowPitch, ++ size_t inputDepthPitch, ++ uint8_t *output, ++ size_t outputRowPitch, ++ size_t outputDepthPitch); ++ ++void LoadRGBA8ToBGRA8(size_t width, ++ size_t height, ++ size_t depth, ++ const uint8_t *input, ++ size_t inputRowPitch, ++ size_t inputDepthPitch, ++ uint8_t *output, ++ size_t outputRowPitch, ++ size_t outputDepthPitch); ++ ++} ++#endif // defined(__i386__) ++ + } // namespace angle + + #include "loadimage.inl" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp 2017-12-25 13:05:24.018939571 +0100 +@@ -0,0 +1,2 @@ ++#define BUILD_ONLY_THE_SSE2_PARTS ++#include "loadimage.cpp" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/qcms/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/qcms/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/qcms/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/qcms/BUILD.gn 2017-12-25 13:51:32.804702578 +0100 +@@ -34,8 +34,8 @@ + defines = [] + + if (current_cpu == "x86" || current_cpu == "x64") { +- defines += [ "SSE2_ENABLE" ] +- sources += [ "src/transform-sse2.c" ] ++ defines += [ "SSE2_ENABLE" ] # runtime detection ++ deps = [ ":qcms_sse2" ] + } + + if (use_libfuzzer) { +@@ -99,3 +99,15 @@ + public_configs = [ ":qcms_config" ] + } + } ++ ++source_set("qcms_sse2") { ++ configs -= [ "//build/config/compiler:chromium_code" ] ++ configs += [ "//build/config/compiler:no_chromium_code" ] ++ public_configs = [ ":qcms_config" ] ++ ++ if (current_cpu == "x86" || current_cpu == "x64") { ++ defines = [ "SSE2_ENABLE" ] ++ sources = [ "src/transform-sse2.c" ] ++ cflags = [ "-msse2" ] ++ } ++} +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp 2017-12-25 14:03:37.424681528 +0100 +@@ -35,7 +35,7 @@ + #include "platform/wtf/MathExtras.h" + #include "platform/wtf/PtrUtil.h" + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + #include + #endif + +@@ -1290,7 +1290,7 @@ + size_t current_frame, + float value, + unsigned write_index) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + auto number_of_values = current_state.number_of_values; + #endif + auto fill_to_frame = current_state.fill_to_frame; +@@ -1303,7 +1303,7 @@ + double delta_time = time2 - time1; + float k = delta_time > 0 ? 1 / delta_time : 0; + const float value_delta = value2 - value1; +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if (fill_to_frame > write_index) { + // Minimize in-loop operations. Calculate starting value and increment. + // Next step: value += inc. +@@ -1431,7 +1431,7 @@ + size_t current_frame, + float value, + unsigned write_index) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + auto number_of_values = current_state.number_of_values; + #endif + auto fill_to_frame = current_state.fill_to_frame; +@@ -1482,7 +1482,7 @@ + for (; write_index < fill_to_frame; ++write_index) + values[write_index] = target; + } else { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if (fill_to_frame > write_index) { + // Resolve recursion by expanding constants to achieve a 4-step + // loop unrolling. +@@ -1616,7 +1616,7 @@ + // Oversampled curve data can be provided if sharp discontinuities are + // desired. + unsigned k = 0; +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if (fill_to_frame > write_index) { + const __m128 v_curve_virtual_index = _mm_set_ps1(curve_virtual_index); + const __m128 v_curve_points_per_frame = _mm_set_ps1(curve_points_per_frame); +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp 2017-12-25 14:40:01.051077869 +0100 +@@ -26,6 +26,9 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++// include this first to get it before the CPU() function-like macro ++#include "base/cpu.h" ++ + #include "platform/audio/DirectConvolver.h" + + #include "build/build_config.h" +@@ -35,21 +38,48 @@ + #include + #endif + +-#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_MACOSX) ++#if ((defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64)) \ ++ && !defined(OS_MACOSX) + #include + #endif + ++#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) ++#error SSE2 parts must be built with -msse2 ++#endif ++ + namespace blink { + + using namespace VectorMath; + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + DirectConvolver::DirectConvolver(size_t input_block_size) +- : input_block_size_(input_block_size), buffer_(input_block_size * 2) {} ++ : m_inputBlockSize(inputBlockSize), m_buffer(inputBlockSize * 2) { ++#ifdef ARCH_CPU_X86 ++ base::CPU cpu; ++ m_haveSSE2 = cpu.has_sse2(); ++#endif ++} ++ ++#endif + ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++void DirectConvolver::m_ProcessSSE2(AudioFloatArray* convolution_kernel, ++ const float* source_p, ++ float* dest_p, ++ size_t frames_to_process) { ++#else + void DirectConvolver::Process(AudioFloatArray* convolution_kernel, + const float* source_p, + float* dest_p, + size_t frames_to_process) { ++#endif ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (m_haveSSE2) { ++ m_ProcessSSE2(convolution_kernel, source_p, dest_p, frames_to_process); ++ return; ++ } ++#endif + DCHECK_EQ(frames_to_process, input_block_size_); + if (frames_to_process != input_block_size_) + return; +@@ -83,7 +113,7 @@ + #endif // ARCH_CPU_X86 + #else + size_t i = 0; +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + // Convolution using SSE2. Currently only do this if both |kernelSize| and + // |framesToProcess| are multiples of 4. If not, use the straightforward loop + // below. +@@ -397,7 +427,7 @@ + } + dest_p[i++] = sum; + } +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + } + #endif + #endif // OS_MACOSX +@@ -406,8 +436,12 @@ + memcpy(buffer_.Data(), input_p, sizeof(float) * frames_to_process); + } + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + void DirectConvolver::Reset() { + buffer_.Zero(); + } + ++#endif ++ + } // namespace blink +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h 2017-12-25 14:39:21.094641400 +0100 +@@ -29,6 +29,7 @@ + #ifndef DirectConvolver_h + #define DirectConvolver_h + ++#include "build/build_config.h" + #include "platform/PlatformExport.h" + #include "platform/audio/AudioArray.h" + #include "platform/wtf/Allocator.h" +@@ -54,6 +55,14 @@ + size_t input_block_size_; + + AudioFloatArray buffer_; ++ ++#ifdef ARCH_CPU_X86 ++ bool m_haveSSE2; ++ void m_ProcessSSE2(AudioFloatArray* convolution_kernel, ++ const float* source_p, ++ float* dest_p, ++ size_t frames_to_process); ++#endif + }; + + } // namespace blink +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp 2017-12-25 13:05:24.021939534 +0100 +@@ -0,0 +1,2 @@ ++#define BUILD_ONLY_THE_SSE2_PARTS ++#include "DirectConvolver.cpp" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp 2017-12-25 14:41:03.697194334 +0100 +@@ -26,16 +26,23 @@ + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++// include this first to get it before the CPU() function-like macro ++#include "base/cpu.h" ++ + #include "platform/audio/SincResampler.h" + + #include "build/build_config.h" + #include "platform/audio/AudioBus.h" + #include "platform/wtf/MathExtras.h" + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + #include + #endif + ++#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) ++#error SSE2 parts must be built with -msse2 ++#endif ++ + // Input buffer layout, dividing the total buffer into regions (r0 - r5): + // + // |----------------|-----------------------------------------|----------------| +@@ -67,6 +74,8 @@ + + namespace blink { + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + SincResampler::SincResampler(double scale_factor, + unsigned kernel_size, + unsigned number_of_kernel_offsets) +@@ -82,6 +91,10 @@ + source_frames_available_(0), + source_provider_(nullptr), + is_buffer_primed_(false) { ++#ifdef ARCH_CPU_X86 ++ base::CPU cpu; ++ m_haveSSE2 = cpu.has_sse2(); ++#endif + InitializeKernel(); + } + +@@ -205,9 +218,23 @@ + } + } + ++#endif ++ ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++void SincResampler::m_ProcessSSE2(AudioSourceProvider* source_provider, ++ float* destination, ++ size_t frames_to_process) { ++#else + void SincResampler::Process(AudioSourceProvider* source_provider, + float* destination, + size_t frames_to_process) { ++#endif ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (m_haveSSE2) { ++ m_ProcessSSE2(source_provider, destination, frames_to_process); ++ return; ++ } ++#endif + bool is_good = source_provider && block_size_ > kernel_size_ && + input_buffer_.size() >= block_size_ + kernel_size_ && + !(kernel_size_ % 2); +@@ -276,7 +303,7 @@ + { + float input; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + // If the sourceP address is not 16-byte aligned, the first several + // frames (at most three) should be processed seperately. + while ((reinterpret_cast(input_p) & 0x0F) && n) { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h 2017-12-25 14:40:36.454578552 +0100 +@@ -29,6 +29,7 @@ + #ifndef SincResampler_h + #define SincResampler_h + ++#include "build/build_config.h" + #include "platform/PlatformExport.h" + #include "platform/audio/AudioArray.h" + #include "platform/audio/AudioSourceProvider.h" +@@ -96,6 +97,14 @@ + + // The buffer is primed once at the very beginning of processing. + bool is_buffer_primed_; ++ ++#ifdef ARCH_CPU_X86 ++ private: ++ bool m_haveSSE2; ++ void m_ProcessSSE2(AudioSourceProvider*, ++ float* destination, ++ size_t frames_to_process); ++#endif + }; + + } // namespace blink +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp 2017-12-25 13:05:24.022939522 +0100 +@@ -0,0 +1,2 @@ ++#define BUILD_ONLY_THE_SSE2_PARTS ++#include "SincResampler.cpp" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp 2017-12-25 14:48:07.515216969 +0100 +@@ -23,6 +23,9 @@ + * DAMAGE. + */ + ++// include this first to get it before the CPU() function-like macro ++#include "base/cpu.h" ++ + #include "platform/audio/VectorMath.h" + + #include +@@ -35,10 +38,14 @@ + #include + #endif + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + #include + #endif + ++#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) ++#error SSE2 parts must be built with -msse2 ++#endif ++ + #if WTF_CPU_ARM_NEON + #include + #endif +@@ -170,15 +177,30 @@ + } + #else + ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++namespace SSE2 { ++#endif ++ ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++static base::CPU cpu; ++#endif ++ + void Vsma(const float* source_p, + int source_stride, + const float* scale, + float* dest_p, + int dest_stride, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vsma(source_p, source_stride, scale, dest_p, ++ dest_stride, frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if ((source_stride == 1) && (dest_stride == 1)) { + float k = *scale; + +@@ -274,9 +296,16 @@ + float* dest_p, + int dest_stride, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vsmul(source_p, source_stride, scale, dest_p, ++ dest_stride, frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if ((source_stride == 1) && (dest_stride == 1)) { + float k = *scale; + +@@ -365,7 +394,7 @@ + source_p += source_stride; + dest_p += dest_stride; + } +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + } + #endif + } +@@ -377,9 +406,17 @@ + float* dest_p, + int dest_stride, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vadd(source1p, source_stride1, source2p, ++ source_stride2, dest_p, dest_stride, ++ frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if ((source_stride1 == 1) && (source_stride2 == 1) && (dest_stride == 1)) { + // If the sourceP address is not 16-byte aligned, the first several frames + // (at most three) should be processed separately. +@@ -506,7 +543,7 @@ + source2p += source_stride2; + dest_p += dest_stride; + } +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + } + #endif + } +@@ -518,9 +555,17 @@ + float* dest_p, + int dest_stride, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vmul(source1p, source_stride1, source2p, ++ source_stride2, dest_p, dest_stride, ++ frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if ((source_stride1 == 1) && (source_stride2 == 1) && (dest_stride == 1)) { + // If the source1P address is not 16-byte aligned, the first several frames + // (at most three) should be processed separately. +@@ -619,8 +664,15 @@ + float* real_dest_p, + float* imag_dest_p, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Zvmul(real1p, imag1p, real2p, imag2p, real_dest_p, ++ imag_dest_p, frames_to_process); ++ return; ++ } ++#endif + unsigned i = 0; +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + // Only use the SSE optimization in the very common case that all addresses + // are 16-byte aligned. Otherwise, fall through to the scalar code below. + if (!(reinterpret_cast(real1p) & 0x0F) && +@@ -676,10 +728,17 @@ + int source_stride, + float* sum_p, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vsvesq(source_p, source_stride, sum_p, ++ frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + float sum = 0; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if (source_stride == 1) { + // If the sourceP address is not 16-byte aligned, the first several frames + // (at most three) should be processed separately. +@@ -745,10 +804,17 @@ + int source_stride, + float* max_p, + size_t frames_to_process) { ++#if defined(ARCH_CPU_X86) && !defined(__SSE2__) ++ if (cpu.has_sse2()) { ++ blink::VectorMath::SSE2::Vmaxmgv(source_p, source_stride, max_p, ++ frames_to_process); ++ return; ++ } ++#endif + int n = frames_to_process; + float max = 0; + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + if (source_stride == 1) { + // If the sourceP address is not 16-byte aligned, the first several frames + // (at most three) should be processed separately. +@@ -837,6 +903,8 @@ + *max_p = max; + } + ++#ifndef BUILD_ONLY_THE_SSE2_PARTS ++ + void Vclip(const float* source_p, + int source_stride, + const float* low_threshold_p, +@@ -894,6 +962,12 @@ + } + } + ++#endif ++ ++#ifdef BUILD_ONLY_THE_SSE2_PARTS ++} // namespace SSE2 ++#endif ++ + #endif // defined(OS_MACOSX) + + } // namespace VectorMath +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h 2017-12-25 14:51:17.547536826 +0100 +@@ -27,6 +27,7 @@ + #define VectorMath_h + + #include ++#include "build/build_config.h" + #include "platform/PlatformExport.h" + #include "platform/wtf/build_config.h" + +@@ -97,6 +98,62 @@ + int dest_stride, + size_t frames_to_process); + ++#ifdef ARCH_CPU_X86 ++namespace SSE2 { ++// Vector scalar multiply and then add. ++PLATFORM_EXPORT void Vsma(const float* source_p, ++ int source_stride, ++ const float* scale, ++ float* dest_p, ++ int dest_stride, ++ size_t frames_to_process); ++ ++PLATFORM_EXPORT void Vsmul(const float* source_p, ++ int source_stride, ++ const float* scale, ++ float* dest_p, ++ int dest_stride, ++ size_t frames_to_process); ++PLATFORM_EXPORT void Vadd(const float* source1p, ++ int source_stride1, ++ const float* source2p, ++ int source_stride2, ++ float* dest_p, ++ int dest_stride, ++ size_t frames_to_process); ++ ++// Finds the maximum magnitude of a float vector. ++PLATFORM_EXPORT void Vmaxmgv(const float* source_p, ++ int source_stride, ++ float* max_p, ++ size_t frames_to_process); ++ ++// Sums the squares of a float vector's elements. ++PLATFORM_EXPORT void Vsvesq(const float* source_p, ++ int source_stride, ++ float* sum_p, ++ size_t frames_to_process); ++ ++// For an element-by-element multiply of two float vectors. ++PLATFORM_EXPORT void Vmul(const float* source1p, ++ int source_stride1, ++ const float* source2p, ++ int source_stride2, ++ float* dest_p, ++ int dest_stride, ++ size_t frames_to_process); ++ ++// Multiplies two complex vectors. ++PLATFORM_EXPORT void Zvmul(const float* real1p, ++ const float* imag1p, ++ const float* real2p, ++ const float* imag2p, ++ float* real_dest_p, ++ float* imag_dest_p, ++ size_t frames_to_process); ++} ++#endif ++ + } // namespace VectorMath + } // namespace blink + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp 2017-12-25 13:05:24.024939497 +0100 +@@ -0,0 +1,2 @@ ++#define BUILD_ONLY_THE_SSE2_PARTS ++#include "VectorMath.cpp" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn 2017-12-25 13:05:24.025939484 +0100 +@@ -1693,6 +1693,10 @@ + deps += [ ":blink_x86_sse" ] + } + ++ if (current_cpu == "x86") { ++ deps += [ ":blink_x86_sse2" ] ++ } ++ + if (use_webaudio_ffmpeg) { + include_dirs += [ "//third_party/ffmpeg" ] + deps += [ "//third_party/ffmpeg" ] +@@ -2139,6 +2143,26 @@ + } + } + ++if (current_cpu == "x86") { ++ source_set("blink_x86_sse2") { ++ sources = [ ++ "audio/DirectConvolverSSE2.cpp", ++ "audio/SincResamplerSSE2.cpp", ++ "audio/VectorMathSSE2.cpp", ++ ] ++ cflags = [ "-msse2", "-mfpmath=sse" ] ++ deps = [ ++ ":blink_common", ++ ] ++ configs += [ ++ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. ++ "//build/config/compiler:no_size_t_to_int_warning", ++ "//third_party/WebKit/Source:config", ++ "//third_party/WebKit/Source:non_test_config", ++ ] ++ } ++} ++ + # This source set is used for fuzzers that need an environment similar to unit + # tests. + source_set("blink_fuzzer_test_support") { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h 2017-12-25 17:01:28.182182131 +0100 +@@ -7,7 +7,7 @@ + + #include "build/build_config.h" + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + #include + + namespace blink { +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp 2017-12-25 17:03:30.477435712 +0100 +@@ -444,7 +444,7 @@ + const uint32_t* source32 = reinterpret_cast_ptr(source); + uint32_t* destination32 = reinterpret_cast_ptr(destination); + +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::UnpackOneRowOfBGRA8LittleToRGBA8(source32, destination32, + pixels_per_row); + #endif +@@ -472,7 +472,7 @@ + const uint16_t* source, + uint8_t* destination, + unsigned pixels_per_row) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::UnpackOneRowOfRGBA5551LittleToRGBA8(source, destination, + pixels_per_row); + #endif +@@ -502,7 +502,7 @@ + const uint16_t* source, + uint8_t* destination, + unsigned pixels_per_row) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::UnpackOneRowOfRGBA4444LittleToRGBA8(source, destination, + pixels_per_row); + #endif +@@ -718,7 +718,7 @@ + uint8_t>(const uint8_t* source, + uint8_t* destination, + unsigned pixels_per_row) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::PackOneRowOfRGBA8LittleToR8(source, destination, pixels_per_row); + #endif + #if HAVE(MIPS_MSA_INTRINSICS) +@@ -775,7 +775,7 @@ + uint8_t>(const uint8_t* source, + uint8_t* destination, + unsigned pixels_per_row) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::PackOneRowOfRGBA8LittleToRA8(source, destination, pixels_per_row); + #endif + #if HAVE(MIPS_MSA_INTRINSICS) +@@ -887,7 +887,7 @@ + uint8_t>(const uint8_t* source, + uint8_t* destination, + unsigned pixels_per_row) { +-#if defined(ARCH_CPU_X86_FAMILY) ++#if (defined(ARCH_CPU_X86) && defined(__SSE2__)) || defined(ARCH_CPU_X86_64) + SIMD::PackOneRowOfRGBA8LittleToRGBA8(source, destination, pixels_per_row); + #endif + #if HAVE(MIPS_MSA_INTRINSICS) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc 2017-12-25 17:05:49.957443890 +0100 +@@ -14,6 +14,7 @@ + #include "webrtc/common_audio/real_fourier_openmax.h" + #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" + #include "webrtc/rtc_base/checks.h" ++#include "webrtc/system_wrappers/include/cpu_features_wrapper.h" + + namespace webrtc { + +@@ -23,7 +24,15 @@ + + std::unique_ptr RealFourier::Create(int fft_order) { + #if defined(RTC_USE_OPENMAX_DL) ++#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__) ++ // x86 CPU detection required. ++ if (WebRtc_GetCPUInfo(kSSE2)) ++ return std::unique_ptr(new RealFourierOpenmax(fft_order)); ++ else ++ return std::unique_ptr(new RealFourierOoura(fft_order)); ++#else + return std::unique_ptr(new RealFourierOpenmax(fft_order)); ++#endif + #else + return std::unique_ptr(new RealFourierOoura(fft_order)); + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/BUILD.gn 2017-12-25 17:42:57.199465881 +0100 +@@ -116,9 +116,9 @@ + v8_experimental_extra_library_files = + [ "//test/cctest/test-experimental-extra.js" ] + +- v8_enable_gdbjit = +- ((v8_current_cpu == "x86" || v8_current_cpu == "x64") && +- (is_linux || is_mac)) || (v8_current_cpu == "ppc64" && is_linux) ++ v8_enable_gdbjit = ((v8_current_cpu == "x86" || v8_current_cpu == "x64" || ++ v8_current_cpu == "x87") && (is_linux || is_mac)) || ++ (v8_current_cpu == "ppc64" && is_linux) + + # Temporary flag to allow embedders to update their microtasks scopes + # while rolling in a new version of V8. +@@ -161,7 +161,7 @@ + + include_dirs = [ "." ] + +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "BUILDING_V8_SHARED" ] + } + } +@@ -175,14 +175,14 @@ + # This config should be applied to code using the libplatform. + config("libplatform_config") { + include_dirs = [ "include" ] +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "USING_V8_PLATFORM_SHARED" ] + } + } + + # This config should be applied to code using the libbase. + config("libbase_config") { +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "USING_V8_BASE_SHARED" ] + } + libs = [] +@@ -199,7 +199,7 @@ + # This config should only be applied to code using V8 and not any V8 code + # itself. + config("external_config") { +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "USING_V8_SHARED" ] + } + include_dirs = [ +@@ -434,6 +434,9 @@ + cflags += [ "/arch:SSE2" ] + } + } ++ if (v8_current_cpu == "x87") { ++ defines += [ "V8_TARGET_ARCH_X87" ] ++ } + if (v8_current_cpu == "x64") { + defines += [ "V8_TARGET_ARCH_X64" ] + if (is_win) { +@@ -443,6 +446,9 @@ + ldflags += [ "/STACK:2097152" ] + } + } ++ if (v8_current_cpu == "x87") { ++ defines += [ "V8_TARGET_ARCH_X87" ] ++ } + if (is_android && v8_android_log_stdout) { + defines += [ "V8_ANDROID_LOG_STDOUT" ] + } +@@ -1040,6 +1046,11 @@ + ### gcmole(arch:s390) ### + "src/builtins/s390/builtins-s390.cc", + ] ++ } else if (v8_current_cpu == "x87") { ++ sources += [ ++ ### gcmole(arch:x87) ### ++ "src/builtins/x87/builtins-x87.cc", ++ ] + } + + if (!v8_enable_i18n_support) { +@@ -2309,6 +2320,37 @@ + "src/s390/simulator-s390.cc", + "src/s390/simulator-s390.h", + ] ++ } else if (v8_current_cpu == "x87") { ++ sources += [ ### gcmole(arch:x87) ### ++ "src/compiler/x87/code-generator-x87.cc", ++ "src/compiler/x87/instruction-codes-x87.h", ++ "src/compiler/x87/instruction-scheduler-x87.cc", ++ "src/compiler/x87/instruction-selector-x87.cc", ++ "src/debug/x87/debug-x87.cc", ++ "src/full-codegen/x87/full-codegen-x87.cc", ++ "src/ic/x87/access-compiler-x87.cc", ++ "src/ic/x87/handler-compiler-x87.cc", ++ "src/ic/x87/ic-x87.cc", ++ "src/regexp/x87/regexp-macro-assembler-x87.cc", ++ "src/regexp/x87/regexp-macro-assembler-x87.h", ++ "src/x87/assembler-x87-inl.h", ++ "src/x87/assembler-x87.cc", ++ "src/x87/assembler-x87.h", ++ "src/x87/code-stubs-x87.cc", ++ "src/x87/code-stubs-x87.h", ++ "src/x87/codegen-x87.cc", ++ "src/x87/codegen-x87.h", ++ "src/x87/cpu-x87.cc", ++ "src/x87/deoptimizer-x87.cc", ++ "src/x87/disasm-x87.cc", ++ "src/x87/frames-x87.cc", ++ "src/x87/frames-x87.h", ++ "src/x87/interface-descriptors-x87.cc", ++ "src/x87/macro-assembler-x87.cc", ++ "src/x87/macro-assembler-x87.h", ++ "src/x87/simulator-x87.cc", ++ "src/x87/simulator-x87.h", ++ ] + } + + configs = [ ":internal_config" ] +@@ -2420,7 +2462,7 @@ + + defines = [] + +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "BUILDING_V8_BASE_SHARED" ] + } + +@@ -2530,7 +2572,7 @@ + + configs = [ ":internal_config_base" ] + +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "BUILDING_V8_PLATFORM_SHARED" ] + } + +@@ -2676,7 +2718,22 @@ + ] + } + +-if (is_component_build) { ++if (v8_build_shared) { ++ shared_library("v8") { ++ sources = [ ++ "src/v8dll-main.cc", ++ ] ++ ++ public_deps = [ ++ ":v8_base", ++ ":v8_maybe_snapshot", ++ ] ++ ++ configs += [ ":internal_config" ] ++ ++ public_configs = [ ":external_config" ] ++ } ++} else if (is_component_build) { + v8_component("v8") { + sources = [ + "src/v8dll-main.cc", +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gni/v8.gni qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gni/v8.gni +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gni/v8.gni 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gni/v8.gni 2017-12-25 18:02:06.095884970 +0100 +@@ -42,6 +42,9 @@ + # add a dependency on the ICU library. + v8_enable_i18n_support = true + ++ # Whether to build V8 as a shared library ++ v8_build_shared = false ++ + # Use static libraries instead of source_sets. + v8_static_library = false + } +@@ -56,6 +59,11 @@ + v8_enable_backtrace = is_debug && !v8_optimized_debug + } + ++if (v8_current_cpu == "x86" || v8_current_cpu == "x87") { ++ # build V8 shared on x86 so we can swap x87 vs. SSE2 builds ++ v8_build_shared = true ++} ++ + # Points to // in v8 stand-alone or to //v8/ in chromium. We need absolute + # paths for all configs in templates as they are shared in different + # subdirectories. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gypfiles/standalone.gypi qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gypfiles/standalone.gypi +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gypfiles/standalone.gypi 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gypfiles/standalone.gypi 2017-12-25 17:42:57.200465867 +0100 +@@ -262,14 +262,14 @@ + # goma doesn't support PDB yet. + 'fastbuild%': 1, + }], +- ['((v8_target_arch=="ia32" or v8_target_arch=="x64") and \ ++ ['((v8_target_arch=="ia32" or v8_target_arch=="x64" or v8_target_arch=="x87") and \ + (OS=="linux" or OS=="mac")) or (v8_target_arch=="ppc64" and OS=="linux")', { + 'v8_enable_gdbjit%': 1, + }, { + 'v8_enable_gdbjit%': 0, + }], + ['(OS=="linux" or OS=="mac") and (target_arch=="ia32" or target_arch=="x64") and \ +- v8_target_arch!="x32"', { ++ (v8_target_arch!="x87" and v8_target_arch!="x32")', { + 'clang%': 1, + }, { + 'clang%': 0, +@@ -1207,7 +1207,7 @@ + '-L<(android_libcpp_libs)/arm64-v8a', + ], + }], +- ['target_arch=="ia32"', { ++ ['target_arch=="ia32" or target_arch=="x87"', { + # The x86 toolchain currently has problems with stack-protector. + 'cflags!': [ + '-fstack-protector', +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gypfiles/toolchain.gypi qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gypfiles/toolchain.gypi +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/gypfiles/toolchain.gypi 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/gypfiles/toolchain.gypi 2017-12-25 17:42:57.200465867 +0100 +@@ -144,7 +144,7 @@ + 'host_cxx_is_biarch%': 0, + }, + }], +- ['target_arch=="ia32" or target_arch=="x64" or \ ++ ['target_arch=="ia32" or target_arch=="x64" or target_arch=="x87" or \ + target_arch=="ppc" or target_arch=="ppc64" or target_arch=="s390" or \ + target_arch=="s390x" or clang==1', { + 'variables': { +@@ -342,6 +342,12 @@ + 'V8_TARGET_ARCH_IA32', + ], + }], # v8_target_arch=="ia32" ++ ['v8_target_arch=="x87"', { ++ 'defines': [ ++ 'V8_TARGET_ARCH_X87', ++ ], ++ 'cflags': ['-march=i586'], ++ }], # v8_target_arch=="x87" + ['v8_target_arch=="mips" or v8_target_arch=="mipsel" \ + or v8_target_arch=="mips64" or v8_target_arch=="mips64el"', { + 'target_conditions': [ +@@ -1000,8 +1006,9 @@ + ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris" \ + or OS=="netbsd" or OS=="mac" or OS=="android" or OS=="qnx") and \ + (v8_target_arch=="arm" or v8_target_arch=="ia32" or \ +- v8_target_arch=="mips" or v8_target_arch=="mipsel" or \ +- v8_target_arch=="ppc" or v8_target_arch=="s390")', { ++ v8_target_arch=="x87" or v8_target_arch=="mips" or \ ++ v8_target_arch=="mipsel" or v8_target_arch=="ppc" or \ ++ v8_target_arch=="s390")', { + 'target_conditions': [ + ['_toolset=="host"', { + 'conditions': [ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/Makefile qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/Makefile +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/Makefile 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/Makefile 2017-12-25 17:42:57.200465867 +0100 +@@ -255,13 +255,14 @@ + + # Architectures and modes to be compiled. Consider these to be internal + # variables, don't override them (use the targets instead). +-ARCHES = ia32 x64 arm arm64 mips mipsel mips64 mips64el ppc ppc64 s390 s390x +-ARCHES32 = ia32 arm mips mipsel ppc s390 ++ARCHES = ia32 x64 arm arm64 mips mipsel mips64 mips64el x87 ppc ppc64 s390 \ ++ s390x ++ARCHES32 = ia32 arm mips mipsel x87 ppc s390 + DEFAULT_ARCHES = ia32 x64 arm + MODES = release debug optdebug + DEFAULT_MODES = release debug + ANDROID_ARCHES = android_ia32 android_x64 android_arm android_arm64 \ +- android_mipsel ++ android_mipsel android_x87 + + # List of files that trigger Makefile regeneration: + GYPFILES = third_party/icu/icu.gypi third_party/icu/icu.gyp \ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/assembler.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/assembler.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/assembler.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/assembler.cc 2017-12-25 17:42:57.201465852 +0100 +@@ -85,6 +85,8 @@ + #include "src/regexp/mips64/regexp-macro-assembler-mips64.h" // NOLINT + #elif V8_TARGET_ARCH_S390 + #include "src/regexp/s390/regexp-macro-assembler-s390.h" // NOLINT ++#elif V8_TARGET_ARCH_X87 ++#include "src/regexp/x87/regexp-macro-assembler-x87.h" // NOLINT + #else // Unknown architecture. + #error "Unknown architecture." + #endif // Target architecture. +@@ -1318,6 +1320,8 @@ + function = FUNCTION_ADDR(RegExpMacroAssemblerMIPS::CheckStackGuardState); + #elif V8_TARGET_ARCH_S390 + function = FUNCTION_ADDR(RegExpMacroAssemblerS390::CheckStackGuardState); ++#elif V8_TARGET_ARCH_X87 ++ function = FUNCTION_ADDR(RegExpMacroAssemblerX87::CheckStackGuardState); + #else + UNREACHABLE(); + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/assembler-inl.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/assembler-inl.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/assembler-inl.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/assembler-inl.h 2017-12-25 17:42:57.201465852 +0100 +@@ -23,6 +23,8 @@ + #include "src/mips64/assembler-mips64-inl.h" + #elif V8_TARGET_ARCH_S390 + #include "src/s390/assembler-s390-inl.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/assembler-x87-inl.h" + #else + #error Unknown architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/base/build_config.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/base/build_config.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/base/build_config.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/base/build_config.h 2017-12-25 17:42:57.201465852 +0100 +@@ -76,9 +76,9 @@ + // Target architecture detection. This may be set externally. If not, detect + // in the same way as the host architecture, that is, target the native + // environment as presented by the compiler. +-#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && \ +- !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 && \ +- !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_S390 ++#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_X87 && \ ++ !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_MIPS && \ ++ !V8_TARGET_ARCH_MIPS64 && !V8_TARGET_ARCH_PPC && !V8_TARGET_ARCH_S390 + #if defined(_M_X64) || defined(__x86_64__) + #define V8_TARGET_ARCH_X64 1 + #elif defined(_M_IX86) || defined(__i386__) +@@ -129,6 +129,8 @@ + #else + #define V8_TARGET_ARCH_32_BIT 1 + #endif ++#elif V8_TARGET_ARCH_X87 ++#define V8_TARGET_ARCH_32_BIT 1 + #else + #error Unknown target architecture pointer size + #endif +@@ -179,6 +181,8 @@ + #else + #define V8_TARGET_LITTLE_ENDIAN 1 + #endif ++#elif V8_TARGET_ARCH_X87 ++#define V8_TARGET_LITTLE_ENDIAN 1 + #elif __BIG_ENDIAN__ // FOR PPCGR on AIX + #define V8_TARGET_BIG_ENDIAN 1 + #elif V8_TARGET_ARCH_PPC_LE +@@ -195,7 +199,8 @@ + #error Unknown target architecture endianness + #endif + +-#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64) ++#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64) || \ ++ defined(V8_TARGET_ARCH_X87) + #define V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK 1 + #else + #define V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK 0 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/builtins-x87.cc 2017-12-25 17:42:57.204465808 +0100 +@@ -0,0 +1,3143 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/code-factory.h" ++#include "src/codegen.h" ++#include "src/deoptimizer.h" ++#include "src/full-codegen/full-codegen.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm) ++ ++void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address, ++ ExitFrameType exit_frame_type) { ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments excluding receiver ++ // -- edi : target ++ // -- edx : new.target ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // -- ... ++ // -- esp[4 * argc] : first argument ++ // -- esp[4 * (argc +1)] : receiver ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // Make sure we operate in the context of the called function (for example ++ // ConstructStubs implemented in C++ will be run in the context of the caller ++ // instead of the callee, due to the way that [[Construct]] is defined for ++ // ordinary functions). ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ // JumpToExternalReference expects eax to contain the number of arguments ++ // including the receiver and the extra arguments. ++ const int num_extra_args = 3; ++ __ add(eax, Immediate(num_extra_args + 1)); ++ ++ // Insert extra arguments. ++ __ PopReturnAddressTo(ecx); ++ __ SmiTag(eax); ++ __ Push(eax); ++ __ SmiUntag(eax); ++ __ Push(edi); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ ++ __ JumpToExternalReference(ExternalReference(address, masm->isolate()), ++ exit_frame_type == BUILTIN_EXIT); ++} ++ ++static void GenerateTailCallToReturnedCode(MacroAssembler* masm, ++ Runtime::FunctionId function_id) { ++ // ----------- S t a t e ------------- ++ // -- eax : argument count (preserved for callee) ++ // -- edx : new target (preserved for callee) ++ // -- edi : target function (preserved for callee) ++ // ----------------------------------- ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // Push the number of arguments to the callee. ++ __ SmiTag(eax); ++ __ push(eax); ++ // Push a copy of the target function and the new target. ++ __ push(edi); ++ __ push(edx); ++ // Function is also the parameter to the runtime call. ++ __ push(edi); ++ ++ __ CallRuntime(function_id, 1); ++ __ mov(ebx, eax); ++ ++ // Restore target function and new target. ++ __ pop(edx); ++ __ pop(edi); ++ __ pop(eax); ++ __ SmiUntag(eax); ++ } ++ ++ __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); ++ __ jmp(ebx); ++} ++ ++static void GenerateTailCallToSharedCode(MacroAssembler* masm) { ++ __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset)); ++ __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); ++ __ jmp(ebx); ++} ++ ++void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { ++ // Checking whether the queued function is ready for install is optional, ++ // since we come across interrupts and stack checks elsewhere. However, ++ // not checking may delay installing ready functions, and always checking ++ // would be quite expensive. A good compromise is to first check against ++ // stack limit as a cue for an interrupt signal. ++ Label ok; ++ ExternalReference stack_limit = ++ ExternalReference::address_of_stack_limit(masm->isolate()); ++ __ cmp(esp, Operand::StaticVariable(stack_limit)); ++ __ j(above_equal, &ok, Label::kNear); ++ ++ GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); ++ ++ __ bind(&ok); ++ GenerateTailCallToSharedCode(masm); ++} ++ ++namespace { ++ ++void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ++ bool create_implicit_receiver, ++ bool check_derived_construct) { ++ // ----------- S t a t e ------------- ++ // -- eax: number of arguments ++ // -- esi: context ++ // -- edi: constructor function ++ // -- edx: new target ++ // ----------------------------------- ++ ++ // Enter a construct frame. ++ { ++ FrameScope scope(masm, StackFrame::CONSTRUCT); ++ ++ // Preserve the incoming parameters on the stack. ++ __ SmiTag(eax); ++ __ push(esi); ++ __ push(eax); ++ ++ if (create_implicit_receiver) { ++ // Allocate the new receiver object. ++ __ Push(edi); ++ __ Push(edx); ++ __ Call(Builtins::CallableFor(masm->isolate(), Builtins::kFastNewObject) ++ .code(), ++ RelocInfo::CODE_TARGET); ++ __ mov(ebx, eax); ++ __ Pop(edx); ++ __ Pop(edi); ++ ++ // ----------- S t a t e ------------- ++ // -- edi: constructor function ++ // -- ebx: newly allocated object ++ // -- edx: new target ++ // ----------------------------------- ++ ++ // Retrieve smi-tagged arguments count from the stack. ++ __ mov(eax, Operand(esp, 0)); ++ } ++ ++ __ SmiUntag(eax); ++ ++ if (create_implicit_receiver) { ++ // Push the allocated receiver to the stack. We need two copies ++ // because we may have to return the original one and the calling ++ // conventions dictate that the called function pops the receiver. ++ __ push(ebx); ++ __ push(ebx); ++ } else { ++ __ PushRoot(Heap::kTheHoleValueRootIndex); ++ } ++ ++ // Set up pointer to last argument. ++ __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); ++ ++ // Copy arguments and receiver to the expression stack. ++ Label loop, entry; ++ __ mov(ecx, eax); ++ __ jmp(&entry); ++ __ bind(&loop); ++ __ push(Operand(ebx, ecx, times_4, 0)); ++ __ bind(&entry); ++ __ dec(ecx); ++ __ j(greater_equal, &loop); ++ ++ // Call the function. ++ ParameterCount actual(eax); ++ __ InvokeFunction(edi, edx, actual, CALL_FUNCTION, ++ CheckDebugStepCallWrapper()); ++ ++ // Store offset of return address for deoptimizer. ++ if (create_implicit_receiver && !is_api_function) { ++ masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); ++ } ++ ++ // Restore context from the frame. ++ __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); ++ ++ if (create_implicit_receiver) { ++ // If the result is an object (in the ECMA sense), we should get rid ++ // of the receiver and use the result; see ECMA-262 section 13.2.2-7 ++ // on page 74. ++ Label use_receiver, exit; ++ ++ // If the result is a smi, it is *not* an object in the ECMA sense. ++ __ JumpIfSmi(eax, &use_receiver, Label::kNear); ++ ++ // If the type of the result (stored in its map) is less than ++ // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(above_equal, &exit, Label::kNear); ++ ++ // Throw away the result of the constructor invocation and use the ++ // on-stack receiver as the result. ++ __ bind(&use_receiver); ++ __ mov(eax, Operand(esp, 0)); ++ ++ // Restore the arguments count and leave the construct frame. The ++ // arguments count is stored below the receiver. ++ __ bind(&exit); ++ __ mov(ebx, Operand(esp, 1 * kPointerSize)); ++ } else { ++ __ mov(ebx, Operand(esp, 0)); ++ } ++ ++ // Leave construct frame. ++ } ++ ++ // ES6 9.2.2. Step 13+ ++ // Check that the result is not a Smi, indicating that the constructor result ++ // from a derived class is neither undefined nor an Object. ++ if (check_derived_construct) { ++ Label dont_throw; ++ __ JumpIfNotSmi(eax, &dont_throw); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); ++ } ++ __ bind(&dont_throw); ++ } ++ ++ // Remove caller arguments from the stack and return. ++ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); ++ __ pop(ecx); ++ __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver ++ __ push(ecx); ++ if (create_implicit_receiver) { ++ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); ++ } ++ __ ret(0); ++} ++ ++} // namespace ++ ++void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { ++ Generate_JSConstructStubHelper(masm, false, true, false); ++} ++ ++void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { ++ Generate_JSConstructStubHelper(masm, true, false, false); ++} ++ ++void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { ++ Generate_JSConstructStubHelper(masm, false, false, false); ++} ++ ++void Builtins::Generate_JSBuiltinsConstructStubForDerived( ++ MacroAssembler* masm) { ++ Generate_JSConstructStubHelper(masm, false, false, true); ++} ++ ++void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ push(edi); ++ __ CallRuntime(Runtime::kThrowConstructedNonConstructable); ++} ++ ++enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt }; ++ ++// Clobbers ecx, edx, edi; preserves all other registers. ++static void Generate_CheckStackOverflow(MacroAssembler* masm, ++ IsTagged eax_is_tagged) { ++ // eax : the number of items to be pushed to the stack ++ // ++ // Check the stack for overflow. We are not trying to catch ++ // interruptions (e.g. debug break and preemption) here, so the "real stack ++ // limit" is checked. ++ Label okay; ++ ExternalReference real_stack_limit = ++ ExternalReference::address_of_real_stack_limit(masm->isolate()); ++ __ mov(edi, Operand::StaticVariable(real_stack_limit)); ++ // Make ecx the space we have left. The stack might already be overflowed ++ // here which will cause ecx to become negative. ++ __ mov(ecx, esp); ++ __ sub(ecx, edi); ++ // Make edx the space we need for the array when it is unrolled onto the ++ // stack. ++ __ mov(edx, eax); ++ int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0; ++ __ shl(edx, kPointerSizeLog2 - smi_tag); ++ // Check if the arguments will overflow the stack. ++ __ cmp(ecx, edx); ++ __ j(greater, &okay); // Signed comparison. ++ ++ // Out of stack space. ++ __ CallRuntime(Runtime::kThrowStackOverflow); ++ ++ __ bind(&okay); ++} ++ ++static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ++ bool is_construct) { ++ ProfileEntryHookStub::MaybeCallEntryHook(masm); ++ ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Setup the context (we need to use the caller context from the isolate). ++ ExternalReference context_address(IsolateAddressId::kContextAddress, ++ masm->isolate()); ++ __ mov(esi, Operand::StaticVariable(context_address)); ++ ++ // Load the previous frame pointer (ebx) to access C arguments ++ __ mov(ebx, Operand(ebp, 0)); ++ ++ // Push the function and the receiver onto the stack. ++ __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); ++ __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); ++ ++ // Load the number of arguments and setup pointer to the arguments. ++ __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); ++ __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); ++ ++ // Check if we have enough stack space to push all arguments. ++ // Expects argument count in eax. Clobbers ecx, edx, edi. ++ Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt); ++ ++ // Copy arguments to the stack in a loop. ++ Label loop, entry; ++ __ Move(ecx, Immediate(0)); ++ __ jmp(&entry, Label::kNear); ++ __ bind(&loop); ++ __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv ++ __ push(Operand(edx, 0)); // dereference handle ++ __ inc(ecx); ++ __ bind(&entry); ++ __ cmp(ecx, eax); ++ __ j(not_equal, &loop); ++ ++ // Load the previous frame pointer (ebx) to access C arguments ++ __ mov(ebx, Operand(ebp, 0)); ++ ++ // Get the new.target and function from the frame. ++ __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset)); ++ __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); ++ ++ // Invoke the code. ++ Handle builtin = is_construct ++ ? masm->isolate()->builtins()->Construct() ++ : masm->isolate()->builtins()->Call(); ++ __ Call(builtin, RelocInfo::CODE_TARGET); ++ ++ // Exit the internal frame. Notice that this also removes the empty. ++ // context and the function left on the stack by the code ++ // invocation. ++ } ++ __ ret(kPointerSize); // Remove receiver. ++} ++ ++void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { ++ Generate_JSEntryTrampolineHelper(masm, false); ++} ++ ++void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { ++ Generate_JSEntryTrampolineHelper(masm, true); ++} ++ ++// static ++void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the value to pass to the generator ++ // -- ebx : the JSGeneratorObject to resume ++ // -- edx : the resume mode (tagged) ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ AssertGeneratorObject(ebx); ++ ++ // Store input value into generator object. ++ __ mov(FieldOperand(ebx, JSGeneratorObject::kInputOrDebugPosOffset), eax); ++ __ RecordWriteField(ebx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx, ++ kDontSaveFPRegs); ++ ++ // Store resume mode into generator object. ++ __ mov(FieldOperand(ebx, JSGeneratorObject::kResumeModeOffset), edx); ++ ++ // Load suspended function and context. ++ __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset)); ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ // Flood function if we are stepping. ++ Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; ++ Label stepping_prepared; ++ ExternalReference debug_hook = ++ ExternalReference::debug_hook_on_function_call_address(masm->isolate()); ++ __ cmpb(Operand::StaticVariable(debug_hook), Immediate(0)); ++ __ j(not_equal, &prepare_step_in_if_stepping); ++ ++ // Flood function if we need to continue stepping in the suspended generator. ++ ExternalReference debug_suspended_generator = ++ ExternalReference::debug_suspended_generator_address(masm->isolate()); ++ __ cmp(ebx, Operand::StaticVariable(debug_suspended_generator)); ++ __ j(equal, &prepare_step_in_suspended_generator); ++ __ bind(&stepping_prepared); ++ ++ // Pop return address. ++ __ PopReturnAddressTo(eax); ++ ++ // Push receiver. ++ __ Push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset)); ++ ++ // ----------- S t a t e ------------- ++ // -- eax : return address ++ // -- ebx : the JSGeneratorObject to resume ++ // -- edx : the resume mode (tagged) ++ // -- edi : generator function ++ // -- esi : generator context ++ // -- esp[0] : generator receiver ++ // ----------------------------------- ++ ++ // Push holes for arguments to generator function. Since the parser forced ++ // context allocation for any variables in generators, the actual argument ++ // values have already been copied into the context and these dummy values ++ // will never be used. ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, ++ FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); ++ { ++ Label done_loop, loop; ++ __ bind(&loop); ++ __ sub(ecx, Immediate(1)); ++ __ j(carry, &done_loop, Label::kNear); ++ __ PushRoot(Heap::kTheHoleValueRootIndex); ++ __ jmp(&loop); ++ __ bind(&done_loop); ++ } ++ ++ // Underlying function needs to have bytecode available. ++ if (FLAG_debug_code) { ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kFunctionDataOffset)); ++ __ CmpObjectType(ecx, BYTECODE_ARRAY_TYPE, ecx); ++ __ Assert(equal, kMissingBytecodeArray); ++ } ++ ++ // Resume (Ignition/TurboFan) generator object. ++ { ++ __ PushReturnAddressFrom(eax); ++ __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(eax, ++ FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); ++ // We abuse new.target both to indicate that this is a resume call and to ++ // pass in the generator object. In ordinary calls, new.target is always ++ // undefined because generator functions are non-constructable. ++ __ mov(edx, ebx); ++ __ jmp(FieldOperand(edi, JSFunction::kCodeEntryOffset)); ++ } ++ ++ __ bind(&prepare_step_in_if_stepping); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(ebx); ++ __ Push(edx); ++ __ Push(edi); ++ __ CallRuntime(Runtime::kDebugOnFunctionCall); ++ __ Pop(edx); ++ __ Pop(ebx); ++ __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset)); ++ } ++ __ jmp(&stepping_prepared); ++ ++ __ bind(&prepare_step_in_suspended_generator); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(ebx); ++ __ Push(edx); ++ __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator); ++ __ Pop(edx); ++ __ Pop(ebx); ++ __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset)); ++ } ++ __ jmp(&stepping_prepared); ++} ++ ++static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1, ++ Register scratch2) { ++ Register args_count = scratch1; ++ Register return_pc = scratch2; ++ ++ // Get the arguments + reciever count. ++ __ mov(args_count, ++ Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); ++ __ mov(args_count, ++ FieldOperand(args_count, BytecodeArray::kParameterSizeOffset)); ++ ++ // Leave the frame (also dropping the register file). ++ __ leave(); ++ ++ // Drop receiver + arguments. ++ __ pop(return_pc); ++ __ add(esp, args_count); ++ __ push(return_pc); ++} ++ ++// Generate code for entering a JS function with the interpreter. ++// On entry to the function the receiver and arguments have been pushed on the ++// stack left to right. The actual argument count matches the formal parameter ++// count expected by the function. ++// ++// The live registers are: ++// o edi: the JS function object being called ++// o edx: the new target ++// o esi: our context ++// o ebp: the caller's frame pointer ++// o esp: stack pointer (pointing to return address) ++// ++// The function builds an interpreter frame. See InterpreterFrameConstants in ++// frames.h for its layout. ++void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { ++ ProfileEntryHookStub::MaybeCallEntryHook(masm); ++ ++ // Open a frame scope to indicate that there is a frame on the stack. The ++ // MANUAL indicates that the scope shouldn't actually generate code to set up ++ // the frame (that is done below). ++ FrameScope frame_scope(masm, StackFrame::MANUAL); ++ __ push(ebp); // Caller's frame pointer. ++ __ mov(ebp, esp); ++ __ push(esi); // Callee's context. ++ __ push(edi); // Callee's JS function. ++ __ push(edx); // Callee's new target. ++ ++ // Get the bytecode array from the function object (or from the DebugInfo if ++ // it is present) and load it into kInterpreterBytecodeArrayRegister. ++ __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ Label load_debug_bytecode_array, bytecode_array_loaded; ++ __ JumpIfNotSmi(FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset), ++ &load_debug_bytecode_array); ++ __ mov(kInterpreterBytecodeArrayRegister, ++ FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset)); ++ __ bind(&bytecode_array_loaded); ++ ++ // Check whether we should continue to use the interpreter. ++ // TODO(rmcilroy) Remove self healing once liveedit only has to deal with ++ // Ignition bytecode. ++ Label switch_to_different_code_kind; ++ __ Move(ecx, masm->CodeObject()); // Self-reference to this code. ++ __ cmp(ecx, FieldOperand(eax, SharedFunctionInfo::kCodeOffset)); ++ __ j(not_equal, &switch_to_different_code_kind); ++ ++ // Increment invocation count for the function. ++ __ EmitLoadFeedbackVector(ecx); ++ __ add( ++ FieldOperand(ecx, FeedbackVector::kInvocationCountIndex * kPointerSize + ++ FeedbackVector::kHeaderSize), ++ Immediate(Smi::FromInt(1))); ++ ++ // Check function data field is actually a BytecodeArray object. ++ if (FLAG_debug_code) { ++ __ AssertNotSmi(kInterpreterBytecodeArrayRegister); ++ __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, ++ eax); ++ __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); ++ } ++ ++ // Reset code age. ++ __ mov_b(FieldOperand(kInterpreterBytecodeArrayRegister, ++ BytecodeArray::kBytecodeAgeOffset), ++ Immediate(BytecodeArray::kNoAgeBytecodeAge)); ++ ++ // Push bytecode array. ++ __ push(kInterpreterBytecodeArrayRegister); ++ // Push Smi tagged initial bytecode array offset. ++ __ push(Immediate(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag))); ++ ++ // Allocate the local and temporary register file on the stack. ++ { ++ // Load frame size from the BytecodeArray object. ++ __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister, ++ BytecodeArray::kFrameSizeOffset)); ++ ++ // Do a stack check to ensure we don't go over the limit. ++ Label ok; ++ __ mov(ecx, esp); ++ __ sub(ecx, ebx); ++ ExternalReference stack_limit = ++ ExternalReference::address_of_real_stack_limit(masm->isolate()); ++ __ cmp(ecx, Operand::StaticVariable(stack_limit)); ++ __ j(above_equal, &ok); ++ __ CallRuntime(Runtime::kThrowStackOverflow); ++ __ bind(&ok); ++ ++ // If ok, push undefined as the initial value for all register file entries. ++ Label loop_header; ++ Label loop_check; ++ __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value())); ++ __ jmp(&loop_check); ++ __ bind(&loop_header); ++ // TODO(rmcilroy): Consider doing more than one push per loop iteration. ++ __ push(eax); ++ // Continue loop if not done. ++ __ bind(&loop_check); ++ __ sub(ebx, Immediate(kPointerSize)); ++ __ j(greater_equal, &loop_header); ++ } ++ ++ // Load accumulator, bytecode offset and dispatch table into registers. ++ __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex); ++ __ mov(kInterpreterBytecodeOffsetRegister, ++ Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag)); ++ __ mov(kInterpreterDispatchTableRegister, ++ Immediate(ExternalReference::interpreter_dispatch_table_address( ++ masm->isolate()))); ++ ++ // Dispatch to the first bytecode handler for the function. ++ __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, ++ kInterpreterBytecodeOffsetRegister, times_1, 0)); ++ __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx, ++ times_pointer_size, 0)); ++ __ call(ebx); ++ masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset()); ++ ++ // The return value is in eax. ++ LeaveInterpreterFrame(masm, ebx, ecx); ++ __ ret(0); ++ ++ // Load debug copy of the bytecode array. ++ __ bind(&load_debug_bytecode_array); ++ Register debug_info = kInterpreterBytecodeArrayRegister; ++ __ mov(debug_info, FieldOperand(eax, SharedFunctionInfo::kDebugInfoOffset)); ++ __ mov(kInterpreterBytecodeArrayRegister, ++ FieldOperand(debug_info, DebugInfo::kDebugBytecodeArrayOffset)); ++ __ jmp(&bytecode_array_loaded); ++ ++ // If the shared code is no longer this entry trampoline, then the underlying ++ // function has been switched to a different kind of code and we heal the ++ // closure by switching the code entry field over to the new code as well. ++ __ bind(&switch_to_different_code_kind); ++ __ pop(edx); // Callee's new target. ++ __ pop(edi); // Callee's JS function. ++ __ pop(esi); // Callee's context. ++ __ leave(); // Leave the frame so we can tail call. ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kCodeOffset)); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ mov(FieldOperand(edi, JSFunction::kCodeEntryOffset), ecx); ++ __ RecordWriteCodeEntryField(edi, ecx, ebx); ++ __ jmp(ecx); ++} ++ ++static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, ++ Register scratch1, Register scratch2, ++ Label* stack_overflow, ++ bool include_receiver = false) { ++ // Check the stack for overflow. We are not trying to catch ++ // interruptions (e.g. debug break and preemption) here, so the "real stack ++ // limit" is checked. ++ ExternalReference real_stack_limit = ++ ExternalReference::address_of_real_stack_limit(masm->isolate()); ++ __ mov(scratch1, Operand::StaticVariable(real_stack_limit)); ++ // Make scratch2 the space we have left. The stack might already be overflowed ++ // here which will cause scratch2 to become negative. ++ __ mov(scratch2, esp); ++ __ sub(scratch2, scratch1); ++ // Make scratch1 the space we need for the array when it is unrolled onto the ++ // stack. ++ __ mov(scratch1, num_args); ++ if (include_receiver) { ++ __ add(scratch1, Immediate(1)); ++ } ++ __ shl(scratch1, kPointerSizeLog2); ++ // Check if the arguments will overflow the stack. ++ __ cmp(scratch2, scratch1); ++ __ j(less_equal, stack_overflow); // Signed comparison. ++} ++ ++static void Generate_InterpreterPushArgs(MacroAssembler* masm, ++ Register array_limit, ++ Register start_address) { ++ // ----------- S t a t e ------------- ++ // -- start_address : Pointer to the last argument in the args array. ++ // -- array_limit : Pointer to one before the first argument in the ++ // args array. ++ // ----------------------------------- ++ Label loop_header, loop_check; ++ __ jmp(&loop_check); ++ __ bind(&loop_header); ++ __ Push(Operand(start_address, 0)); ++ __ sub(start_address, Immediate(kPointerSize)); ++ __ bind(&loop_check); ++ __ cmp(start_address, array_limit); ++ __ j(greater, &loop_header, Label::kNear); ++} ++ ++// static ++void Builtins::Generate_InterpreterPushArgsThenCallImpl( ++ MacroAssembler* masm, TailCallMode tail_call_mode, ++ InterpreterPushArgsMode mode) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- ebx : the address of the first argument to be pushed. Subsequent ++ // arguments should be consecutive above this, in the same order as ++ // they are to be pushed onto the stack. ++ // -- edi : the target to call (can be any Object). ++ // ----------------------------------- ++ Label stack_overflow; ++ // Compute the expected number of arguments. ++ __ mov(ecx, eax); ++ __ add(ecx, Immediate(1)); // Add one for receiver. ++ ++ // Add a stack check before pushing the arguments. We need an extra register ++ // to perform a stack check. So push it onto the stack temporarily. This ++ // might cause stack overflow, but it will be detected by the check. ++ __ Push(edi); ++ Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow); ++ __ Pop(edi); ++ ++ // Pop return address to allow tail-call after pushing arguments. ++ __ Pop(edx); ++ ++ // Find the address of the last argument. ++ __ shl(ecx, kPointerSizeLog2); ++ __ neg(ecx); ++ __ add(ecx, ebx); ++ Generate_InterpreterPushArgs(masm, ecx, ebx); ++ ++ // Call the target. ++ __ Push(edx); // Re-push return address. ++ ++ if (mode == InterpreterPushArgsMode::kJSFunction) { ++ __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, ++ tail_call_mode), ++ RelocInfo::CODE_TARGET); ++ } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) { ++ __ Jump(masm->isolate()->builtins()->CallWithSpread(), ++ RelocInfo::CODE_TARGET); ++ } else { ++ __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, ++ tail_call_mode), ++ RelocInfo::CODE_TARGET); ++ } ++ ++ __ bind(&stack_overflow); ++ { ++ // Pop the temporary registers, so that return address is on top of stack. ++ __ Pop(edi); ++ ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ ++ // This should be unreachable. ++ __ int3(); ++ } ++} ++ ++namespace { ++ ++// This function modified start_addr, and only reads the contents of num_args ++// register. scratch1 and scratch2 are used as temporary registers. Their ++// original values are restored after the use. ++void Generate_InterpreterPushArgsThenReturnAddress( ++ MacroAssembler* masm, Register num_args, Register start_addr, ++ Register scratch1, Register scratch2, bool receiver_in_args, ++ int num_slots_above_ret_addr, Label* stack_overflow) { ++ // We have to move return address and the temporary registers above it ++ // before we can copy arguments onto the stack. To achieve this: ++ // Step 1: Increment the stack pointer by num_args + 1 (for receiver). ++ // Step 2: Move the return address and values above it to the top of stack. ++ // Step 3: Copy the arguments into the correct locations. ++ // current stack =====> required stack layout ++ // | | | scratch1 | (2) <-- esp(1) ++ // | | | .... | (2) ++ // | | | scratch-n | (2) ++ // | | | return addr | (2) ++ // | | | arg N | (3) ++ // | scratch1 | <-- esp | .... | ++ // | .... | | arg 0 | ++ // | scratch-n | | arg 0 | ++ // | return addr | | receiver slot | ++ ++ // Check for stack overflow before we increment the stack pointer. ++ Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2, ++ stack_overflow, true); ++ ++// Step 1 - Update the stack pointer. scratch1 already contains the required ++// increment to the stack. i.e. num_args + 1 stack slots. This is computed in ++// the Generate_StackOverflowCheck. ++ ++#ifdef _MSC_VER ++ // TODO(mythria): Move it to macro assembler. ++ // In windows, we cannot increment the stack size by more than one page ++ // (mimimum page size is 4KB) without accessing at least one byte on the ++ // page. Check this: ++ // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. ++ const int page_size = 4 * 1024; ++ Label check_offset, update_stack_pointer; ++ __ bind(&check_offset); ++ __ cmp(scratch1, page_size); ++ __ j(less, &update_stack_pointer); ++ __ sub(esp, Immediate(page_size)); ++ // Just to touch the page, before we increment further. ++ __ mov(Operand(esp, 0), Immediate(0)); ++ __ sub(scratch1, Immediate(page_size)); ++ __ jmp(&check_offset); ++ __ bind(&update_stack_pointer); ++#endif ++ ++ __ sub(esp, scratch1); ++ ++ // Step 2 move return_address and slots above it to the correct locations. ++ // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1, ++ // basically when the source and destination overlap. We at least need one ++ // extra slot for receiver, so no extra checks are required to avoid copy. ++ for (int i = 0; i < num_slots_above_ret_addr + 1; i++) { ++ __ mov(scratch1, ++ Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize)); ++ __ mov(Operand(esp, i * kPointerSize), scratch1); ++ } ++ ++ // Step 3 copy arguments to correct locations. ++ if (receiver_in_args) { ++ __ mov(scratch1, num_args); ++ __ add(scratch1, Immediate(1)); ++ } else { ++ // Slot meant for receiver contains return address. Reset it so that ++ // we will not incorrectly interpret return address as an object. ++ __ mov(Operand(esp, num_args, times_pointer_size, ++ (num_slots_above_ret_addr + 1) * kPointerSize), ++ Immediate(0)); ++ __ mov(scratch1, num_args); ++ } ++ ++ Label loop_header, loop_check; ++ __ jmp(&loop_check); ++ __ bind(&loop_header); ++ __ mov(scratch2, Operand(start_addr, 0)); ++ __ mov(Operand(esp, scratch1, times_pointer_size, ++ num_slots_above_ret_addr * kPointerSize), ++ scratch2); ++ __ sub(start_addr, Immediate(kPointerSize)); ++ __ sub(scratch1, Immediate(1)); ++ __ bind(&loop_check); ++ __ cmp(scratch1, Immediate(0)); ++ __ j(greater, &loop_header, Label::kNear); ++} ++ ++} // end anonymous namespace ++ ++// static ++void Builtins::Generate_InterpreterPushArgsThenConstructImpl( ++ MacroAssembler* masm, InterpreterPushArgsMode mode) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the new target ++ // -- edi : the constructor ++ // -- ebx : allocation site feedback (if available or undefined) ++ // -- ecx : the address of the first argument to be pushed. Subsequent ++ // arguments should be consecutive above this, in the same order as ++ // they are to be pushed onto the stack. ++ // ----------------------------------- ++ Label stack_overflow; ++ // We need two scratch registers. Push edi and edx onto stack. ++ __ Push(edi); ++ __ Push(edx); ++ ++ // Push arguments and move return address to the top of stack. ++ // The eax register is readonly. The ecx register will be modified. The edx ++ // and edi registers will be modified but restored to their original values. ++ Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, false, ++ 2, &stack_overflow); ++ ++ // Restore edi and edx ++ __ Pop(edx); ++ __ Pop(edi); ++ ++ __ AssertUndefinedOrAllocationSite(ebx); ++ if (mode == InterpreterPushArgsMode::kJSFunction) { ++ // Tail call to the function-specific construct stub (still in the caller ++ // context at this point). ++ __ AssertFunction(edi); ++ ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++ } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) { ++ // Call the constructor with unmodified eax, edi, edx values. ++ __ Jump(masm->isolate()->builtins()->ConstructWithSpread(), ++ RelocInfo::CODE_TARGET); ++ } else { ++ DCHECK_EQ(InterpreterPushArgsMode::kOther, mode); ++ // Call the constructor with unmodified eax, edi, edx values. ++ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); ++ } ++ ++ __ bind(&stack_overflow); ++ { ++ // Pop the temporary registers, so that return address is on top of stack. ++ __ Pop(edx); ++ __ Pop(edi); ++ ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ ++ // This should be unreachable. ++ __ int3(); ++ } ++} ++ ++// static ++void Builtins::Generate_InterpreterPushArgsThenConstructArray( ++ MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the target to call checked to be Array function. ++ // -- ebx : the allocation site feedback ++ // -- ecx : the address of the first argument to be pushed. Subsequent ++ // arguments should be consecutive above this, in the same order as ++ // they are to be pushed onto the stack. ++ // ----------------------------------- ++ Label stack_overflow; ++ // We need two scratch registers. Register edi is available, push edx onto ++ // stack. ++ __ Push(edx); ++ ++ // Push arguments and move return address to the top of stack. ++ // The eax register is readonly. The ecx register will be modified. The edx ++ // and edi registers will be modified but restored to their original values. ++ Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, true, ++ 1, &stack_overflow); ++ ++ // Restore edx. ++ __ Pop(edx); ++ ++ // Array constructor expects constructor in edi. It is same as edx here. ++ __ Move(edi, edx); ++ ++ ArrayConstructorStub stub(masm->isolate()); ++ __ TailCallStub(&stub); ++ ++ __ bind(&stack_overflow); ++ { ++ // Pop the temporary registers, so that return address is on top of stack. ++ __ Pop(edx); ++ ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ ++ // This should be unreachable. ++ __ int3(); ++ } ++} ++ ++static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { ++ // Set the return address to the correct point in the interpreter entry ++ // trampoline. ++ Smi* interpreter_entry_return_pc_offset( ++ masm->isolate()->heap()->interpreter_entry_return_pc_offset()); ++ DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero); ++ __ LoadHeapObject(ebx, ++ masm->isolate()->builtins()->InterpreterEntryTrampoline()); ++ __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() + ++ Code::kHeaderSize - kHeapObjectTag)); ++ __ push(ebx); ++ ++ // Initialize the dispatch table register. ++ __ mov(kInterpreterDispatchTableRegister, ++ Immediate(ExternalReference::interpreter_dispatch_table_address( ++ masm->isolate()))); ++ ++ // Get the bytecode array pointer from the frame. ++ __ mov(kInterpreterBytecodeArrayRegister, ++ Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); ++ ++ if (FLAG_debug_code) { ++ // Check function data field is actually a BytecodeArray object. ++ __ AssertNotSmi(kInterpreterBytecodeArrayRegister); ++ __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, ++ ebx); ++ __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); ++ } ++ ++ // Get the target bytecode offset from the frame. ++ __ mov(kInterpreterBytecodeOffsetRegister, ++ Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); ++ __ SmiUntag(kInterpreterBytecodeOffsetRegister); ++ ++ // Dispatch to the target bytecode. ++ __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, ++ kInterpreterBytecodeOffsetRegister, times_1, 0)); ++ __ mov(ebx, Operand(kInterpreterDispatchTableRegister, ebx, ++ times_pointer_size, 0)); ++ __ jmp(ebx); ++} ++ ++void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { ++ // Advance the current bytecode offset stored within the given interpreter ++ // stack frame. This simulates what all bytecode handlers do upon completion ++ // of the underlying operation. ++ __ mov(ebx, Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); ++ __ mov(edx, Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); ++ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(kInterpreterAccumulatorRegister); ++ __ Push(ebx); // First argument is the bytecode array. ++ __ Push(edx); // Second argument is the bytecode offset. ++ __ CallRuntime(Runtime::kInterpreterAdvanceBytecodeOffset); ++ __ Move(edx, eax); // Result is the new bytecode offset. ++ __ Pop(kInterpreterAccumulatorRegister); ++ } ++ __ mov(Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp), edx); ++ ++ Generate_InterpreterEnterBytecode(masm); ++} ++ ++void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { ++ Generate_InterpreterEnterBytecode(masm); ++} ++ ++void Builtins::Generate_CompileLazy(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argument count (preserved for callee) ++ // -- edx : new target (preserved for callee) ++ // -- edi : target function (preserved for callee) ++ // ----------------------------------- ++ // First lookup code, maybe we don't need to compile! ++ Label gotta_call_runtime, gotta_call_runtime_no_stack; ++ Label try_shared; ++ Label loop_top, loop_bottom; ++ ++ Register closure = edi; ++ Register new_target = edx; ++ Register argument_count = eax; ++ ++ // Do we have a valid feedback vector? ++ __ mov(ebx, FieldOperand(closure, JSFunction::kFeedbackVectorOffset)); ++ __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset)); ++ __ cmp(ebx, masm->isolate()->factory()->undefined_value()); ++ __ j(equal, &gotta_call_runtime_no_stack); ++ ++ __ push(argument_count); ++ __ push(new_target); ++ __ push(closure); ++ ++ Register map = argument_count; ++ Register index = ebx; ++ __ mov(map, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(map, FieldOperand(map, SharedFunctionInfo::kOptimizedCodeMapOffset)); ++ __ mov(index, FieldOperand(map, FixedArray::kLengthOffset)); ++ __ cmp(index, Immediate(Smi::FromInt(2))); ++ __ j(less, &try_shared); ++ ++ // edx : native context ++ // ebx : length / index ++ // eax : optimized code map ++ // stack[0] : new target ++ // stack[4] : closure ++ Register native_context = edx; ++ __ mov(native_context, NativeContextOperand()); ++ ++ __ bind(&loop_top); ++ Register temp = edi; ++ ++ // Does the native context match? ++ __ mov(temp, FieldOperand(map, index, times_half_pointer_size, ++ SharedFunctionInfo::kOffsetToPreviousContext)); ++ __ mov(temp, FieldOperand(temp, WeakCell::kValueOffset)); ++ __ cmp(temp, native_context); ++ __ j(not_equal, &loop_bottom); ++ // Code available? ++ Register entry = ecx; ++ __ mov(entry, FieldOperand(map, index, times_half_pointer_size, ++ SharedFunctionInfo::kOffsetToPreviousCachedCode)); ++ __ mov(entry, FieldOperand(entry, WeakCell::kValueOffset)); ++ __ JumpIfSmi(entry, &try_shared); ++ ++ // Found code. Get it into the closure and return. ++ __ pop(closure); ++ // Store code entry in the closure. ++ __ lea(entry, FieldOperand(entry, Code::kHeaderSize)); ++ __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry); ++ __ RecordWriteCodeEntryField(closure, entry, eax); ++ ++ // Link the closure into the optimized function list. ++ // ecx : code entry ++ // edx : native context ++ // edi : closure ++ __ mov(ebx, ++ ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST)); ++ __ mov(FieldOperand(closure, JSFunction::kNextFunctionLinkOffset), ebx); ++ __ RecordWriteField(closure, JSFunction::kNextFunctionLinkOffset, ebx, eax, ++ kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); ++ const int function_list_offset = ++ Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST); ++ __ mov(ContextOperand(native_context, Context::OPTIMIZED_FUNCTIONS_LIST), ++ closure); ++ // Save closure before the write barrier. ++ __ mov(ebx, closure); ++ __ RecordWriteContextSlot(native_context, function_list_offset, closure, eax, ++ kDontSaveFPRegs); ++ __ mov(closure, ebx); ++ __ pop(new_target); ++ __ pop(argument_count); ++ __ jmp(entry); ++ ++ __ bind(&loop_bottom); ++ __ sub(index, Immediate(Smi::FromInt(SharedFunctionInfo::kEntryLength))); ++ __ cmp(index, Immediate(Smi::FromInt(1))); ++ __ j(greater, &loop_top); ++ ++ // We found no code. ++ __ jmp(&gotta_call_runtime); ++ ++ __ bind(&try_shared); ++ __ pop(closure); ++ __ pop(new_target); ++ __ pop(argument_count); ++ __ mov(entry, FieldOperand(closure, JSFunction::kSharedFunctionInfoOffset)); ++ // Is the shared function marked for tier up? ++ __ test(FieldOperand(entry, SharedFunctionInfo::kCompilerHintsOffset), ++ Immediate(SharedFunctionInfo::MarkedForTierUpBit::kMask)); ++ __ j(not_zero, &gotta_call_runtime_no_stack); ++ ++ // If SFI points to anything other than CompileLazy, install that. ++ __ mov(entry, FieldOperand(entry, SharedFunctionInfo::kCodeOffset)); ++ __ Move(ebx, masm->CodeObject()); ++ __ cmp(entry, ebx); ++ __ j(equal, &gotta_call_runtime_no_stack); ++ ++ // Install the SFI's code entry. ++ __ lea(entry, FieldOperand(entry, Code::kHeaderSize)); ++ __ mov(FieldOperand(closure, JSFunction::kCodeEntryOffset), entry); ++ __ RecordWriteCodeEntryField(closure, entry, ebx); ++ __ jmp(entry); ++ ++ __ bind(&gotta_call_runtime); ++ __ pop(closure); ++ __ pop(new_target); ++ __ pop(argument_count); ++ __ bind(&gotta_call_runtime_no_stack); ++ ++ GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy); ++} ++ ++void Builtins::Generate_CompileOptimized(MacroAssembler* masm) { ++ GenerateTailCallToReturnedCode(masm, ++ Runtime::kCompileOptimized_NotConcurrent); ++} ++ ++void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) { ++ GenerateTailCallToReturnedCode(masm, Runtime::kCompileOptimized_Concurrent); ++} ++ ++void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argument count (preserved for callee) ++ // -- edx : new target (preserved for callee) ++ // -- edi : target function (preserved for callee) ++ // ----------------------------------- ++ Label failed; ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // Preserve argument count for later compare. ++ __ mov(ecx, eax); ++ // Push the number of arguments to the callee. ++ __ SmiTag(eax); ++ __ push(eax); ++ // Push a copy of the target function and the new target. ++ __ push(edi); ++ __ push(edx); ++ ++ // The function. ++ __ push(edi); ++ // Copy arguments from caller (stdlib, foreign, heap). ++ Label args_done; ++ for (int j = 0; j < 4; ++j) { ++ Label over; ++ if (j < 3) { ++ __ cmp(ecx, Immediate(j)); ++ __ j(not_equal, &over, Label::kNear); ++ } ++ for (int i = j - 1; i >= 0; --i) { ++ __ Push(Operand( ++ ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize)); ++ } ++ for (int i = 0; i < 3 - j; ++i) { ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ } ++ if (j < 3) { ++ __ jmp(&args_done, Label::kNear); ++ __ bind(&over); ++ } ++ } ++ __ bind(&args_done); ++ ++ // Call runtime, on success unwind frame, and parent frame. ++ __ CallRuntime(Runtime::kInstantiateAsmJs, 4); ++ // A smi 0 is returned on failure, an object on success. ++ __ JumpIfSmi(eax, &failed, Label::kNear); ++ ++ __ Drop(2); ++ __ Pop(ecx); ++ __ SmiUntag(ecx); ++ scope.GenerateLeaveFrame(); ++ ++ __ PopReturnAddressTo(ebx); ++ __ inc(ecx); ++ __ lea(esp, Operand(esp, ecx, times_pointer_size, 0)); ++ __ PushReturnAddressFrom(ebx); ++ __ ret(0); ++ ++ __ bind(&failed); ++ // Restore target function and new target. ++ __ pop(edx); ++ __ pop(edi); ++ __ pop(eax); ++ __ SmiUntag(eax); ++ } ++ // On failure, tail call back to regular js. ++ GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy); ++} ++ ++static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { ++ // For now, we are relying on the fact that make_code_young doesn't do any ++ // garbage collection which allows us to save/restore the registers without ++ // worrying about which of them contain pointers. We also don't build an ++ // internal frame to make the code faster, since we shouldn't have to do stack ++ // crawls in MakeCodeYoung. This seems a bit fragile. ++ ++ // Re-execute the code that was patched back to the young age when ++ // the stub returns. ++ __ sub(Operand(esp, 0), Immediate(5)); ++ __ pushad(); ++ __ mov(eax, Operand(esp, 8 * kPointerSize)); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ PrepareCallCFunction(2, ebx); ++ __ mov(Operand(esp, 1 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(masm->isolate()))); ++ __ mov(Operand(esp, 0), eax); ++ __ CallCFunction( ++ ExternalReference::get_make_code_young_function(masm->isolate()), 2); ++ } ++ __ popad(); ++ __ ret(0); ++} ++ ++#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ ++ void Builtins::Generate_Make##C##CodeYoungAgain(MacroAssembler* masm) { \ ++ GenerateMakeCodeYoungAgainCommon(masm); \ ++ } ++CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) ++#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR ++ ++void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) { ++ // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact ++ // that make_code_young doesn't do any garbage collection which allows us to ++ // save/restore the registers without worrying about which of them contain ++ // pointers. ++ __ pushad(); ++ __ mov(eax, Operand(esp, 8 * kPointerSize)); ++ __ sub(eax, Immediate(Assembler::kCallInstructionLength)); ++ { // NOLINT ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ PrepareCallCFunction(2, ebx); ++ __ mov(Operand(esp, 1 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(masm->isolate()))); ++ __ mov(Operand(esp, 0), eax); ++ __ CallCFunction( ++ ExternalReference::get_mark_code_as_executed_function(masm->isolate()), ++ 2); ++ } ++ __ popad(); ++ ++ // Perform prologue operations usually performed by the young code stub. ++ __ pop(eax); // Pop return address into scratch register. ++ __ push(ebp); // Caller's frame pointer. ++ __ mov(ebp, esp); ++ __ push(esi); // Callee's context. ++ __ push(edi); // Callee's JS Function. ++ __ push(eax); // Push return address after frame prologue. ++ ++ // Jump to point after the code-age stub. ++ __ ret(0); ++} ++ ++void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) { ++ GenerateMakeCodeYoungAgainCommon(masm); ++} ++ ++void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) { ++ Generate_MarkCodeAsExecutedOnce(masm); ++} ++ ++static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, ++ Deoptimizer::BailoutType type) { ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Pass deoptimization type to the runtime system. ++ __ push(Immediate(Smi::FromInt(static_cast(type)))); ++ __ CallRuntime(Runtime::kNotifyDeoptimized); ++ ++ // Tear down internal frame. ++ } ++ ++ // Get the full codegen state from the stack and untag it. ++ __ mov(ecx, Operand(esp, 1 * kPointerSize)); ++ __ SmiUntag(ecx); ++ ++ // Switch on the state. ++ Label not_no_registers, not_tos_eax; ++ __ cmp(ecx, static_cast(Deoptimizer::BailoutState::NO_REGISTERS)); ++ __ j(not_equal, ¬_no_registers, Label::kNear); ++ __ ret(1 * kPointerSize); // Remove state. ++ ++ __ bind(¬_no_registers); ++ DCHECK_EQ(kInterpreterAccumulatorRegister.code(), eax.code()); ++ __ mov(eax, Operand(esp, 2 * kPointerSize)); ++ __ cmp(ecx, static_cast(Deoptimizer::BailoutState::TOS_REGISTER)); ++ __ j(not_equal, ¬_tos_eax, Label::kNear); ++ __ ret(2 * kPointerSize); // Remove state, eax. ++ ++ __ bind(¬_tos_eax); ++ __ Abort(kNoCasesLeft); ++} ++ ++void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { ++ Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); ++} ++ ++void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) { ++ Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); ++} ++ ++void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { ++ Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); ++} ++ ++// static ++void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- esp[0] : return address ++ // -- esp[4] : argArray ++ // -- esp[8] : thisArg ++ // -- esp[12] : receiver ++ // ----------------------------------- ++ ++ // 1. Load receiver into edi, argArray into eax (if present), remove all ++ // arguments from the stack (including the receiver), and push thisArg (if ++ // present) instead. ++ { ++ Label no_arg_array, no_this_arg; ++ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); ++ __ mov(ebx, edx); ++ __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ __ test(eax, eax); ++ __ j(zero, &no_this_arg, Label::kNear); ++ { ++ __ mov(edx, Operand(esp, eax, times_pointer_size, 0)); ++ __ cmp(eax, Immediate(1)); ++ __ j(equal, &no_arg_array, Label::kNear); ++ __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize)); ++ __ bind(&no_arg_array); ++ } ++ __ bind(&no_this_arg); ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(eax, ebx); ++ } ++ ++ // ----------- S t a t e ------------- ++ // -- eax : argArray ++ // -- edi : receiver ++ // -- esp[0] : return address ++ // -- esp[4] : thisArg ++ // ----------------------------------- ++ ++ // 2. Make sure the receiver is actually callable. ++ Label receiver_not_callable; ++ __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear); ++ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsCallable)); ++ __ j(zero, &receiver_not_callable, Label::kNear); ++ ++ // 3. Tail call with no arguments if argArray is null or undefined. ++ Label no_arguments; ++ __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); ++ __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments, ++ Label::kNear); ++ ++ // 4a. Apply the receiver to the given argArray (passing undefined for ++ // new.target). ++ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); ++ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); ++ ++ // 4b. The argArray is either null or undefined, so we tail call without any ++ // arguments to the receiver. ++ __ bind(&no_arguments); ++ { ++ __ Set(eax, 0); ++ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); ++ } ++ ++ // 4c. The receiver is not callable, throw an appropriate TypeError. ++ __ bind(&receiver_not_callable); ++ { ++ __ mov(Operand(esp, kPointerSize), edi); ++ __ TailCallRuntime(Runtime::kThrowApplyNonFunction); ++ } ++} ++ ++// static ++void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { ++ // Stack Layout: ++ // esp[0] : Return address ++ // esp[8] : Argument n ++ // esp[16] : Argument n-1 ++ // ... ++ // esp[8 * n] : Argument 1 ++ // esp[8 * (n + 1)] : Receiver (callable to call) ++ // ++ // eax contains the number of arguments, n, not counting the receiver. ++ // ++ // 1. Make sure we have at least one argument. ++ { ++ Label done; ++ __ test(eax, eax); ++ __ j(not_zero, &done, Label::kNear); ++ __ PopReturnAddressTo(ebx); ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ __ PushReturnAddressFrom(ebx); ++ __ inc(eax); ++ __ bind(&done); ++ } ++ ++ // 2. Get the callable to call (passed as receiver) from the stack. ++ __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ ++ // 3. Shift arguments and return address one slot down on the stack ++ // (overwriting the original receiver). Adjust argument count to make ++ // the original first argument the new receiver. ++ { ++ Label loop; ++ __ mov(ecx, eax); ++ __ bind(&loop); ++ __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0)); ++ __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx); ++ __ dec(ecx); ++ __ j(not_sign, &loop); // While non-negative (to copy return address). ++ __ pop(ebx); // Discard copy of return address. ++ __ dec(eax); // One fewer argument (first argument is new receiver). ++ } ++ ++ // 4. Call the callable. ++ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); ++} ++ ++void Builtins::Generate_ReflectApply(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- esp[0] : return address ++ // -- esp[4] : argumentsList ++ // -- esp[8] : thisArgument ++ // -- esp[12] : target ++ // -- esp[16] : receiver ++ // ----------------------------------- ++ ++ // 1. Load target into edi (if present), argumentsList into eax (if present), ++ // remove all arguments from the stack (including the receiver), and push ++ // thisArgument (if present) instead. ++ { ++ Label done; ++ __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); ++ __ mov(edx, edi); ++ __ mov(ebx, edi); ++ __ cmp(eax, Immediate(1)); ++ __ j(below, &done, Label::kNear); ++ __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); ++ __ j(equal, &done, Label::kNear); ++ __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); ++ __ cmp(eax, Immediate(3)); ++ __ j(below, &done, Label::kNear); ++ __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); ++ __ bind(&done); ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(eax, ebx); ++ } ++ ++ // ----------- S t a t e ------------- ++ // -- eax : argumentsList ++ // -- edi : target ++ // -- esp[0] : return address ++ // -- esp[4] : thisArgument ++ // ----------------------------------- ++ ++ // 2. Make sure the target is actually callable. ++ Label target_not_callable; ++ __ JumpIfSmi(edi, &target_not_callable, Label::kNear); ++ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsCallable)); ++ __ j(zero, &target_not_callable, Label::kNear); ++ ++ // 3a. Apply the target to the given argumentsList (passing undefined for ++ // new.target). ++ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); ++ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); ++ ++ // 3b. The target is not callable, throw an appropriate TypeError. ++ __ bind(&target_not_callable); ++ { ++ __ mov(Operand(esp, kPointerSize), edi); ++ __ TailCallRuntime(Runtime::kThrowApplyNonFunction); ++ } ++} ++ ++void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- esp[0] : return address ++ // -- esp[4] : new.target (optional) ++ // -- esp[8] : argumentsList ++ // -- esp[12] : target ++ // -- esp[16] : receiver ++ // ----------------------------------- ++ ++ // 1. Load target into edi (if present), argumentsList into eax (if present), ++ // new.target into edx (if present, otherwise use target), remove all ++ // arguments from the stack (including the receiver), and push thisArgument ++ // (if present) instead. ++ { ++ Label done; ++ __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); ++ __ mov(edx, edi); ++ __ mov(ebx, edi); ++ __ cmp(eax, Immediate(1)); ++ __ j(below, &done, Label::kNear); ++ __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); ++ __ mov(edx, edi); ++ __ j(equal, &done, Label::kNear); ++ __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); ++ __ cmp(eax, Immediate(3)); ++ __ j(below, &done, Label::kNear); ++ __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); ++ __ bind(&done); ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(eax, ebx); ++ } ++ ++ // ----------- S t a t e ------------- ++ // -- eax : argumentsList ++ // -- edx : new.target ++ // -- edi : target ++ // -- esp[0] : return address ++ // -- esp[4] : receiver (undefined) ++ // ----------------------------------- ++ ++ // 2. Make sure the target is actually a constructor. ++ Label target_not_constructor; ++ __ JumpIfSmi(edi, &target_not_constructor, Label::kNear); ++ __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsConstructor)); ++ __ j(zero, &target_not_constructor, Label::kNear); ++ ++ // 3. Make sure the target is actually a constructor. ++ Label new_target_not_constructor; ++ __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear); ++ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsConstructor)); ++ __ j(zero, &new_target_not_constructor, Label::kNear); ++ ++ // 4a. Construct the target with the given new.target and argumentsList. ++ __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); ++ ++ // 4b. The target is not a constructor, throw an appropriate TypeError. ++ __ bind(&target_not_constructor); ++ { ++ __ mov(Operand(esp, kPointerSize), edi); ++ __ TailCallRuntime(Runtime::kThrowNotConstructor); ++ } ++ ++ // 4c. The new.target is not a constructor, throw an appropriate TypeError. ++ __ bind(&new_target_not_constructor); ++ { ++ __ mov(Operand(esp, kPointerSize), edx); ++ __ TailCallRuntime(Runtime::kThrowNotConstructor); ++ } ++} ++ ++void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // ----------------------------------- ++ Label generic_array_code; ++ ++ // Get the InternalArray function. ++ __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); ++ ++ if (FLAG_debug_code) { ++ // Initial map for the builtin InternalArray function should be a map. ++ __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); ++ // Will both indicate a NULL and a Smi. ++ __ test(ebx, Immediate(kSmiTagMask)); ++ __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction); ++ __ CmpObjectType(ebx, MAP_TYPE, ecx); ++ __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction); ++ } ++ ++ // Run the native code for the InternalArray function called as a normal ++ // function. ++ // tail call a stub ++ InternalArrayConstructorStub stub(masm->isolate()); ++ __ TailCallStub(&stub); ++} ++ ++void Builtins::Generate_ArrayCode(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // ----------------------------------- ++ Label generic_array_code; ++ ++ // Get the Array function. ++ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi); ++ __ mov(edx, edi); ++ ++ if (FLAG_debug_code) { ++ // Initial map for the builtin Array function should be a map. ++ __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); ++ // Will both indicate a NULL and a Smi. ++ __ test(ebx, Immediate(kSmiTagMask)); ++ __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); ++ __ CmpObjectType(ebx, MAP_TYPE, ecx); ++ __ Assert(equal, kUnexpectedInitialMapForArrayFunction); ++ } ++ ++ // Run the native code for the Array function called as a normal function. ++ // tail call a stub ++ __ mov(ebx, masm->isolate()->factory()->undefined_value()); ++ ArrayConstructorStub stub(masm->isolate()); ++ __ TailCallStub(&stub); ++} ++ ++// static ++void Builtins::Generate_NumberConstructor(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments ++ // -- edi : constructor function ++ // -- esi : context ++ // -- esp[0] : return address ++ // -- esp[(argc - n) * 4] : arg[n] (zero-based) ++ // -- esp[(argc + 1) * 4] : receiver ++ // ----------------------------------- ++ ++ // 1. Load the first argument into ebx. ++ Label no_arguments; ++ { ++ __ test(eax, eax); ++ __ j(zero, &no_arguments, Label::kNear); ++ __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); ++ } ++ ++ // 2a. Convert the first argument to a number. ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ SmiTag(eax); ++ __ EnterBuiltinFrame(esi, edi, eax); ++ __ mov(eax, ebx); ++ __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET); ++ __ LeaveBuiltinFrame(esi, edi, ebx); // Argc popped to ebx. ++ __ SmiUntag(ebx); ++ } ++ ++ { ++ // Drop all arguments including the receiver. ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); ++ __ PushReturnAddressFrom(ecx); ++ __ Ret(); ++ } ++ ++ // 2b. No arguments, return +0 (already in eax). ++ __ bind(&no_arguments); ++ __ ret(1 * kPointerSize); ++} ++ ++// static ++void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments ++ // -- edi : constructor function ++ // -- edx : new target ++ // -- esi : context ++ // -- esp[0] : return address ++ // -- esp[(argc - n) * 4] : arg[n] (zero-based) ++ // -- esp[(argc + 1) * 4] : receiver ++ // ----------------------------------- ++ ++ // 1. Make sure we operate in the context of the called function. ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ // Store argc in r8. ++ __ mov(ecx, eax); ++ __ SmiTag(ecx); ++ ++ // 2. Load the first argument into ebx. ++ { ++ Label no_arguments, done; ++ __ test(eax, eax); ++ __ j(zero, &no_arguments, Label::kNear); ++ __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); ++ __ jmp(&done, Label::kNear); ++ __ bind(&no_arguments); ++ __ Move(ebx, Smi::kZero); ++ __ bind(&done); ++ } ++ ++ // 3. Make sure ebx is a number. ++ { ++ Label done_convert; ++ __ JumpIfSmi(ebx, &done_convert); ++ __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset), ++ Heap::kHeapNumberMapRootIndex); ++ __ j(equal, &done_convert); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ EnterBuiltinFrame(esi, edi, ecx); ++ __ Push(edx); ++ __ Move(eax, ebx); ++ __ Call(masm->isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET); ++ __ Move(ebx, eax); ++ __ Pop(edx); ++ __ LeaveBuiltinFrame(esi, edi, ecx); ++ } ++ __ bind(&done_convert); ++ } ++ ++ // 4. Check if new target and constructor differ. ++ Label drop_frame_and_ret, done_alloc, new_object; ++ __ cmp(edx, edi); ++ __ j(not_equal, &new_object); ++ ++ // 5. Allocate a JSValue wrapper for the number. ++ __ AllocateJSValue(eax, edi, ebx, esi, &done_alloc); ++ __ jmp(&drop_frame_and_ret); ++ ++ __ bind(&done_alloc); ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); // Restore esi. ++ ++ // 6. Fallback to the runtime to create new object. ++ __ bind(&new_object); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ EnterBuiltinFrame(esi, edi, ecx); ++ __ Push(ebx); // the first argument ++ __ Call(masm->isolate()->builtins()->FastNewObject(), ++ RelocInfo::CODE_TARGET); ++ __ Pop(FieldOperand(eax, JSValue::kValueOffset)); ++ __ LeaveBuiltinFrame(esi, edi, ecx); ++ } ++ ++ __ bind(&drop_frame_and_ret); ++ { ++ // Drop all arguments including the receiver. ++ __ PopReturnAddressTo(esi); ++ __ SmiUntag(ecx); ++ __ lea(esp, Operand(esp, ecx, times_pointer_size, kPointerSize)); ++ __ PushReturnAddressFrom(esi); ++ __ Ret(); ++ } ++} ++ ++// static ++void Builtins::Generate_StringConstructor(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments ++ // -- edi : constructor function ++ // -- esi : context ++ // -- esp[0] : return address ++ // -- esp[(argc - n) * 4] : arg[n] (zero-based) ++ // -- esp[(argc + 1) * 4] : receiver ++ // ----------------------------------- ++ ++ // 1. Load the first argument into eax. ++ Label no_arguments; ++ { ++ __ mov(ebx, eax); // Store argc in ebx. ++ __ test(eax, eax); ++ __ j(zero, &no_arguments, Label::kNear); ++ __ mov(eax, Operand(esp, eax, times_pointer_size, 0)); ++ } ++ ++ // 2a. At least one argument, return eax if it's a string, otherwise ++ // dispatch to appropriate conversion. ++ Label drop_frame_and_ret, to_string, symbol_descriptive_string; ++ { ++ __ JumpIfSmi(eax, &to_string, Label::kNear); ++ STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); ++ __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); ++ __ j(above, &to_string, Label::kNear); ++ __ j(equal, &symbol_descriptive_string, Label::kNear); ++ __ jmp(&drop_frame_and_ret, Label::kNear); ++ } ++ ++ // 2b. No arguments, return the empty string (and pop the receiver). ++ __ bind(&no_arguments); ++ { ++ __ LoadRoot(eax, Heap::kempty_stringRootIndex); ++ __ ret(1 * kPointerSize); ++ } ++ ++ // 3a. Convert eax to a string. ++ __ bind(&to_string); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ SmiTag(ebx); ++ __ EnterBuiltinFrame(esi, edi, ebx); ++ __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET); ++ __ LeaveBuiltinFrame(esi, edi, ebx); ++ __ SmiUntag(ebx); ++ } ++ __ jmp(&drop_frame_and_ret, Label::kNear); ++ ++ // 3b. Convert symbol in eax to a string. ++ __ bind(&symbol_descriptive_string); ++ { ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); ++ __ Push(eax); ++ __ PushReturnAddressFrom(ecx); ++ __ TailCallRuntime(Runtime::kSymbolDescriptiveString); ++ } ++ ++ __ bind(&drop_frame_and_ret); ++ { ++ // Drop all arguments including the receiver. ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); ++ __ PushReturnAddressFrom(ecx); ++ __ Ret(); ++ } ++} ++ ++// static ++void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments ++ // -- edi : constructor function ++ // -- edx : new target ++ // -- esi : context ++ // -- esp[0] : return address ++ // -- esp[(argc - n) * 4] : arg[n] (zero-based) ++ // -- esp[(argc + 1) * 4] : receiver ++ // ----------------------------------- ++ ++ // 1. Make sure we operate in the context of the called function. ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ __ mov(ebx, eax); ++ ++ // 2. Load the first argument into eax. ++ { ++ Label no_arguments, done; ++ __ test(ebx, ebx); ++ __ j(zero, &no_arguments, Label::kNear); ++ __ mov(eax, Operand(esp, ebx, times_pointer_size, 0)); ++ __ jmp(&done, Label::kNear); ++ __ bind(&no_arguments); ++ __ LoadRoot(eax, Heap::kempty_stringRootIndex); ++ __ bind(&done); ++ } ++ ++ // 3. Make sure eax is a string. ++ { ++ Label convert, done_convert; ++ __ JumpIfSmi(eax, &convert, Label::kNear); ++ __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); ++ __ j(below, &done_convert); ++ __ bind(&convert); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ SmiTag(ebx); ++ __ EnterBuiltinFrame(esi, edi, ebx); ++ __ Push(edx); ++ __ Call(masm->isolate()->builtins()->ToString(), RelocInfo::CODE_TARGET); ++ __ Pop(edx); ++ __ LeaveBuiltinFrame(esi, edi, ebx); ++ __ SmiUntag(ebx); ++ } ++ __ bind(&done_convert); ++ } ++ ++ // 4. Check if new target and constructor differ. ++ Label drop_frame_and_ret, done_alloc, new_object; ++ __ cmp(edx, edi); ++ __ j(not_equal, &new_object); ++ ++ // 5. Allocate a JSValue wrapper for the string. ++ // AllocateJSValue can't handle src == dst register. Reuse esi and restore it ++ // as needed after the call. ++ __ mov(esi, eax); ++ __ AllocateJSValue(eax, edi, esi, ecx, &done_alloc); ++ __ jmp(&drop_frame_and_ret); ++ ++ __ bind(&done_alloc); ++ { ++ // Restore eax to the first argument and esi to the context. ++ __ mov(eax, esi); ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ } ++ ++ // 6. Fallback to the runtime to create new object. ++ __ bind(&new_object); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ SmiTag(ebx); ++ __ EnterBuiltinFrame(esi, edi, ebx); ++ __ Push(eax); // the first argument ++ __ Call(masm->isolate()->builtins()->FastNewObject(), ++ RelocInfo::CODE_TARGET); ++ __ Pop(FieldOperand(eax, JSValue::kValueOffset)); ++ __ LeaveBuiltinFrame(esi, edi, ebx); ++ __ SmiUntag(ebx); ++ } ++ ++ __ bind(&drop_frame_and_ret); ++ { ++ // Drop all arguments including the receiver. ++ __ PopReturnAddressTo(ecx); ++ __ lea(esp, Operand(esp, ebx, times_pointer_size, kPointerSize)); ++ __ PushReturnAddressFrom(ecx); ++ __ Ret(); ++ } ++} ++ ++static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { ++ __ push(ebp); ++ __ mov(ebp, esp); ++ ++ // Store the arguments adaptor context sentinel. ++ __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ ++ // Push the function on the stack. ++ __ push(edi); ++ ++ // Preserve the number of arguments on the stack. Must preserve eax, ++ // ebx and ecx because these registers are used when copying the ++ // arguments and the receiver. ++ STATIC_ASSERT(kSmiTagSize == 1); ++ __ lea(edi, Operand(eax, eax, times_1, kSmiTag)); ++ __ push(edi); ++} ++ ++static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { ++ // Retrieve the number of arguments from the stack. ++ __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ ++ // Leave the frame. ++ __ leave(); ++ ++ // Remove caller arguments from the stack. ++ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); ++ __ pop(ecx); ++ __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver ++ __ push(ecx); ++} ++ ++// static ++void Builtins::Generate_Apply(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argumentsList ++ // -- edi : target ++ // -- edx : new.target (checked to be constructor or undefined) ++ // -- esp[0] : return address. ++ // -- esp[4] : thisArgument ++ // ----------------------------------- ++ ++ // Create the list of arguments from the array-like argumentsList. ++ { ++ Label create_arguments, create_array, create_holey_array, create_runtime, ++ done_create; ++ __ JumpIfSmi(eax, &create_runtime); ++ ++ // Load the map of argumentsList into ecx. ++ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); ++ ++ // Load native context into ebx. ++ __ mov(ebx, NativeContextOperand()); ++ ++ // Check if argumentsList is an (unmodified) arguments object. ++ __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX)); ++ __ j(equal, &create_arguments); ++ __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX)); ++ __ j(equal, &create_arguments); ++ ++ // Check if argumentsList is a fast JSArray. ++ __ CmpInstanceType(ecx, JS_ARRAY_TYPE); ++ __ j(equal, &create_array); ++ ++ // Ask the runtime to create the list (actually a FixedArray). ++ __ bind(&create_runtime); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(edi); ++ __ Push(edx); ++ __ Push(eax); ++ __ CallRuntime(Runtime::kCreateListFromArrayLike); ++ __ Pop(edx); ++ __ Pop(edi); ++ __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset)); ++ __ SmiUntag(ebx); ++ } ++ __ jmp(&done_create); ++ ++ // Try to create the list from an arguments object. ++ __ bind(&create_arguments); ++ __ mov(ebx, FieldOperand(eax, JSArgumentsObject::kLengthOffset)); ++ __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset)); ++ __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); ++ __ j(not_equal, &create_runtime); ++ __ SmiUntag(ebx); ++ __ mov(eax, ecx); ++ __ jmp(&done_create); ++ ++ // For holey JSArrays we need to check that the array prototype chain ++ // protector is intact and our prototype is the Array.prototype actually. ++ __ bind(&create_holey_array); ++ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ mov(ecx, FieldOperand(ecx, Map::kPrototypeOffset)); ++ __ cmp(ecx, ContextOperand(ebx, Context::INITIAL_ARRAY_PROTOTYPE_INDEX)); ++ __ j(not_equal, &create_runtime); ++ __ LoadRoot(ecx, Heap::kArrayProtectorRootIndex); ++ __ cmp(FieldOperand(ecx, PropertyCell::kValueOffset), ++ Immediate(Smi::FromInt(Isolate::kProtectorValid))); ++ __ j(not_equal, &create_runtime); ++ __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset)); ++ __ SmiUntag(ebx); ++ __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset)); ++ __ jmp(&done_create); ++ ++ // Try to create the list from a JSArray object. ++ __ bind(&create_array); ++ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); ++ __ DecodeField(ecx); ++ STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); ++ STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1); ++ STATIC_ASSERT(PACKED_ELEMENTS == 2); ++ STATIC_ASSERT(HOLEY_ELEMENTS == 3); ++ __ cmp(ecx, Immediate(HOLEY_SMI_ELEMENTS)); ++ __ j(equal, &create_holey_array, Label::kNear); ++ __ cmp(ecx, Immediate(HOLEY_ELEMENTS)); ++ __ j(equal, &create_holey_array, Label::kNear); ++ __ j(above, &create_runtime); ++ __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset)); ++ __ SmiUntag(ebx); ++ __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset)); ++ ++ __ bind(&done_create); ++ } ++ ++ // Check for stack overflow. ++ { ++ // Check the stack for overflow. We are not trying to catch interruptions ++ // (i.e. debug break and preemption) here, so check the "real stack limit". ++ Label done; ++ ExternalReference real_stack_limit = ++ ExternalReference::address_of_real_stack_limit(masm->isolate()); ++ __ mov(ecx, Operand::StaticVariable(real_stack_limit)); ++ // Make ecx the space we have left. The stack might already be overflowed ++ // here which will cause ecx to become negative. ++ __ neg(ecx); ++ __ add(ecx, esp); ++ __ sar(ecx, kPointerSizeLog2); ++ // Check if the arguments will overflow the stack. ++ __ cmp(ecx, ebx); ++ __ j(greater, &done, Label::kNear); // Signed comparison. ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ __ bind(&done); ++ } ++ ++ // ----------- S t a t e ------------- ++ // -- edi : target ++ // -- eax : args (a FixedArray built from argumentsList) ++ // -- ebx : len (number of elements to push from args) ++ // -- edx : new.target (checked to be constructor or undefined) ++ // -- esp[0] : return address. ++ // -- esp[4] : thisArgument ++ // ----------------------------------- ++ ++ // Push arguments onto the stack (thisArgument is already on the stack). ++ { ++ // Save edx/edi to stX0/stX1. ++ __ push(edx); ++ __ push(edi); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 4)); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ ++ __ PopReturnAddressTo(edx); ++ __ Move(ecx, Immediate(0)); ++ Label done, push, loop; ++ __ bind(&loop); ++ __ cmp(ecx, ebx); ++ __ j(equal, &done, Label::kNear); ++ // Turn the hole into undefined as we go. ++ __ mov(edi, ++ FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize)); ++ __ CompareRoot(edi, Heap::kTheHoleValueRootIndex); ++ __ j(not_equal, &push, Label::kNear); ++ __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); ++ __ bind(&push); ++ __ Push(edi); ++ __ inc(ecx); ++ __ jmp(&loop); ++ __ bind(&done); ++ __ PushReturnAddressFrom(edx); ++ ++ // Restore edx/edi from stX0/stX1. ++ __ lea(esp, Operand(esp, -2 * kFloatSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fstp_s(MemOperand(esp, 4)); ++ __ pop(edx); ++ __ pop(edi); ++ ++ __ Move(eax, ebx); ++ } ++ ++ // Dispatch to Call or Construct depending on whether new.target is undefined. ++ { ++ __ CompareRoot(edx, Heap::kUndefinedValueRootIndex); ++ __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); ++ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); ++ } ++} ++ ++// static ++void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm, ++ Handle code) { ++ // ----------- S t a t e ------------- ++ // -- edi : the target to call (can be any Object) ++ // -- ecx : start index (to support rest parameters) ++ // -- esp[0] : return address. ++ // -- esp[4] : thisArgument ++ // ----------------------------------- ++ ++ // Check if we have an arguments adaptor frame below the function frame. ++ Label arguments_adaptor, arguments_done; ++ __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(equal, &arguments_adaptor, Label::kNear); ++ { ++ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(eax, ++ FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); ++ __ mov(ebx, ebp); ++ } ++ __ jmp(&arguments_done, Label::kNear); ++ __ bind(&arguments_adaptor); ++ { ++ // Just load the length from the ArgumentsAdaptorFrame. ++ __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ SmiUntag(eax); ++ } ++ __ bind(&arguments_done); ++ ++ Label stack_empty, stack_done; ++ __ sub(eax, ecx); ++ __ j(less_equal, &stack_empty); ++ { ++ // Check for stack overflow. ++ { ++ // Check the stack for overflow. We are not trying to catch interruptions ++ // (i.e. debug break and preemption) here, so check the "real stack ++ // limit". ++ Label done; ++ __ LoadRoot(ecx, Heap::kRealStackLimitRootIndex); ++ // Make ecx the space we have left. The stack might already be ++ // overflowed here which will cause ecx to become negative. ++ __ neg(ecx); ++ __ add(ecx, esp); ++ __ sar(ecx, kPointerSizeLog2); ++ // Check if the arguments will overflow the stack. ++ __ cmp(ecx, eax); ++ __ j(greater, &done, Label::kNear); // Signed comparison. ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ __ bind(&done); ++ } ++ ++ // Forward the arguments from the caller frame. ++ { ++ Label loop; ++ __ mov(ecx, eax); ++ __ pop(edx); ++ __ bind(&loop); ++ { ++ __ Push(Operand(ebx, ecx, times_pointer_size, 1 * kPointerSize)); ++ __ dec(ecx); ++ __ j(not_zero, &loop); ++ } ++ __ push(edx); ++ } ++ } ++ __ jmp(&stack_done, Label::kNear); ++ __ bind(&stack_empty); ++ { ++ // We just pass the receiver, which is already on the stack. ++ __ Move(eax, Immediate(0)); ++ } ++ __ bind(&stack_done); ++ ++ __ Jump(code, RelocInfo::CODE_TARGET); ++} ++ ++namespace { ++ ++// Drops top JavaScript frame and an arguments adaptor frame below it (if ++// present) preserving all the arguments prepared for current call. ++// Does nothing if debugger is currently active. ++// ES6 14.6.3. PrepareForTailCall ++// ++// Stack structure for the function g() tail calling f(): ++// ++// ------- Caller frame: ------- ++// | ... ++// | g()'s arg M ++// | ... ++// | g()'s arg 1 ++// | g()'s receiver arg ++// | g()'s caller pc ++// ------- g()'s frame: ------- ++// | g()'s caller fp <- fp ++// | g()'s context ++// | function pointer: g ++// | ------------------------- ++// | ... ++// | ... ++// | f()'s arg N ++// | ... ++// | f()'s arg 1 ++// | f()'s receiver arg ++// | f()'s caller pc <- sp ++// ---------------------- ++// ++void PrepareForTailCall(MacroAssembler* masm, Register args_reg, ++ Register scratch1, Register scratch2, ++ Register scratch3) { ++ DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); ++ Comment cmnt(masm, "[ PrepareForTailCall"); ++ ++ // Prepare for tail call only if ES2015 tail call elimination is enabled. ++ Label done; ++ ExternalReference is_tail_call_elimination_enabled = ++ ExternalReference::is_tail_call_elimination_enabled_address( ++ masm->isolate()); ++ __ movzx_b(scratch1, ++ Operand::StaticVariable(is_tail_call_elimination_enabled)); ++ __ cmp(scratch1, Immediate(0)); ++ __ j(equal, &done, Label::kNear); ++ ++ // Drop possible interpreter handler/stub frame. ++ { ++ Label no_interpreter_frame; ++ __ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(StackFrame::STUB))); ++ __ j(not_equal, &no_interpreter_frame, Label::kNear); ++ __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ bind(&no_interpreter_frame); ++ } ++ ++ // Check if next frame is an arguments adaptor frame. ++ Register caller_args_count_reg = scratch1; ++ Label no_arguments_adaptor, formal_parameter_count_loaded; ++ __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ cmp(Operand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(not_equal, &no_arguments_adaptor, Label::kNear); ++ ++ // Drop current frame and load arguments count from arguments adaptor frame. ++ __ mov(ebp, scratch2); ++ __ mov(caller_args_count_reg, ++ Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ SmiUntag(caller_args_count_reg); ++ __ jmp(&formal_parameter_count_loaded, Label::kNear); ++ ++ __ bind(&no_arguments_adaptor); ++ // Load caller's formal parameter count ++ __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ mov(scratch1, ++ FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov( ++ caller_args_count_reg, ++ FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset)); ++ ++ __ bind(&formal_parameter_count_loaded); ++ ++ ParameterCount callee_args_count(args_reg); ++ __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, ++ scratch3, ReturnAddressState::kOnStack, 0); ++ __ bind(&done); ++} ++} // namespace ++ ++// static ++void Builtins::Generate_CallFunction(MacroAssembler* masm, ++ ConvertReceiverMode mode, ++ TailCallMode tail_call_mode) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the function to call (checked to be a JSFunction) ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) ++ // Check that the function is not a "classConstructor". ++ Label class_constructor; ++ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ test(FieldOperand(edx, SharedFunctionInfo::kCompilerHintsOffset), ++ Immediate(SharedFunctionInfo::kClassConstructorMask)); ++ __ j(not_zero, &class_constructor); ++ ++ // Enter the context of the function; ToObject has to run in the function ++ // context, and we also need to take the global proxy from the function ++ // context in case of conversion. ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ // We need to convert the receiver for non-native sloppy mode functions. ++ Label done_convert; ++ __ test(FieldOperand(edx, SharedFunctionInfo::kCompilerHintsOffset), ++ Immediate(SharedFunctionInfo::IsNativeBit::kMask | ++ SharedFunctionInfo::IsStrictBit::kMask)); ++ __ j(not_zero, &done_convert); ++ { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the shared function info. ++ // -- edi : the function to call (checked to be a JSFunction) ++ // -- esi : the function context. ++ // ----------------------------------- ++ ++ if (mode == ConvertReceiverMode::kNullOrUndefined) { ++ // Patch receiver to global proxy. ++ __ LoadGlobalProxy(ecx); ++ } else { ++ Label convert_to_object, convert_receiver; ++ __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize)); ++ __ JumpIfSmi(ecx, &convert_to_object, Label::kNear); ++ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); ++ __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx); ++ __ j(above_equal, &done_convert); ++ if (mode != ConvertReceiverMode::kNotNullOrUndefined) { ++ Label convert_global_proxy; ++ __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, ++ &convert_global_proxy, Label::kNear); ++ __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object, ++ Label::kNear); ++ __ bind(&convert_global_proxy); ++ { ++ // Patch receiver to global proxy. ++ __ LoadGlobalProxy(ecx); ++ } ++ __ jmp(&convert_receiver); ++ } ++ __ bind(&convert_to_object); ++ { ++ // Convert receiver using ToObject. ++ // TODO(bmeurer): Inline the allocation here to avoid building the frame ++ // in the fast case? (fall back to AllocateInNewSpace?) ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ SmiTag(eax); ++ __ Push(eax); ++ __ Push(edi); ++ __ mov(eax, ecx); ++ __ Push(esi); ++ __ Call(masm->isolate()->builtins()->ToObject(), ++ RelocInfo::CODE_TARGET); ++ __ Pop(esi); ++ __ mov(ecx, eax); ++ __ Pop(edi); ++ __ Pop(eax); ++ __ SmiUntag(eax); ++ } ++ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ bind(&convert_receiver); ++ } ++ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx); ++ } ++ __ bind(&done_convert); ++ ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the shared function info. ++ // -- edi : the function to call (checked to be a JSFunction) ++ // -- esi : the function context. ++ // ----------------------------------- ++ ++ if (tail_call_mode == TailCallMode::kAllow) { ++ PrepareForTailCall(masm, eax, ebx, ecx, edx); ++ // Reload shared function info. ++ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ } ++ ++ __ mov(ebx, ++ FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); ++ ParameterCount actual(eax); ++ ParameterCount expected(ebx); ++ __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION, ++ CheckDebugStepCallWrapper()); ++ // The function is a "classConstructor", need to raise an exception. ++ __ bind(&class_constructor); ++ { ++ FrameScope frame(masm, StackFrame::INTERNAL); ++ __ push(edi); ++ __ CallRuntime(Runtime::kThrowConstructorNonCallableError); ++ } ++} ++ ++namespace { ++ ++void Generate_PushBoundArguments(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : new.target (only in case of [[Construct]]) ++ // -- edi : target (checked to be a JSBoundFunction) ++ // ----------------------------------- ++ ++ // Load [[BoundArguments]] into ecx and length of that into ebx. ++ Label no_bound_arguments; ++ __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); ++ __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); ++ __ SmiUntag(ebx); ++ __ test(ebx, ebx); ++ __ j(zero, &no_bound_arguments); ++ { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : new.target (only in case of [[Construct]]) ++ // -- edi : target (checked to be a JSBoundFunction) ++ // -- ecx : the [[BoundArguments]] (implemented as FixedArray) ++ // -- ebx : the number of [[BoundArguments]] ++ // ----------------------------------- ++ ++ // Reserve stack space for the [[BoundArguments]]. ++ { ++ Label done; ++ __ lea(ecx, Operand(ebx, times_pointer_size, 0)); ++ __ sub(esp, ecx); ++ // Check the stack for overflow. We are not trying to catch interruptions ++ // (i.e. debug break and preemption) here, so check the "real stack ++ // limit". ++ __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex); ++ __ j(greater, &done, Label::kNear); // Signed comparison. ++ // Restore the stack pointer. ++ __ lea(esp, Operand(esp, ebx, times_pointer_size, 0)); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ EnterFrame(StackFrame::INTERNAL); ++ __ CallRuntime(Runtime::kThrowStackOverflow); ++ } ++ __ bind(&done); ++ } ++ ++ // Adjust effective number of arguments to include return address. ++ __ inc(eax); ++ ++ // Relocate arguments and return address down the stack. ++ { ++ Label loop; ++ __ Set(ecx, 0); ++ __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0)); ++ __ bind(&loop); ++ __ fld_s(Operand(ebx, ecx, times_pointer_size, 0)); ++ __ fstp_s(Operand(esp, ecx, times_pointer_size, 0)); ++ __ inc(ecx); ++ __ cmp(ecx, eax); ++ __ j(less, &loop); ++ } ++ ++ // Copy [[BoundArguments]] to the stack (below the arguments). ++ { ++ Label loop; ++ __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); ++ __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); ++ __ SmiUntag(ebx); ++ __ bind(&loop); ++ __ dec(ebx); ++ __ fld_s( ++ FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize)); ++ __ fstp_s(Operand(esp, eax, times_pointer_size, 0)); ++ __ lea(eax, Operand(eax, 1)); ++ __ j(greater, &loop); ++ } ++ ++ // Adjust effective number of arguments (eax contains the number of ++ // arguments from the call plus return address plus the number of ++ // [[BoundArguments]]), so we need to subtract one for the return address. ++ __ dec(eax); ++ } ++ __ bind(&no_bound_arguments); ++} ++ ++} // namespace ++ ++// static ++void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm, ++ TailCallMode tail_call_mode) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the function to call (checked to be a JSBoundFunction) ++ // ----------------------------------- ++ __ AssertBoundFunction(edi); ++ ++ if (tail_call_mode == TailCallMode::kAllow) { ++ PrepareForTailCall(masm, eax, ebx, ecx, edx); ++ } ++ ++ // Patch the receiver to [[BoundThis]]. ++ __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset)); ++ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx); ++ ++ // Push the [[BoundArguments]] onto the stack. ++ Generate_PushBoundArguments(masm); ++ ++ // Call the [[BoundTargetFunction]] via the Call builtin. ++ __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); ++ __ mov(ecx, Operand::StaticVariable(ExternalReference( ++ Builtins::kCall_ReceiverIsAny, masm->isolate()))); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++} ++ ++// static ++void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode, ++ TailCallMode tail_call_mode) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the target to call (can be any Object). ++ // ----------------------------------- ++ ++ Label non_callable, non_function, non_smi; ++ __ JumpIfSmi(edi, &non_callable); ++ __ bind(&non_smi); ++ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); ++ __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode), ++ RelocInfo::CODE_TARGET); ++ __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); ++ __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode), ++ RelocInfo::CODE_TARGET); ++ ++ // Check if target has a [[Call]] internal method. ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsCallable)); ++ __ j(zero, &non_callable); ++ ++ // Check if target is a proxy and call CallProxy external builtin ++ __ CmpInstanceType(ecx, JS_PROXY_TYPE); ++ __ j(not_equal, &non_function); ++ ++ __ mov(ecx, Operand::StaticVariable( ++ ExternalReference(Builtins::kCallProxy, masm->isolate()))); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++ ++ // 2. Call to something else, which might have a [[Call]] internal method (if ++ // not we raise an exception). ++ __ bind(&non_function); ++ // Overwrite the original receiver with the (original) target. ++ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); ++ // Let the "call_as_function_delegate" take care of the rest. ++ __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi); ++ __ Jump(masm->isolate()->builtins()->CallFunction( ++ ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode), ++ RelocInfo::CODE_TARGET); ++ ++ // 3. Call to something that is not callable. ++ __ bind(&non_callable); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(edi); ++ __ CallRuntime(Runtime::kThrowCalledNonCallable); ++ } ++} ++ ++static void CheckSpreadAndPushToStack(MacroAssembler* masm) { ++ // Free up some registers. ++ // Save edx/edi to stX0/stX1. ++ __ push(edx); ++ __ push(edi); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 4)); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ ++ Register argc = eax; ++ ++ Register scratch = ecx; ++ Register scratch2 = edi; ++ ++ Register spread = ebx; ++ Register spread_map = edx; ++ ++ Register spread_len = edx; ++ ++ Label runtime_call, push_args; ++ __ mov(spread, Operand(esp, kPointerSize)); ++ __ JumpIfSmi(spread, &runtime_call); ++ __ mov(spread_map, FieldOperand(spread, HeapObject::kMapOffset)); ++ ++ // Check that the spread is an array. ++ __ CmpInstanceType(spread_map, JS_ARRAY_TYPE); ++ __ j(not_equal, &runtime_call); ++ ++ // Check that we have the original ArrayPrototype. ++ __ mov(scratch, FieldOperand(spread_map, Map::kPrototypeOffset)); ++ __ mov(scratch2, NativeContextOperand()); ++ __ cmp(scratch, ++ ContextOperand(scratch2, Context::INITIAL_ARRAY_PROTOTYPE_INDEX)); ++ __ j(not_equal, &runtime_call); ++ ++ // Check that the ArrayPrototype hasn't been modified in a way that would ++ // affect iteration. ++ __ LoadRoot(scratch, Heap::kArrayIteratorProtectorRootIndex); ++ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), ++ Immediate(Smi::FromInt(Isolate::kProtectorValid))); ++ __ j(not_equal, &runtime_call); ++ ++ // Check that the map of the initial array iterator hasn't changed. ++ __ mov(scratch2, NativeContextOperand()); ++ __ mov(scratch, ++ ContextOperand(scratch2, ++ Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)); ++ __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); ++ __ cmp(scratch, ++ ContextOperand(scratch2, ++ Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_MAP_INDEX)); ++ __ j(not_equal, &runtime_call); ++ ++ // For FastPacked kinds, iteration will have the same effect as simply ++ // accessing each property in order. ++ Label no_protector_check; ++ __ mov(scratch, FieldOperand(spread_map, Map::kBitField2Offset)); ++ __ DecodeField(scratch); ++ __ cmp(scratch, Immediate(HOLEY_ELEMENTS)); ++ __ j(above, &runtime_call); ++ // For non-FastHoley kinds, we can skip the protector check. ++ __ cmp(scratch, Immediate(PACKED_SMI_ELEMENTS)); ++ __ j(equal, &no_protector_check); ++ __ cmp(scratch, Immediate(PACKED_ELEMENTS)); ++ __ j(equal, &no_protector_check); ++ // Check the ArrayProtector cell. ++ __ LoadRoot(scratch, Heap::kArrayProtectorRootIndex); ++ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), ++ Immediate(Smi::FromInt(Isolate::kProtectorValid))); ++ __ j(not_equal, &runtime_call); ++ ++ __ bind(&no_protector_check); ++ // Load the FixedArray backing store, but use the length from the array. ++ __ mov(spread_len, FieldOperand(spread, JSArray::kLengthOffset)); ++ __ SmiUntag(spread_len); ++ __ mov(spread, FieldOperand(spread, JSArray::kElementsOffset)); ++ __ jmp(&push_args); ++ ++ __ bind(&runtime_call); ++ { ++ // Call the builtin for the result of the spread. ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // Need to save these on the stack. ++ // Restore edx/edi from stX0/stX1. ++ __ lea(esp, Operand(esp, -2 * kFloatSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fstp_s(MemOperand(esp, 4)); ++ __ pop(edx); ++ __ pop(edi); ++ ++ __ Push(edi); ++ __ Push(edx); ++ __ SmiTag(argc); ++ __ Push(argc); ++ __ Push(spread); ++ __ CallRuntime(Runtime::kSpreadIterableFixed); ++ __ mov(spread, eax); ++ __ Pop(argc); ++ __ SmiUntag(argc); ++ __ Pop(edx); ++ __ Pop(edi); ++ // Free up some registers. ++ // Save edx/edi to stX0/stX1. ++ __ push(edx); ++ __ push(edi); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 4)); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ } ++ ++ { ++ // Calculate the new nargs including the result of the spread. ++ __ mov(spread_len, FieldOperand(spread, FixedArray::kLengthOffset)); ++ __ SmiUntag(spread_len); ++ ++ __ bind(&push_args); ++ // argc += spread_len - 1. Subtract 1 for the spread itself. ++ __ lea(argc, Operand(argc, spread_len, times_1, -1)); ++ } ++ ++ // Check for stack overflow. ++ { ++ // Check the stack for overflow. We are not trying to catch interruptions ++ // (i.e. debug break and preemption) here, so check the "real stack limit". ++ Label done; ++ __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex); ++ // Make scratch the space we have left. The stack might already be ++ // overflowed here which will cause scratch to become negative. ++ __ neg(scratch); ++ __ add(scratch, esp); ++ __ sar(scratch, kPointerSizeLog2); ++ // Check if the arguments will overflow the stack. ++ __ cmp(scratch, spread_len); ++ __ j(greater, &done, Label::kNear); // Signed comparison. ++ __ TailCallRuntime(Runtime::kThrowStackOverflow); ++ __ bind(&done); ++ } ++ ++ // Put the evaluated spread onto the stack as additional arguments. ++ { ++ Register return_address = edi; ++ // Pop the return address and spread argument. ++ __ PopReturnAddressTo(return_address); ++ __ Pop(scratch); ++ ++ Register scratch2 = esi; ++ // Save esi to stX0, edx/edi in stX1/stX2 now. ++ __ push(esi); ++ __ fld_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, 1 * kFloatSize)); ++ ++ __ mov(scratch, Immediate(0)); ++ Label done, push, loop; ++ __ bind(&loop); ++ __ cmp(scratch, spread_len); ++ __ j(equal, &done, Label::kNear); ++ __ mov(scratch2, FieldOperand(spread, scratch, times_pointer_size, ++ FixedArray::kHeaderSize)); ++ __ JumpIfNotRoot(scratch2, Heap::kTheHoleValueRootIndex, &push); ++ __ LoadRoot(scratch2, Heap::kUndefinedValueRootIndex); ++ __ bind(&push); ++ __ Push(scratch2); ++ __ inc(scratch); ++ __ jmp(&loop); ++ __ bind(&done); ++ __ PushReturnAddressFrom(return_address); ++ ++ // Now Restore esi from stX0, edx/edi from stX1/stX2. ++ __ lea(esp, Operand(esp, -3 * kFloatSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fstp_s(MemOperand(esp, 4)); ++ __ fstp_s(MemOperand(esp, 8)); ++ __ pop(esi); ++ __ pop(edx); ++ __ pop(edi); ++ } ++} ++ ++// static ++void Builtins::Generate_CallWithSpread(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the target to call (can be any Object) ++ // ----------------------------------- ++ ++ // CheckSpreadAndPushToStack will push edx to save it. ++ __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); ++ CheckSpreadAndPushToStack(masm); ++ __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, ++ TailCallMode::kDisallow), ++ RelocInfo::CODE_TARGET); ++} ++ ++// static ++void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the new target (checked to be a constructor) ++ // -- edi : the constructor to call (checked to be a JSFunction) ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // Calling convention for function specific ConstructStubs require ++ // ebx to contain either an AllocationSite or undefined. ++ __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); ++ ++ // Tail call to the function-specific construct stub (still in the caller ++ // context at this point). ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++} ++ ++// static ++void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the new target (checked to be a constructor) ++ // -- edi : the constructor to call (checked to be a JSBoundFunction) ++ // ----------------------------------- ++ __ AssertBoundFunction(edi); ++ ++ // Push the [[BoundArguments]] onto the stack. ++ Generate_PushBoundArguments(masm); ++ ++ // Patch new.target to [[BoundTargetFunction]] if new.target equals target. ++ { ++ Label done; ++ __ cmp(edi, edx); ++ __ j(not_equal, &done, Label::kNear); ++ __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); ++ __ bind(&done); ++ } ++ ++ // Construct the [[BoundTargetFunction]] via the Construct builtin. ++ __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); ++ __ mov(ecx, Operand::StaticVariable( ++ ExternalReference(Builtins::kConstruct, masm->isolate()))); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++} ++ ++// static ++void Builtins::Generate_ConstructProxy(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edi : the constructor to call (checked to be a JSProxy) ++ // -- edx : the new target (either the same as the constructor or ++ // the JSFunction on which new was invoked initially) ++ // ----------------------------------- ++ ++ // Call into the Runtime for Proxy [[Construct]]. ++ __ PopReturnAddressTo(ecx); ++ __ Push(edi); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ // Include the pushed new_target, constructor and the receiver. ++ __ add(eax, Immediate(3)); ++ // Tail-call to the runtime. ++ __ JumpToExternalReference( ++ ExternalReference(Runtime::kJSProxyConstruct, masm->isolate())); ++} ++ ++// static ++void Builtins::Generate_Construct(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the new target (either the same as the constructor or ++ // the JSFunction on which new was invoked initially) ++ // -- edi : the constructor to call (can be any Object) ++ // ----------------------------------- ++ ++ // Check if target is a Smi. ++ Label non_constructor; ++ __ JumpIfSmi(edi, &non_constructor, Label::kNear); ++ ++ // Dispatch based on instance type. ++ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); ++ __ j(equal, masm->isolate()->builtins()->ConstructFunction(), ++ RelocInfo::CODE_TARGET); ++ ++ // Check if target has a [[Construct]] internal method. ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsConstructor)); ++ __ j(zero, &non_constructor, Label::kNear); ++ ++ // Only dispatch to bound functions after checking whether they are ++ // constructors. ++ __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); ++ __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(), ++ RelocInfo::CODE_TARGET); ++ ++ // Only dispatch to proxies after checking whether they are constructors. ++ __ CmpInstanceType(ecx, JS_PROXY_TYPE); ++ __ j(equal, masm->isolate()->builtins()->ConstructProxy(), ++ RelocInfo::CODE_TARGET); ++ ++ // Called Construct on an exotic Object with a [[Construct]] internal method. ++ { ++ // Overwrite the original receiver with the (original) target. ++ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); ++ // Let the "call_as_constructor_delegate" take care of the rest. ++ __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi); ++ __ Jump(masm->isolate()->builtins()->CallFunction(), ++ RelocInfo::CODE_TARGET); ++ } ++ ++ // Called Construct on an Object that doesn't have a [[Construct]] internal ++ // method. ++ __ bind(&non_constructor); ++ __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(), ++ RelocInfo::CODE_TARGET); ++} ++ ++// static ++void Builtins::Generate_ConstructWithSpread(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : the number of arguments (not including the receiver) ++ // -- edx : the new target (either the same as the constructor or ++ // the JSFunction on which new was invoked initially) ++ // -- edi : the constructor to call (can be any Object) ++ // ----------------------------------- ++ ++ CheckSpreadAndPushToStack(masm); ++ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); ++} ++ ++// static ++void Builtins::Generate_AllocateInNewSpace(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edx : requested object size (untagged) ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ SmiTag(edx); ++ __ PopReturnAddressTo(ecx); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(esi, Smi::kZero); ++ __ TailCallRuntime(Runtime::kAllocateInNewSpace); ++} ++ ++// static ++void Builtins::Generate_AllocateInOldSpace(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edx : requested object size (untagged) ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ SmiTag(edx); ++ __ PopReturnAddressTo(ecx); ++ __ Push(edx); ++ __ Push(Smi::FromInt(AllocateTargetSpace::encode(OLD_SPACE))); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(esi, Smi::kZero); ++ __ TailCallRuntime(Runtime::kAllocateInTargetSpace); ++} ++ ++// static ++void Builtins::Generate_Abort(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edx : message_id as Smi ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ PopReturnAddressTo(ecx); ++ __ Push(edx); ++ __ PushReturnAddressFrom(ecx); ++ __ Move(esi, Smi::kZero); ++ __ TailCallRuntime(Runtime::kAbort); ++} ++ ++void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : actual number of arguments ++ // -- ebx : expected number of arguments ++ // -- edx : new target (passed through to callee) ++ // -- edi : function (passed through to callee) ++ // ----------------------------------- ++ ++ Label invoke, dont_adapt_arguments, stack_overflow; ++ __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); ++ ++ Label enough, too_few; ++ __ cmp(eax, ebx); ++ __ j(less, &too_few); ++ __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); ++ __ j(equal, &dont_adapt_arguments); ++ ++ { // Enough parameters: Actual >= expected. ++ __ bind(&enough); ++ EnterArgumentsAdaptorFrame(masm); ++ // edi is used as a scratch register. It should be restored from the frame ++ // when needed. ++ Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); ++ ++ // Copy receiver and all expected arguments. ++ const int offset = StandardFrameConstants::kCallerSPOffset; ++ __ lea(edi, Operand(ebp, eax, times_4, offset)); ++ __ mov(eax, -1); // account for receiver ++ ++ Label copy; ++ __ bind(©); ++ __ inc(eax); ++ __ push(Operand(edi, 0)); ++ __ sub(edi, Immediate(kPointerSize)); ++ __ cmp(eax, ebx); ++ __ j(less, ©); ++ // eax now contains the expected number of arguments. ++ __ jmp(&invoke); ++ } ++ ++ { // Too few parameters: Actual < expected. ++ __ bind(&too_few); ++ EnterArgumentsAdaptorFrame(masm); ++ // edi is used as a scratch register. It should be restored from the frame ++ // when needed. ++ Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); ++ ++ // Remember expected arguments in ecx. ++ __ mov(ecx, ebx); ++ ++ // Copy receiver and all actual arguments. ++ const int offset = StandardFrameConstants::kCallerSPOffset; ++ __ lea(edi, Operand(ebp, eax, times_4, offset)); ++ // ebx = expected - actual. ++ __ sub(ebx, eax); ++ // eax = -actual - 1 ++ __ neg(eax); ++ __ sub(eax, Immediate(1)); ++ ++ Label copy; ++ __ bind(©); ++ __ inc(eax); ++ __ push(Operand(edi, 0)); ++ __ sub(edi, Immediate(kPointerSize)); ++ __ test(eax, eax); ++ __ j(not_zero, ©); ++ ++ // Fill remaining expected arguments with undefined values. ++ Label fill; ++ __ bind(&fill); ++ __ inc(eax); ++ __ push(Immediate(masm->isolate()->factory()->undefined_value())); ++ __ cmp(eax, ebx); ++ __ j(less, &fill); ++ ++ // Restore expected arguments. ++ __ mov(eax, ecx); ++ } ++ ++ // Call the entry point. ++ __ bind(&invoke); ++ // Restore function pointer. ++ __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset)); ++ // eax : expected number of arguments ++ // edx : new target (passed through to callee) ++ // edi : function (passed through to callee) ++ __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); ++ __ call(ecx); ++ ++ // Store offset of return address for deoptimizer. ++ masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); ++ ++ // Leave frame and return. ++ LeaveArgumentsAdaptorFrame(masm); ++ __ ret(0); ++ ++ // ------------------------------------------- ++ // Dont adapt arguments. ++ // ------------------------------------------- ++ __ bind(&dont_adapt_arguments); ++ __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); ++ __ jmp(ecx); ++ ++ __ bind(&stack_overflow); ++ { ++ FrameScope frame(masm, StackFrame::MANUAL); ++ __ CallRuntime(Runtime::kThrowStackOverflow); ++ __ int3(); ++ } ++} ++ ++static void Generate_OnStackReplacementHelper(MacroAssembler* masm, ++ bool has_handler_frame) { ++ // Lookup the function in the JavaScript frame. ++ if (has_handler_frame) { ++ __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ mov(eax, Operand(eax, JavaScriptFrameConstants::kFunctionOffset)); ++ } else { ++ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ } ++ ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // Pass function as argument. ++ __ push(eax); ++ __ CallRuntime(Runtime::kCompileForOnStackReplacement); ++ } ++ ++ Label skip; ++ // If the code object is null, just return to the caller. ++ __ cmp(eax, Immediate(0)); ++ __ j(not_equal, &skip, Label::kNear); ++ __ ret(0); ++ ++ __ bind(&skip); ++ ++ // Drop any potential handler frame that is be sitting on top of the actual ++ // JavaScript frame. This is the case then OSR is triggered from bytecode. ++ if (has_handler_frame) { ++ __ leave(); ++ } ++ ++ // Load deoptimization data from the code object. ++ __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag)); ++ ++ // Load the OSR entrypoint offset from the deoptimization data. ++ __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt( ++ DeoptimizationInputData::kOsrPcOffsetIndex) - ++ kHeapObjectTag)); ++ __ SmiUntag(ebx); ++ ++ // Compute the target address = code_obj + header_size + osr_offset ++ __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag)); ++ ++ // Overwrite the return address on the stack. ++ __ mov(Operand(esp, 0), eax); ++ ++ // And "return" to the OSR entry point of the function. ++ __ ret(0); ++} ++ ++void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { ++ Generate_OnStackReplacementHelper(masm, false); ++} ++ ++void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { ++ Generate_OnStackReplacementHelper(masm, true); ++} ++ ++#undef __ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/builtins/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/builtins/x87/OWNERS 2017-12-25 17:42:57.201465852 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/codegen.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/codegen.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/codegen.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/codegen.h 2017-12-25 17:42:57.205465793 +0100 +@@ -59,6 +59,8 @@ + #include "src/mips64/codegen-mips64.h" // NOLINT + #elif V8_TARGET_ARCH_S390 + #include "src/s390/codegen-s390.h" // NOLINT ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/codegen-x87.h" // NOLINT + #else + #error Unsupported target architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/code-stubs.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/code-stubs.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/code-stubs.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/code-stubs.h 2017-12-25 17:42:57.205465793 +0100 +@@ -514,6 +514,8 @@ + #include "src/mips64/code-stubs-mips64.h" + #elif V8_TARGET_ARCH_S390 + #include "src/s390/code-stubs-s390.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/code-stubs-x87.h" + #else + #error Unsupported target architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/c-linkage.cc 2017-12-25 17:42:57.205465793 +0100 +@@ -50,6 +50,12 @@ + rbx.bit() | r12.bit() | r13.bit() | r14.bit() | r15.bit() + #endif + ++#elif V8_TARGET_ARCH_X87 ++// =========================================================================== ++// == x87 ==================================================================== ++// =========================================================================== ++#define CALLEE_SAVE_REGISTERS esi.bit() | edi.bit() | ebx.bit() ++ + #elif V8_TARGET_ARCH_ARM + // =========================================================================== + // == arm ==================================================================== +@@ -155,7 +161,7 @@ + msig->parameter_count()); + // Check the types of the signature. + // Currently no floating point parameters or returns are allowed because +- // on ia32, the FP top of stack is involved. ++ // on x87 and ia32, the FP top of stack is involved. + for (size_t i = 0; i < msig->return_count(); i++) { + MachineRepresentation rep = msig->GetReturn(i).representation(); + CHECK_NE(MachineRepresentation::kFloat32, rep); +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/instruction-codes.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/instruction-codes.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/instruction-codes.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/instruction-codes.h 2017-12-25 17:42:57.205465793 +0100 +@@ -23,6 +23,8 @@ + #include "src/compiler/ppc/instruction-codes-ppc.h" + #elif V8_TARGET_ARCH_S390 + #include "src/compiler/s390/instruction-codes-s390.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/compiler/x87/instruction-codes-x87.h" + #else + #define TARGET_ARCH_OPCODE_LIST(V) + #define TARGET_ADDRESSING_MODE_LIST(V) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/wasm-linkage.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/wasm-linkage.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/wasm-linkage.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/wasm-linkage.cc 2017-12-25 17:42:57.205465793 +0100 +@@ -69,6 +69,14 @@ + #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6 + #define FP_RETURN_REGISTERS xmm1, xmm2 + ++#elif V8_TARGET_ARCH_X87 ++// =========================================================================== ++// == x87 ==================================================================== ++// =========================================================================== ++#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi ++#define GP_RETURN_REGISTERS eax, edx ++#define FP_RETURN_REGISTERS stX_0 ++ + #elif V8_TARGET_ARCH_ARM + // =========================================================================== + // == arm ==================================================================== +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/code-generator-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/code-generator-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/code-generator-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/code-generator-x87.cc 2017-12-25 17:42:57.208465749 +0100 +@@ -0,0 +1,2768 @@ ++// Copyright 2013 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "src/compiler/code-generator.h" ++ ++#include "src/compilation-info.h" ++#include "src/compiler/code-generator-impl.h" ++#include "src/compiler/gap-resolver.h" ++#include "src/compiler/node-matchers.h" ++#include "src/compiler/osr.h" ++#include "src/frames.h" ++#include "src/x87/assembler-x87.h" ++#include "src/x87/frames-x87.h" ++#include "src/x87/macro-assembler-x87.h" ++ ++namespace v8 { ++namespace internal { ++namespace compiler { ++ ++#define __ masm()-> ++ ++ ++// Adds X87 specific methods for decoding operands. ++class X87OperandConverter : public InstructionOperandConverter { ++ public: ++ X87OperandConverter(CodeGenerator* gen, Instruction* instr) ++ : InstructionOperandConverter(gen, instr) {} ++ ++ Operand InputOperand(size_t index, int extra = 0) { ++ return ToOperand(instr_->InputAt(index), extra); ++ } ++ ++ Immediate InputImmediate(size_t index) { ++ return ToImmediate(instr_->InputAt(index)); ++ } ++ ++ Operand OutputOperand() { return ToOperand(instr_->Output()); } ++ ++ Operand ToOperand(InstructionOperand* op, int extra = 0) { ++ if (op->IsRegister()) { ++ DCHECK(extra == 0); ++ return Operand(ToRegister(op)); ++ } ++ DCHECK(op->IsStackSlot() || op->IsFPStackSlot()); ++ return SlotToOperand(AllocatedOperand::cast(op)->index(), extra); ++ } ++ ++ Operand SlotToOperand(int slot, int extra = 0) { ++ FrameOffset offset = frame_access_state()->GetFrameOffset(slot); ++ return Operand(offset.from_stack_pointer() ? esp : ebp, ++ offset.offset() + extra); ++ } ++ ++ Operand HighOperand(InstructionOperand* op) { ++ DCHECK(op->IsFPStackSlot()); ++ return ToOperand(op, kPointerSize); ++ } ++ ++ Immediate ToImmediate(InstructionOperand* operand) { ++ Constant constant = ToConstant(operand); ++ if (constant.type() == Constant::kInt32 && ++ RelocInfo::IsWasmReference(constant.rmode())) { ++ return Immediate(reinterpret_cast
(constant.ToInt32()), ++ constant.rmode()); ++ } ++ switch (constant.type()) { ++ case Constant::kInt32: ++ return Immediate(constant.ToInt32()); ++ case Constant::kFloat32: ++ return Immediate( ++ isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED)); ++ case Constant::kFloat64: ++ return Immediate(isolate()->factory()->NewNumber( ++ constant.ToFloat64(value()).value(), TENURED)); ++ case Constant::kExternalReference: ++ return Immediate(constant.ToExternalReference()); ++ case Constant::kHeapObject: ++ return Immediate(constant.ToHeapObject()); ++ case Constant::kInt64: ++ break; ++ case Constant::kRpoNumber: ++ return Immediate::CodeRelativeOffset(ToLabel(operand)); ++ } ++ UNREACHABLE(); ++ } ++ ++ static size_t NextOffset(size_t* offset) { ++ size_t i = *offset; ++ (*offset)++; ++ return i; ++ } ++ ++ static ScaleFactor ScaleFor(AddressingMode one, AddressingMode mode) { ++ STATIC_ASSERT(0 == static_cast(times_1)); ++ STATIC_ASSERT(1 == static_cast(times_2)); ++ STATIC_ASSERT(2 == static_cast(times_4)); ++ STATIC_ASSERT(3 == static_cast(times_8)); ++ int scale = static_cast(mode - one); ++ DCHECK(scale >= 0 && scale < 4); ++ return static_cast(scale); ++ } ++ ++ Operand MemoryOperand(size_t* offset) { ++ AddressingMode mode = AddressingModeField::decode(instr_->opcode()); ++ switch (mode) { ++ case kMode_MR: { ++ Register base = InputRegister(NextOffset(offset)); ++ int32_t disp = 0; ++ return Operand(base, disp); ++ } ++ case kMode_MRI: { ++ Register base = InputRegister(NextOffset(offset)); ++ Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset))); ++ return Operand(base, ctant.ToInt32(), ctant.rmode()); ++ } ++ case kMode_MR1: ++ case kMode_MR2: ++ case kMode_MR4: ++ case kMode_MR8: { ++ Register base = InputRegister(NextOffset(offset)); ++ Register index = InputRegister(NextOffset(offset)); ++ ScaleFactor scale = ScaleFor(kMode_MR1, mode); ++ int32_t disp = 0; ++ return Operand(base, index, scale, disp); ++ } ++ case kMode_MR1I: ++ case kMode_MR2I: ++ case kMode_MR4I: ++ case kMode_MR8I: { ++ Register base = InputRegister(NextOffset(offset)); ++ Register index = InputRegister(NextOffset(offset)); ++ ScaleFactor scale = ScaleFor(kMode_MR1I, mode); ++ Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset))); ++ return Operand(base, index, scale, ctant.ToInt32(), ctant.rmode()); ++ } ++ case kMode_M1: ++ case kMode_M2: ++ case kMode_M4: ++ case kMode_M8: { ++ Register index = InputRegister(NextOffset(offset)); ++ ScaleFactor scale = ScaleFor(kMode_M1, mode); ++ int32_t disp = 0; ++ return Operand(index, scale, disp); ++ } ++ case kMode_M1I: ++ case kMode_M2I: ++ case kMode_M4I: ++ case kMode_M8I: { ++ Register index = InputRegister(NextOffset(offset)); ++ ScaleFactor scale = ScaleFor(kMode_M1I, mode); ++ Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset))); ++ return Operand(index, scale, ctant.ToInt32(), ctant.rmode()); ++ } ++ case kMode_MI: { ++ Constant ctant = ToConstant(instr_->InputAt(NextOffset(offset))); ++ return Operand(ctant.ToInt32(), ctant.rmode()); ++ } ++ case kMode_None: ++ UNREACHABLE(); ++ } ++ UNREACHABLE(); ++ } ++ ++ Operand MemoryOperand(size_t first_input = 0) { ++ return MemoryOperand(&first_input); ++ } ++}; ++ ++ ++namespace { ++ ++bool HasImmediateInput(Instruction* instr, size_t index) { ++ return instr->InputAt(index)->IsImmediate(); ++} ++ ++ ++class OutOfLineLoadInteger final : public OutOfLineCode { ++ public: ++ OutOfLineLoadInteger(CodeGenerator* gen, Register result) ++ : OutOfLineCode(gen), result_(result) {} ++ ++ void Generate() final { __ xor_(result_, result_); } ++ ++ private: ++ Register const result_; ++}; ++ ++class OutOfLineLoadFloat32NaN final : public OutOfLineCode { ++ public: ++ OutOfLineLoadFloat32NaN(CodeGenerator* gen, X87Register result) ++ : OutOfLineCode(gen), result_(result) {} ++ ++ void Generate() final { ++ DCHECK(result_.code() == 0); ++ USE(result_); ++ __ fstp(0); ++ __ push(Immediate(0xffc00000)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ } ++ ++ private: ++ X87Register const result_; ++}; ++ ++class OutOfLineLoadFloat64NaN final : public OutOfLineCode { ++ public: ++ OutOfLineLoadFloat64NaN(CodeGenerator* gen, X87Register result) ++ : OutOfLineCode(gen), result_(result) {} ++ ++ void Generate() final { ++ DCHECK(result_.code() == 0); ++ USE(result_); ++ __ fstp(0); ++ __ push(Immediate(0xfff80000)); ++ __ push(Immediate(0x00000000)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ } ++ ++ private: ++ X87Register const result_; ++}; ++ ++class OutOfLineTruncateDoubleToI final : public OutOfLineCode { ++ public: ++ OutOfLineTruncateDoubleToI(CodeGenerator* gen, Register result, ++ X87Register input) ++ : OutOfLineCode(gen), result_(result), input_(input) {} ++ ++ void Generate() final { ++ UNIMPLEMENTED(); ++ USE(result_); ++ USE(input_); ++ } ++ ++ private: ++ Register const result_; ++ X87Register const input_; ++}; ++ ++ ++class OutOfLineRecordWrite final : public OutOfLineCode { ++ public: ++ OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand operand, ++ Register value, Register scratch0, Register scratch1, ++ RecordWriteMode mode) ++ : OutOfLineCode(gen), ++ object_(object), ++ operand_(operand), ++ value_(value), ++ scratch0_(scratch0), ++ scratch1_(scratch1), ++ mode_(mode) {} ++ ++ void Generate() final { ++ if (mode_ > RecordWriteMode::kValueIsPointer) { ++ __ JumpIfSmi(value_, exit()); ++ } ++ __ CheckPageFlag(value_, scratch0_, ++ MemoryChunk::kPointersToHereAreInterestingMask, zero, ++ exit()); ++ RememberedSetAction const remembered_set_action = ++ mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET ++ : OMIT_REMEMBERED_SET; ++ SaveFPRegsMode const save_fp_mode = ++ frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; ++ RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, ++ remembered_set_action, save_fp_mode); ++ __ lea(scratch1_, operand_); ++ __ CallStub(&stub); ++ } ++ ++ private: ++ Register const object_; ++ Operand const operand_; ++ Register const value_; ++ Register const scratch0_; ++ Register const scratch1_; ++ RecordWriteMode const mode_; ++}; ++ ++} // namespace ++ ++#define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, OutOfLineLoadNaN) \ ++ do { \ ++ auto result = i.OutputDoubleRegister(); \ ++ auto offset = i.InputRegister(0); \ ++ DCHECK(result.code() == 0); \ ++ if (instr->InputAt(1)->IsRegister()) { \ ++ __ cmp(offset, i.InputRegister(1)); \ ++ } else { \ ++ __ cmp(offset, i.InputImmediate(1)); \ ++ } \ ++ OutOfLineCode* ool = new (zone()) OutOfLineLoadNaN(this, result); \ ++ __ j(above_equal, ool->entry()); \ ++ __ fstp(0); \ ++ __ asm_instr(i.MemoryOperand(2)); \ ++ __ bind(ool->exit()); \ ++ } while (false) ++ ++#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \ ++ do { \ ++ auto result = i.OutputRegister(); \ ++ auto offset = i.InputRegister(0); \ ++ if (instr->InputAt(1)->IsRegister()) { \ ++ __ cmp(offset, i.InputRegister(1)); \ ++ } else { \ ++ __ cmp(offset, i.InputImmediate(1)); \ ++ } \ ++ OutOfLineCode* ool = new (zone()) OutOfLineLoadInteger(this, result); \ ++ __ j(above_equal, ool->entry()); \ ++ __ asm_instr(result, i.MemoryOperand(2)); \ ++ __ bind(ool->exit()); \ ++ } while (false) ++ ++ ++#define ASSEMBLE_CHECKED_STORE_FLOAT(asm_instr) \ ++ do { \ ++ auto offset = i.InputRegister(0); \ ++ if (instr->InputAt(1)->IsRegister()) { \ ++ __ cmp(offset, i.InputRegister(1)); \ ++ } else { \ ++ __ cmp(offset, i.InputImmediate(1)); \ ++ } \ ++ Label done; \ ++ DCHECK(i.InputDoubleRegister(2).code() == 0); \ ++ __ j(above_equal, &done, Label::kNear); \ ++ __ asm_instr(i.MemoryOperand(3)); \ ++ __ bind(&done); \ ++ } while (false) ++ ++ ++#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \ ++ do { \ ++ auto offset = i.InputRegister(0); \ ++ if (instr->InputAt(1)->IsRegister()) { \ ++ __ cmp(offset, i.InputRegister(1)); \ ++ } else { \ ++ __ cmp(offset, i.InputImmediate(1)); \ ++ } \ ++ Label done; \ ++ __ j(above_equal, &done, Label::kNear); \ ++ if (instr->InputAt(2)->IsRegister()) { \ ++ __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \ ++ } else { \ ++ __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \ ++ } \ ++ __ bind(&done); \ ++ } while (false) ++ ++#define ASSEMBLE_COMPARE(asm_instr) \ ++ do { \ ++ if (AddressingModeField::decode(instr->opcode()) != kMode_None) { \ ++ size_t index = 0; \ ++ Operand left = i.MemoryOperand(&index); \ ++ if (HasImmediateInput(instr, index)) { \ ++ __ asm_instr(left, i.InputImmediate(index)); \ ++ } else { \ ++ __ asm_instr(left, i.InputRegister(index)); \ ++ } \ ++ } else { \ ++ if (HasImmediateInput(instr, 1)) { \ ++ if (instr->InputAt(0)->IsRegister()) { \ ++ __ asm_instr(i.InputRegister(0), i.InputImmediate(1)); \ ++ } else { \ ++ __ asm_instr(i.InputOperand(0), i.InputImmediate(1)); \ ++ } \ ++ } else { \ ++ if (instr->InputAt(1)->IsRegister()) { \ ++ __ asm_instr(i.InputRegister(0), i.InputRegister(1)); \ ++ } else { \ ++ __ asm_instr(i.InputRegister(0), i.InputOperand(1)); \ ++ } \ ++ } \ ++ } \ ++ } while (0) ++ ++#define ASSEMBLE_IEEE754_BINOP(name) \ ++ do { \ ++ /* Saves the esp into ebx */ \ ++ __ push(ebx); \ ++ __ mov(ebx, esp); \ ++ /* Pass one double as argument on the stack. */ \ ++ __ PrepareCallCFunction(4, eax); \ ++ __ fstp(0); \ ++ /* Load first operand from original stack */ \ ++ __ fld_d(MemOperand(ebx, 4 + kDoubleSize)); \ ++ /* Put first operand into stack for function call */ \ ++ __ fstp_d(Operand(esp, 0 * kDoubleSize)); \ ++ /* Load second operand from original stack */ \ ++ __ fld_d(MemOperand(ebx, 4)); \ ++ /* Put second operand into stack for function call */ \ ++ __ fstp_d(Operand(esp, 1 * kDoubleSize)); \ ++ __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ ++ 4); \ ++ /* Restore the ebx */ \ ++ __ pop(ebx); \ ++ /* Return value is in st(0) on x87. */ \ ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); \ ++ } while (false) ++ ++#define ASSEMBLE_IEEE754_UNOP(name) \ ++ do { \ ++ /* Saves the esp into ebx */ \ ++ __ push(ebx); \ ++ __ mov(ebx, esp); \ ++ /* Pass one double as argument on the stack. */ \ ++ __ PrepareCallCFunction(2, eax); \ ++ __ fstp(0); \ ++ /* Load operand from original stack */ \ ++ __ fld_d(MemOperand(ebx, 4)); \ ++ /* Put operand into stack for function call */ \ ++ __ fstp_d(Operand(esp, 0)); \ ++ __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \ ++ 2); \ ++ /* Restore the ebx */ \ ++ __ pop(ebx); \ ++ /* Return value is in st(0) on x87. */ \ ++ __ lea(esp, Operand(esp, kDoubleSize)); \ ++ } while (false) ++ ++void CodeGenerator::AssembleDeconstructFrame() { ++ __ mov(esp, ebp); ++ __ pop(ebp); ++} ++ ++void CodeGenerator::AssemblePrepareTailCall() { ++ if (frame_access_state()->has_frame()) { ++ __ mov(ebp, MemOperand(ebp, 0)); ++ } ++ frame_access_state()->SetFrameAccessToSP(); ++} ++ ++void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, ++ Register, Register, ++ Register) { ++ // There are not enough temp registers left on ia32 for a call instruction ++ // so we pick some scratch registers and save/restore them manually here. ++ int scratch_count = 3; ++ Register scratch1 = ebx; ++ Register scratch2 = ecx; ++ Register scratch3 = edx; ++ DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); ++ Label done; ++ ++ // Check if current frame is an arguments adaptor frame. ++ __ cmp(Operand(ebp, StandardFrameConstants::kContextOffset), ++ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(not_equal, &done, Label::kNear); ++ ++ __ push(scratch1); ++ __ push(scratch2); ++ __ push(scratch3); ++ ++ // Load arguments count from current arguments adaptor frame (note, it ++ // does not include receiver). ++ Register caller_args_count_reg = scratch1; ++ __ mov(caller_args_count_reg, ++ Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ SmiUntag(caller_args_count_reg); ++ ++ ParameterCount callee_args_count(args_reg); ++ __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, ++ scratch3, ReturnAddressState::kOnStack, scratch_count); ++ __ pop(scratch3); ++ __ pop(scratch2); ++ __ pop(scratch1); ++ ++ __ bind(&done); ++} ++ ++namespace { ++ ++void AdjustStackPointerForTailCall(MacroAssembler* masm, ++ FrameAccessState* state, ++ int new_slot_above_sp, ++ bool allow_shrinkage = true) { ++ int current_sp_offset = state->GetSPToFPSlotCount() + ++ StandardFrameConstants::kFixedSlotCountAboveFp; ++ int stack_slot_delta = new_slot_above_sp - current_sp_offset; ++ if (stack_slot_delta > 0) { ++ masm->sub(esp, Immediate(stack_slot_delta * kPointerSize)); ++ state->IncreaseSPDelta(stack_slot_delta); ++ } else if (allow_shrinkage && stack_slot_delta < 0) { ++ masm->add(esp, Immediate(-stack_slot_delta * kPointerSize)); ++ state->IncreaseSPDelta(stack_slot_delta); ++ } ++} ++ ++} // namespace ++ ++void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, ++ int first_unused_stack_slot) { ++ CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush); ++ ZoneVector pushes(zone()); ++ GetPushCompatibleMoves(instr, flags, &pushes); ++ ++ if (!pushes.empty() && ++ (LocationOperand::cast(pushes.back()->destination()).index() + 1 == ++ first_unused_stack_slot)) { ++ X87OperandConverter g(this, instr); ++ for (auto move : pushes) { ++ LocationOperand destination_location( ++ LocationOperand::cast(move->destination())); ++ InstructionOperand source(move->source()); ++ AdjustStackPointerForTailCall(masm(), frame_access_state(), ++ destination_location.index()); ++ if (source.IsStackSlot()) { ++ LocationOperand source_location(LocationOperand::cast(source)); ++ __ push(g.SlotToOperand(source_location.index())); ++ } else if (source.IsRegister()) { ++ LocationOperand source_location(LocationOperand::cast(source)); ++ __ push(source_location.GetRegister()); ++ } else if (source.IsImmediate()) { ++ __ push(Immediate(ImmediateOperand::cast(source).inline_value())); ++ } else { ++ // Pushes of non-scalar data types is not supported. ++ UNIMPLEMENTED(); ++ } ++ frame_access_state()->IncreaseSPDelta(1); ++ move->Eliminate(); ++ } ++ } ++ AdjustStackPointerForTailCall(masm(), frame_access_state(), ++ first_unused_stack_slot, false); ++} ++ ++void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, ++ int first_unused_stack_slot) { ++ AdjustStackPointerForTailCall(masm(), frame_access_state(), ++ first_unused_stack_slot); ++} ++ ++// Assembles an instruction after register allocation, producing machine code. ++CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ++ Instruction* instr) { ++ X87OperandConverter i(this, instr); ++ InstructionCode opcode = instr->opcode(); ++ ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); ++ ++ switch (arch_opcode) { ++ case kArchCallCodeObject: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ EnsureSpaceForLazyDeopt(); ++ if (HasImmediateInput(instr, 0)) { ++ Handle code = Handle::cast(i.InputHeapObject(0)); ++ __ call(code, RelocInfo::CODE_TARGET); ++ } else { ++ Register reg = i.InputRegister(0); ++ __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag)); ++ __ call(reg); ++ } ++ RecordCallPosition(instr); ++ bool double_result = ++ instr->HasOutput() && instr->Output()->IsFPRegister(); ++ if (double_result) { ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ __ fstp_d(Operand(esp, 0)); ++ } ++ __ fninit(); ++ if (double_result) { ++ __ fld_d(Operand(esp, 0)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ } else { ++ __ fld1(); ++ } ++ frame_access_state()->ClearSPDelta(); ++ break; ++ } ++ case kArchTailCallCodeObjectFromJSFunction: ++ case kArchTailCallCodeObject: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { ++ AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, ++ no_reg, no_reg, no_reg); ++ } ++ if (HasImmediateInput(instr, 0)) { ++ Handle code = Handle::cast(i.InputHeapObject(0)); ++ __ jmp(code, RelocInfo::CODE_TARGET); ++ } else { ++ Register reg = i.InputRegister(0); ++ __ add(reg, Immediate(Code::kHeaderSize - kHeapObjectTag)); ++ __ jmp(reg); ++ } ++ frame_access_state()->ClearSPDelta(); ++ frame_access_state()->SetFrameAccessToDefault(); ++ break; ++ } ++ case kArchTailCallAddress: { ++ CHECK(!HasImmediateInput(instr, 0)); ++ Register reg = i.InputRegister(0); ++ __ jmp(reg); ++ frame_access_state()->ClearSPDelta(); ++ frame_access_state()->SetFrameAccessToDefault(); ++ break; ++ } ++ case kArchCallJSFunction: { ++ EnsureSpaceForLazyDeopt(); ++ Register func = i.InputRegister(0); ++ if (FLAG_debug_code) { ++ // Check the function's context matches the context argument. ++ __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); ++ __ Assert(equal, kWrongFunctionContext); ++ } ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ call(FieldOperand(func, JSFunction::kCodeEntryOffset)); ++ RecordCallPosition(instr); ++ bool double_result = ++ instr->HasOutput() && instr->Output()->IsFPRegister(); ++ if (double_result) { ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ __ fstp_d(Operand(esp, 0)); ++ } ++ __ fninit(); ++ if (double_result) { ++ __ fld_d(Operand(esp, 0)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ } else { ++ __ fld1(); ++ } ++ frame_access_state()->ClearSPDelta(); ++ break; ++ } ++ case kArchTailCallJSFunctionFromJSFunction: { ++ Register func = i.InputRegister(0); ++ if (FLAG_debug_code) { ++ // Check the function's context matches the context argument. ++ __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); ++ __ Assert(equal, kWrongFunctionContext); ++ } ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, no_reg, ++ no_reg, no_reg); ++ __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset)); ++ frame_access_state()->ClearSPDelta(); ++ frame_access_state()->SetFrameAccessToDefault(); ++ break; ++ } ++ case kArchPrepareCallCFunction: { ++ // Frame alignment requires using FP-relative frame addressing. ++ frame_access_state()->SetFrameAccessToFP(); ++ int const num_parameters = MiscField::decode(instr->opcode()); ++ __ PrepareCallCFunction(num_parameters, i.TempRegister(0)); ++ break; ++ } ++ case kArchPrepareTailCall: ++ AssemblePrepareTailCall(); ++ break; ++ case kArchCallCFunction: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ int const num_parameters = MiscField::decode(instr->opcode()); ++ if (HasImmediateInput(instr, 0)) { ++ ExternalReference ref = i.InputExternalReference(0); ++ __ CallCFunction(ref, num_parameters); ++ } else { ++ Register func = i.InputRegister(0); ++ __ CallCFunction(func, num_parameters); ++ } ++ bool double_result = ++ instr->HasOutput() && instr->Output()->IsFPRegister(); ++ if (double_result) { ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ __ fstp_d(Operand(esp, 0)); ++ } ++ __ fninit(); ++ if (double_result) { ++ __ fld_d(Operand(esp, 0)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ } else { ++ __ fld1(); ++ } ++ frame_access_state()->SetFrameAccessToDefault(); ++ frame_access_state()->ClearSPDelta(); ++ break; ++ } ++ case kArchJmp: ++ AssembleArchJump(i.InputRpo(0)); ++ break; ++ case kArchLookupSwitch: ++ AssembleArchLookupSwitch(instr); ++ break; ++ case kArchTableSwitch: ++ AssembleArchTableSwitch(instr); ++ break; ++ case kArchComment: { ++ Address comment_string = i.InputExternalReference(0).address(); ++ __ RecordComment(reinterpret_cast(comment_string)); ++ break; ++ } ++ case kArchDebugBreak: ++ __ int3(); ++ break; ++ case kArchNop: ++ case kArchThrowTerminator: ++ // don't emit code for nops. ++ break; ++ case kArchDeoptimize: { ++ int deopt_state_id = ++ BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore()); ++ int double_register_param_count = 0; ++ int x87_layout = 0; ++ for (size_t i = 0; i < instr->InputCount(); i++) { ++ if (instr->InputAt(i)->IsFPRegister()) { ++ double_register_param_count++; ++ } ++ } ++ // Currently we use only one X87 register. If double_register_param_count ++ // is bigger than 1, it means duplicated double register is added to input ++ // of this instruction. ++ if (double_register_param_count > 0) { ++ x87_layout = (0 << 3) | 1; ++ } ++ // The layout of x87 register stack is loaded on the top of FPU register ++ // stack for deoptimization. ++ __ push(Immediate(x87_layout)); ++ __ fild_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kPointerSize)); ++ ++ CodeGenResult result = ++ AssembleDeoptimizerCall(deopt_state_id, current_source_position_); ++ if (result != kSuccess) return result; ++ break; ++ } ++ case kArchRet: ++ AssembleReturn(instr->InputAt(0)); ++ break; ++ case kArchFramePointer: ++ __ mov(i.OutputRegister(), ebp); ++ break; ++ case kArchStackPointer: ++ __ mov(i.OutputRegister(), esp); ++ break; ++ case kArchParentFramePointer: ++ if (frame_access_state()->has_frame()) { ++ __ mov(i.OutputRegister(), Operand(ebp, 0)); ++ } else { ++ __ mov(i.OutputRegister(), ebp); ++ } ++ break; ++ case kArchTruncateDoubleToI: { ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fld_d(i.InputOperand(0)); ++ } ++ __ TruncateX87TOSToI(i.OutputRegister()); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fstp(0); ++ } ++ break; ++ } ++ case kArchStoreWithWriteBarrier: { ++ RecordWriteMode mode = ++ static_cast(MiscField::decode(instr->opcode())); ++ Register object = i.InputRegister(0); ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ Register value = i.InputRegister(index); ++ Register scratch0 = i.TempRegister(0); ++ Register scratch1 = i.TempRegister(1); ++ auto ool = new (zone()) OutOfLineRecordWrite(this, object, operand, value, ++ scratch0, scratch1, mode); ++ __ mov(operand, value); ++ __ CheckPageFlag(object, scratch0, ++ MemoryChunk::kPointersFromHereAreInterestingMask, ++ not_zero, ool->entry()); ++ __ bind(ool->exit()); ++ break; ++ } ++ case kArchStackSlot: { ++ FrameOffset offset = ++ frame_access_state()->GetFrameOffset(i.InputInt32(0)); ++ Register base; ++ if (offset.from_stack_pointer()) { ++ base = esp; ++ } else { ++ base = ebp; ++ } ++ __ lea(i.OutputRegister(), Operand(base, offset.offset())); ++ break; ++ } ++ case kIeee754Float64Acos: ++ ASSEMBLE_IEEE754_UNOP(acos); ++ break; ++ case kIeee754Float64Acosh: ++ ASSEMBLE_IEEE754_UNOP(acosh); ++ break; ++ case kIeee754Float64Asin: ++ ASSEMBLE_IEEE754_UNOP(asin); ++ break; ++ case kIeee754Float64Asinh: ++ ASSEMBLE_IEEE754_UNOP(asinh); ++ break; ++ case kIeee754Float64Atan: ++ ASSEMBLE_IEEE754_UNOP(atan); ++ break; ++ case kIeee754Float64Atanh: ++ ASSEMBLE_IEEE754_UNOP(atanh); ++ break; ++ case kIeee754Float64Atan2: ++ ASSEMBLE_IEEE754_BINOP(atan2); ++ break; ++ case kIeee754Float64Cbrt: ++ ASSEMBLE_IEEE754_UNOP(cbrt); ++ break; ++ case kIeee754Float64Cos: ++ __ X87SetFPUCW(0x027F); ++ ASSEMBLE_IEEE754_UNOP(cos); ++ __ X87SetFPUCW(0x037F); ++ break; ++ case kIeee754Float64Cosh: ++ ASSEMBLE_IEEE754_UNOP(cosh); ++ break; ++ case kIeee754Float64Expm1: ++ __ X87SetFPUCW(0x027F); ++ ASSEMBLE_IEEE754_UNOP(expm1); ++ __ X87SetFPUCW(0x037F); ++ break; ++ case kIeee754Float64Exp: ++ ASSEMBLE_IEEE754_UNOP(exp); ++ break; ++ case kIeee754Float64Log: ++ ASSEMBLE_IEEE754_UNOP(log); ++ break; ++ case kIeee754Float64Log1p: ++ ASSEMBLE_IEEE754_UNOP(log1p); ++ break; ++ case kIeee754Float64Log2: ++ ASSEMBLE_IEEE754_UNOP(log2); ++ break; ++ case kIeee754Float64Log10: ++ ASSEMBLE_IEEE754_UNOP(log10); ++ break; ++ case kIeee754Float64Pow: { ++ // Keep the x87 FPU stack empty before calling stub code ++ __ fstp(0); ++ // Call the MathStub and put return value in stX_0 ++ MathPowStub stub(isolate(), MathPowStub::DOUBLE); ++ __ CallStub(&stub); ++ /* Return value is in st(0) on x87. */ ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ break; ++ } ++ case kIeee754Float64Sin: ++ __ X87SetFPUCW(0x027F); ++ ASSEMBLE_IEEE754_UNOP(sin); ++ __ X87SetFPUCW(0x037F); ++ break; ++ case kIeee754Float64Sinh: ++ ASSEMBLE_IEEE754_UNOP(sinh); ++ break; ++ case kIeee754Float64Tan: ++ __ X87SetFPUCW(0x027F); ++ ASSEMBLE_IEEE754_UNOP(tan); ++ __ X87SetFPUCW(0x037F); ++ break; ++ case kIeee754Float64Tanh: ++ ASSEMBLE_IEEE754_UNOP(tanh); ++ break; ++ case kX87Add: ++ if (HasImmediateInput(instr, 1)) { ++ __ add(i.InputOperand(0), i.InputImmediate(1)); ++ } else { ++ __ add(i.InputRegister(0), i.InputOperand(1)); ++ } ++ break; ++ case kX87And: ++ if (HasImmediateInput(instr, 1)) { ++ __ and_(i.InputOperand(0), i.InputImmediate(1)); ++ } else { ++ __ and_(i.InputRegister(0), i.InputOperand(1)); ++ } ++ break; ++ case kX87Cmp: ++ ASSEMBLE_COMPARE(cmp); ++ break; ++ case kX87Cmp16: ++ ASSEMBLE_COMPARE(cmpw); ++ break; ++ case kX87Cmp8: ++ ASSEMBLE_COMPARE(cmpb); ++ break; ++ case kX87Test: ++ ASSEMBLE_COMPARE(test); ++ break; ++ case kX87Test16: ++ ASSEMBLE_COMPARE(test_w); ++ break; ++ case kX87Test8: ++ ASSEMBLE_COMPARE(test_b); ++ break; ++ case kX87Imul: ++ if (HasImmediateInput(instr, 1)) { ++ __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1)); ++ } else { ++ __ imul(i.OutputRegister(), i.InputOperand(1)); ++ } ++ break; ++ case kX87ImulHigh: ++ __ imul(i.InputRegister(1)); ++ break; ++ case kX87UmulHigh: ++ __ mul(i.InputRegister(1)); ++ break; ++ case kX87Idiv: ++ __ cdq(); ++ __ idiv(i.InputOperand(1)); ++ break; ++ case kX87Udiv: ++ __ Move(edx, Immediate(0)); ++ __ div(i.InputOperand(1)); ++ break; ++ case kX87Not: ++ __ not_(i.OutputOperand()); ++ break; ++ case kX87Neg: ++ __ neg(i.OutputOperand()); ++ break; ++ case kX87Or: ++ if (HasImmediateInput(instr, 1)) { ++ __ or_(i.InputOperand(0), i.InputImmediate(1)); ++ } else { ++ __ or_(i.InputRegister(0), i.InputOperand(1)); ++ } ++ break; ++ case kX87Xor: ++ if (HasImmediateInput(instr, 1)) { ++ __ xor_(i.InputOperand(0), i.InputImmediate(1)); ++ } else { ++ __ xor_(i.InputRegister(0), i.InputOperand(1)); ++ } ++ break; ++ case kX87Sub: ++ if (HasImmediateInput(instr, 1)) { ++ __ sub(i.InputOperand(0), i.InputImmediate(1)); ++ } else { ++ __ sub(i.InputRegister(0), i.InputOperand(1)); ++ } ++ break; ++ case kX87Shl: ++ if (HasImmediateInput(instr, 1)) { ++ __ shl(i.OutputOperand(), i.InputInt5(1)); ++ } else { ++ __ shl_cl(i.OutputOperand()); ++ } ++ break; ++ case kX87Shr: ++ if (HasImmediateInput(instr, 1)) { ++ __ shr(i.OutputOperand(), i.InputInt5(1)); ++ } else { ++ __ shr_cl(i.OutputOperand()); ++ } ++ break; ++ case kX87Sar: ++ if (HasImmediateInput(instr, 1)) { ++ __ sar(i.OutputOperand(), i.InputInt5(1)); ++ } else { ++ __ sar_cl(i.OutputOperand()); ++ } ++ break; ++ case kX87AddPair: { ++ // i.OutputRegister(0) == i.InputRegister(0) ... left low word. ++ // i.InputRegister(1) ... left high word. ++ // i.InputRegister(2) ... right low word. ++ // i.InputRegister(3) ... right high word. ++ bool use_temp = false; ++ if (i.OutputRegister(0).code() == i.InputRegister(1).code() || ++ i.OutputRegister(0).code() == i.InputRegister(3).code()) { ++ // We cannot write to the output register directly, because it would ++ // overwrite an input for adc. We have to use the temp register. ++ use_temp = true; ++ __ Move(i.TempRegister(0), i.InputRegister(0)); ++ __ add(i.TempRegister(0), i.InputRegister(2)); ++ } else { ++ __ add(i.OutputRegister(0), i.InputRegister(2)); ++ } ++ if (i.OutputRegister(1).code() != i.InputRegister(1).code()) { ++ __ Move(i.OutputRegister(1), i.InputRegister(1)); ++ } ++ __ adc(i.OutputRegister(1), Operand(i.InputRegister(3))); ++ if (use_temp) { ++ __ Move(i.OutputRegister(0), i.TempRegister(0)); ++ } ++ break; ++ } ++ case kX87SubPair: { ++ // i.OutputRegister(0) == i.InputRegister(0) ... left low word. ++ // i.InputRegister(1) ... left high word. ++ // i.InputRegister(2) ... right low word. ++ // i.InputRegister(3) ... right high word. ++ bool use_temp = false; ++ if (i.OutputRegister(0).code() == i.InputRegister(1).code() || ++ i.OutputRegister(0).code() == i.InputRegister(3).code()) { ++ // We cannot write to the output register directly, because it would ++ // overwrite an input for adc. We have to use the temp register. ++ use_temp = true; ++ __ Move(i.TempRegister(0), i.InputRegister(0)); ++ __ sub(i.TempRegister(0), i.InputRegister(2)); ++ } else { ++ __ sub(i.OutputRegister(0), i.InputRegister(2)); ++ } ++ if (i.OutputRegister(1).code() != i.InputRegister(1).code()) { ++ __ Move(i.OutputRegister(1), i.InputRegister(1)); ++ } ++ __ sbb(i.OutputRegister(1), Operand(i.InputRegister(3))); ++ if (use_temp) { ++ __ Move(i.OutputRegister(0), i.TempRegister(0)); ++ } ++ break; ++ } ++ case kX87MulPair: { ++ __ imul(i.OutputRegister(1), i.InputOperand(0)); ++ __ mov(i.TempRegister(0), i.InputOperand(1)); ++ __ imul(i.TempRegister(0), i.InputOperand(2)); ++ __ add(i.OutputRegister(1), i.TempRegister(0)); ++ __ mov(i.OutputRegister(0), i.InputOperand(0)); ++ // Multiplies the low words and stores them in eax and edx. ++ __ mul(i.InputRegister(2)); ++ __ add(i.OutputRegister(1), i.TempRegister(0)); ++ ++ break; ++ } ++ case kX87ShlPair: ++ if (HasImmediateInput(instr, 2)) { ++ __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); ++ } else { ++ // Shift has been loaded into CL by the register allocator. ++ __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0)); ++ } ++ break; ++ case kX87ShrPair: ++ if (HasImmediateInput(instr, 2)) { ++ __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); ++ } else { ++ // Shift has been loaded into CL by the register allocator. ++ __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0)); ++ } ++ break; ++ case kX87SarPair: ++ if (HasImmediateInput(instr, 2)) { ++ __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); ++ } else { ++ // Shift has been loaded into CL by the register allocator. ++ __ SarPair_cl(i.InputRegister(1), i.InputRegister(0)); ++ } ++ break; ++ case kX87Ror: ++ if (HasImmediateInput(instr, 1)) { ++ __ ror(i.OutputOperand(), i.InputInt5(1)); ++ } else { ++ __ ror_cl(i.OutputOperand()); ++ } ++ break; ++ case kX87Lzcnt: ++ __ Lzcnt(i.OutputRegister(), i.InputOperand(0)); ++ break; ++ case kX87Popcnt: ++ __ Popcnt(i.OutputRegister(), i.InputOperand(0)); ++ break; ++ case kX87LoadFloat64Constant: { ++ InstructionOperand* source = instr->InputAt(0); ++ InstructionOperand* destination = instr->Output(); ++ DCHECK(source->IsConstant()); ++ X87OperandConverter g(this, nullptr); ++ Constant src_constant = g.ToConstant(source); ++ ++ DCHECK_EQ(Constant::kFloat64, src_constant.type()); ++ uint64_t src = src_constant.ToFloat64().AsUint64(); ++ uint32_t lower = static_cast(src); ++ uint32_t upper = static_cast(src >> 32); ++ if (destination->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ mov(MemOperand(esp, 0), Immediate(lower)); ++ __ mov(MemOperand(esp, kInt32Size), Immediate(upper)); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ UNREACHABLE(); ++ } ++ break; ++ } ++ case kX87Float32Cmp: { ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ FCmp(); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ break; ++ } ++ case kX87Float32Add: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ faddp(); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float32Sub: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fsubp(); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float32Mul: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fmulp(); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float32Div: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fdivp(); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ ++ case kX87Float32Sqrt: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fsqrt(); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ break; ++ } ++ case kX87Float32Abs: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fabs(); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ break; ++ } ++ case kX87Float32Neg: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fchs(); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ break; ++ } ++ case kX87Float32Round: { ++ RoundingMode mode = ++ static_cast(MiscField::decode(instr->opcode())); ++ // Set the correct round mode in x87 control register ++ __ X87SetRC((mode << 10)); ++ ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ InstructionOperand* input = instr->InputAt(0); ++ USE(input); ++ DCHECK(input->IsFPStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(i.InputOperand(0)); ++ } ++ __ frndint(); ++ __ X87SetRC(0x0000); ++ break; ++ } ++ case kX87Float64Add: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ faddp(); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float64Sub: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fsub_d(MemOperand(esp, 0)); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float64Mul: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fmul_d(MemOperand(esp, 0)); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float64Div: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fdiv_d(MemOperand(esp, 0)); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ // Restore the default value of control word. ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float64Mod: { ++ FrameScope frame_scope(&masm_, StackFrame::MANUAL); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ mov(eax, esp); ++ __ PrepareCallCFunction(4, eax); ++ __ fstp(0); ++ __ fld_d(MemOperand(eax, 0)); ++ __ fstp_d(Operand(esp, 1 * kDoubleSize)); ++ __ fld_d(MemOperand(eax, kDoubleSize)); ++ __ fstp_d(Operand(esp, 0)); ++ __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), ++ 4); ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ break; ++ } ++ case kX87Float32Max: { ++ Label compare_swap, done_compare; ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld(1); ++ __ fld(1); ++ __ FCmp(); ++ ++ auto ool = ++ new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister()); ++ __ j(parity_even, ool->entry()); ++ __ j(below, &done_compare, Label::kNear); ++ __ j(above, &compare_swap, Label::kNear); ++ __ push(eax); ++ __ lea(esp, Operand(esp, -kFloatSize)); ++ __ fld(1); ++ __ fstp_s(Operand(esp, 0)); ++ __ mov(eax, MemOperand(esp, 0)); ++ __ and_(eax, Immediate(0x80000000)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ __ pop(eax); ++ __ j(zero, &done_compare, Label::kNear); ++ ++ __ bind(&compare_swap); ++ __ bind(ool->exit()); ++ __ fxch(1); ++ ++ __ bind(&done_compare); ++ __ fstp(0); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ break; ++ } ++ case kX87Float64Max: { ++ Label compare_swap, done_compare; ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fld(1); ++ __ fld(1); ++ __ FCmp(); ++ ++ auto ool = ++ new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister()); ++ __ j(parity_even, ool->entry()); ++ __ j(below, &done_compare, Label::kNear); ++ __ j(above, &compare_swap, Label::kNear); ++ __ push(eax); ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ __ fld(1); ++ __ fstp_d(Operand(esp, 0)); ++ __ mov(eax, MemOperand(esp, 4)); ++ __ and_(eax, Immediate(0x80000000)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ __ pop(eax); ++ __ j(zero, &done_compare, Label::kNear); ++ ++ __ bind(&compare_swap); ++ __ bind(ool->exit()); ++ __ fxch(1); ++ ++ __ bind(&done_compare); ++ __ fstp(0); ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ break; ++ } ++ case kX87Float32Min: { ++ Label compare_swap, done_compare; ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, kFloatSize)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ fld(1); ++ __ fld(1); ++ __ FCmp(); ++ ++ auto ool = ++ new (zone()) OutOfLineLoadFloat32NaN(this, i.OutputDoubleRegister()); ++ __ j(parity_even, ool->entry()); ++ __ j(above, &done_compare, Label::kNear); ++ __ j(below, &compare_swap, Label::kNear); ++ __ push(eax); ++ __ lea(esp, Operand(esp, -kFloatSize)); ++ __ fld(0); ++ __ fstp_s(Operand(esp, 0)); ++ __ mov(eax, MemOperand(esp, 0)); ++ __ and_(eax, Immediate(0x80000000)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ __ pop(eax); ++ __ j(zero, &done_compare, Label::kNear); ++ ++ __ bind(&compare_swap); ++ __ bind(ool->exit()); ++ __ fxch(1); ++ ++ __ bind(&done_compare); ++ __ fstp(0); ++ __ lea(esp, Operand(esp, 2 * kFloatSize)); ++ break; ++ } ++ case kX87Float64Min: { ++ Label compare_swap, done_compare; ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fld(1); ++ __ fld(1); ++ __ FCmp(); ++ ++ auto ool = ++ new (zone()) OutOfLineLoadFloat64NaN(this, i.OutputDoubleRegister()); ++ __ j(parity_even, ool->entry()); ++ __ j(above, &done_compare, Label::kNear); ++ __ j(below, &compare_swap, Label::kNear); ++ __ push(eax); ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ __ fld(0); ++ __ fstp_d(Operand(esp, 0)); ++ __ mov(eax, MemOperand(esp, 4)); ++ __ and_(eax, Immediate(0x80000000)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ __ pop(eax); ++ __ j(zero, &done_compare, Label::kNear); ++ ++ __ bind(&compare_swap); ++ __ bind(ool->exit()); ++ __ fxch(1); ++ ++ __ bind(&done_compare); ++ __ fstp(0); ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ break; ++ } ++ case kX87Float64Abs: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fabs(); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ break; ++ } ++ case kX87Float64Neg: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fchs(); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ break; ++ } ++ case kX87Int32ToFloat32: { ++ InstructionOperand* input = instr->InputAt(0); ++ DCHECK(input->IsRegister() || input->IsStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ if (input->IsRegister()) { ++ Register input_reg = i.InputRegister(0); ++ __ push(input_reg); ++ __ fild_s(Operand(esp, 0)); ++ __ pop(input_reg); ++ } else { ++ __ fild_s(i.InputOperand(0)); ++ } ++ break; ++ } ++ case kX87Uint32ToFloat32: { ++ InstructionOperand* input = instr->InputAt(0); ++ DCHECK(input->IsRegister() || input->IsStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ Label msb_set_src; ++ Label jmp_return; ++ // Put input integer into eax(tmporarilly) ++ __ push(eax); ++ if (input->IsRegister()) ++ __ mov(eax, i.InputRegister(0)); ++ else ++ __ mov(eax, i.InputOperand(0)); ++ ++ __ test(eax, eax); ++ __ j(sign, &msb_set_src, Label::kNear); ++ __ push(eax); ++ __ fild_s(Operand(esp, 0)); ++ __ pop(eax); ++ ++ __ jmp(&jmp_return, Label::kNear); ++ __ bind(&msb_set_src); ++ // Need another temp reg ++ __ push(ebx); ++ __ mov(ebx, eax); ++ __ shr(eax, 1); ++ // Recover the least significant bit to avoid rounding errors. ++ __ and_(ebx, Immediate(1)); ++ __ or_(eax, ebx); ++ __ push(eax); ++ __ fild_s(Operand(esp, 0)); ++ __ pop(eax); ++ __ fld(0); ++ __ faddp(); ++ // Restore the ebx ++ __ pop(ebx); ++ __ bind(&jmp_return); ++ // Restore the eax ++ __ pop(eax); ++ break; ++ } ++ case kX87Int32ToFloat64: { ++ InstructionOperand* input = instr->InputAt(0); ++ DCHECK(input->IsRegister() || input->IsStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ if (input->IsRegister()) { ++ Register input_reg = i.InputRegister(0); ++ __ push(input_reg); ++ __ fild_s(Operand(esp, 0)); ++ __ pop(input_reg); ++ } else { ++ __ fild_s(i.InputOperand(0)); ++ } ++ break; ++ } ++ case kX87Float32ToFloat64: { ++ InstructionOperand* input = instr->InputAt(0); ++ if (input->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ DCHECK(input->IsFPStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(i.InputOperand(0)); ++ } ++ break; ++ } ++ case kX87Uint32ToFloat64: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ LoadUint32NoSSE2(i.InputRegister(0)); ++ break; ++ } ++ case kX87Float32ToInt32: { ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fld_s(i.InputOperand(0)); ++ } ++ __ TruncateX87TOSToI(i.OutputRegister(0)); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fstp(0); ++ } ++ break; ++ } ++ case kX87Float32ToUint32: { ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fld_s(i.InputOperand(0)); ++ } ++ Label success; ++ __ TruncateX87TOSToI(i.OutputRegister(0)); ++ __ test(i.OutputRegister(0), i.OutputRegister(0)); ++ __ j(positive, &success); ++ // Need to reserve the input float32 data. ++ __ fld(0); ++ __ push(Immediate(INT32_MIN)); ++ __ fild_s(Operand(esp, 0)); ++ __ lea(esp, Operand(esp, kPointerSize)); ++ __ faddp(); ++ __ TruncateX87TOSToI(i.OutputRegister(0)); ++ __ or_(i.OutputRegister(0), Immediate(0x80000000)); ++ // Only keep input float32 data in x87 stack when return. ++ __ fstp(0); ++ __ bind(&success); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fstp(0); ++ } ++ break; ++ } ++ case kX87Float64ToInt32: { ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fld_d(i.InputOperand(0)); ++ } ++ __ TruncateX87TOSToI(i.OutputRegister(0)); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fstp(0); ++ } ++ break; ++ } ++ case kX87Float64ToFloat32: { ++ InstructionOperand* input = instr->InputAt(0); ++ if (input->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ DCHECK(input->IsFPStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(i.InputOperand(0)); ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fstp_s(MemOperand(esp, 0)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } ++ break; ++ } ++ case kX87Float64ToUint32: { ++ __ push_imm32(-2147483648); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fld_d(i.InputOperand(0)); ++ } ++ __ fild_s(Operand(esp, 0)); ++ __ fld(1); ++ __ faddp(); ++ __ TruncateX87TOSToI(i.OutputRegister(0)); ++ __ add(esp, Immediate(kInt32Size)); ++ __ add(i.OutputRegister(), Immediate(0x80000000)); ++ __ fstp(0); ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ __ fstp(0); ++ } ++ break; ++ } ++ case kX87Float64ExtractHighWord32: { ++ if (instr->InputAt(0)->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fst_d(MemOperand(esp, 0)); ++ __ mov(i.OutputRegister(), MemOperand(esp, kDoubleSize / 2)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ InstructionOperand* input = instr->InputAt(0); ++ USE(input); ++ DCHECK(input->IsFPStackSlot()); ++ __ mov(i.OutputRegister(), i.InputOperand(0, kDoubleSize / 2)); ++ } ++ break; ++ } ++ case kX87Float64ExtractLowWord32: { ++ if (instr->InputAt(0)->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fst_d(MemOperand(esp, 0)); ++ __ mov(i.OutputRegister(), MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ InstructionOperand* input = instr->InputAt(0); ++ USE(input); ++ DCHECK(input->IsFPStackSlot()); ++ __ mov(i.OutputRegister(), i.InputOperand(0)); ++ } ++ break; ++ } ++ case kX87Float64InsertHighWord32: { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fstp_d(MemOperand(esp, 0)); ++ __ mov(MemOperand(esp, kDoubleSize / 2), i.InputRegister(1)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ break; ++ } ++ case kX87Float64InsertLowWord32: { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fstp_d(MemOperand(esp, 0)); ++ __ mov(MemOperand(esp, 0), i.InputRegister(1)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ break; ++ } ++ case kX87Float64Sqrt: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ X87SetFPUCW(0x027F); ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ fsqrt(); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ __ X87SetFPUCW(0x037F); ++ break; ++ } ++ case kX87Float64Round: { ++ RoundingMode mode = ++ static_cast(MiscField::decode(instr->opcode())); ++ // Set the correct round mode in x87 control register ++ __ X87SetRC((mode << 10)); ++ ++ if (!instr->InputAt(0)->IsFPRegister()) { ++ InstructionOperand* input = instr->InputAt(0); ++ USE(input); ++ DCHECK(input->IsFPStackSlot()); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(i.InputOperand(0)); ++ } ++ __ frndint(); ++ __ X87SetRC(0x0000); ++ break; ++ } ++ case kX87Float64Cmp: { ++ __ fld_d(MemOperand(esp, kDoubleSize)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ FCmp(); ++ __ lea(esp, Operand(esp, 2 * kDoubleSize)); ++ break; ++ } ++ case kX87Float64SilenceNaN: { ++ Label end, return_qnan; ++ __ fstp(0); ++ __ push(ebx); ++ // Load Half word of HoleNan(SNaN) into ebx ++ __ mov(ebx, MemOperand(esp, 2 * kInt32Size)); ++ __ cmp(ebx, Immediate(kHoleNanUpper32)); ++ // Check input is HoleNaN(SNaN)? ++ __ j(equal, &return_qnan, Label::kNear); ++ // If input isn't HoleNaN(SNaN), just load it and return ++ __ fld_d(MemOperand(esp, 1 * kInt32Size)); ++ __ jmp(&end); ++ __ bind(&return_qnan); ++ // If input is HoleNaN(SNaN), Return QNaN ++ __ push(Immediate(0xffffffff)); ++ __ push(Immediate(0xfff7ffff)); ++ __ fld_d(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kDoubleSize)); ++ __ bind(&end); ++ __ pop(ebx); ++ // Clear stack. ++ __ lea(esp, Operand(esp, 1 * kDoubleSize)); ++ break; ++ } ++ case kX87Movsxbl: ++ __ movsx_b(i.OutputRegister(), i.MemoryOperand()); ++ break; ++ case kX87Movzxbl: ++ __ movzx_b(i.OutputRegister(), i.MemoryOperand()); ++ break; ++ case kX87Movb: { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ if (HasImmediateInput(instr, index)) { ++ __ mov_b(operand, i.InputInt8(index)); ++ } else { ++ __ mov_b(operand, i.InputRegister(index)); ++ } ++ break; ++ } ++ case kX87Movsxwl: ++ __ movsx_w(i.OutputRegister(), i.MemoryOperand()); ++ break; ++ case kX87Movzxwl: ++ __ movzx_w(i.OutputRegister(), i.MemoryOperand()); ++ break; ++ case kX87Movw: { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ if (HasImmediateInput(instr, index)) { ++ __ mov_w(operand, i.InputInt16(index)); ++ } else { ++ __ mov_w(operand, i.InputRegister(index)); ++ } ++ break; ++ } ++ case kX87Movl: ++ if (instr->HasOutput()) { ++ __ mov(i.OutputRegister(), i.MemoryOperand()); ++ } else { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ if (HasImmediateInput(instr, index)) { ++ __ mov(operand, i.InputImmediate(index)); ++ } else { ++ __ mov(operand, i.InputRegister(index)); ++ } ++ } ++ break; ++ case kX87Movsd: { ++ if (instr->HasOutput()) { ++ X87Register output = i.OutputDoubleRegister(); ++ USE(output); ++ DCHECK(output.code() == 0); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_d(i.MemoryOperand()); ++ } else { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ __ fst_d(operand); ++ } ++ break; ++ } ++ case kX87Movss: { ++ if (instr->HasOutput()) { ++ X87Register output = i.OutputDoubleRegister(); ++ USE(output); ++ DCHECK(output.code() == 0); ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ __ fld_s(i.MemoryOperand()); ++ } else { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ __ fst_s(operand); ++ } ++ break; ++ } ++ case kX87BitcastFI: { ++ __ mov(i.OutputRegister(), MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ break; ++ } ++ case kX87BitcastIF: { ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ __ fstp(0); ++ if (instr->InputAt(0)->IsRegister()) { ++ __ lea(esp, Operand(esp, -kFloatSize)); ++ __ mov(MemOperand(esp, 0), i.InputRegister(0)); ++ __ fld_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kFloatSize)); ++ } else { ++ __ fld_s(i.InputOperand(0)); ++ } ++ break; ++ } ++ case kX87Lea: { ++ AddressingMode mode = AddressingModeField::decode(instr->opcode()); ++ // Shorten "leal" to "addl", "subl" or "shll" if the register allocation ++ // and addressing mode just happens to work out. The "addl"/"subl" forms ++ // in these cases are faster based on measurements. ++ if (mode == kMode_MI) { ++ __ Move(i.OutputRegister(), Immediate(i.InputInt32(0))); ++ } else if (i.InputRegister(0).is(i.OutputRegister())) { ++ if (mode == kMode_MRI) { ++ int32_t constant_summand = i.InputInt32(1); ++ if (constant_summand > 0) { ++ __ add(i.OutputRegister(), Immediate(constant_summand)); ++ } else if (constant_summand < 0) { ++ __ sub(i.OutputRegister(), Immediate(-constant_summand)); ++ } ++ } else if (mode == kMode_MR1) { ++ if (i.InputRegister(1).is(i.OutputRegister())) { ++ __ shl(i.OutputRegister(), 1); ++ } else { ++ __ add(i.OutputRegister(), i.InputRegister(1)); ++ } ++ } else if (mode == kMode_M2) { ++ __ shl(i.OutputRegister(), 1); ++ } else if (mode == kMode_M4) { ++ __ shl(i.OutputRegister(), 2); ++ } else if (mode == kMode_M8) { ++ __ shl(i.OutputRegister(), 3); ++ } else { ++ __ lea(i.OutputRegister(), i.MemoryOperand()); ++ } ++ } else if (mode == kMode_MR1 && ++ i.InputRegister(1).is(i.OutputRegister())) { ++ __ add(i.OutputRegister(), i.InputRegister(0)); ++ } else { ++ __ lea(i.OutputRegister(), i.MemoryOperand()); ++ } ++ break; ++ } ++ case kX87Push: ++ if (instr->InputAt(0)->IsFPRegister()) { ++ auto allocated = AllocatedOperand::cast(*instr->InputAt(0)); ++ if (allocated.representation() == MachineRepresentation::kFloat32) { ++ __ sub(esp, Immediate(kFloatSize)); ++ __ fst_s(Operand(esp, 0)); ++ frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize); ++ } else { ++ DCHECK(allocated.representation() == MachineRepresentation::kFloat64); ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fst_d(Operand(esp, 0)); ++ frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); ++ } ++ } else if (instr->InputAt(0)->IsFPStackSlot()) { ++ auto allocated = AllocatedOperand::cast(*instr->InputAt(0)); ++ if (allocated.representation() == MachineRepresentation::kFloat32) { ++ __ sub(esp, Immediate(kFloatSize)); ++ __ fld_s(i.InputOperand(0)); ++ __ fstp_s(MemOperand(esp, 0)); ++ frame_access_state()->IncreaseSPDelta(kFloatSize / kPointerSize); ++ } else { ++ DCHECK(allocated.representation() == MachineRepresentation::kFloat64); ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ fld_d(i.InputOperand(0)); ++ __ fstp_d(MemOperand(esp, 0)); ++ frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); ++ } ++ } else if (HasImmediateInput(instr, 0)) { ++ __ push(i.InputImmediate(0)); ++ frame_access_state()->IncreaseSPDelta(1); ++ } else { ++ __ push(i.InputOperand(0)); ++ frame_access_state()->IncreaseSPDelta(1); ++ } ++ break; ++ case kX87Poke: { ++ int const slot = MiscField::decode(instr->opcode()); ++ if (HasImmediateInput(instr, 0)) { ++ __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0)); ++ } else { ++ __ mov(Operand(esp, slot * kPointerSize), i.InputRegister(0)); ++ } ++ break; ++ } ++ case kX87Xchgb: { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ __ xchg_b(i.InputRegister(index), operand); ++ break; ++ } ++ case kX87Xchgw: { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ __ xchg_w(i.InputRegister(index), operand); ++ break; ++ } ++ case kX87Xchgl: { ++ size_t index = 0; ++ Operand operand = i.MemoryOperand(&index); ++ __ xchg(i.InputRegister(index), operand); ++ break; ++ } ++ case kX87PushFloat32: ++ __ lea(esp, Operand(esp, -kFloatSize)); ++ if (instr->InputAt(0)->IsFPStackSlot()) { ++ __ fld_s(i.InputOperand(0)); ++ __ fstp_s(MemOperand(esp, 0)); ++ } else if (instr->InputAt(0)->IsFPRegister()) { ++ __ fst_s(MemOperand(esp, 0)); ++ } else { ++ UNREACHABLE(); ++ } ++ break; ++ case kX87PushFloat64: ++ __ lea(esp, Operand(esp, -kDoubleSize)); ++ if (instr->InputAt(0)->IsFPStackSlot()) { ++ __ fld_d(i.InputOperand(0)); ++ __ fstp_d(MemOperand(esp, 0)); ++ } else if (instr->InputAt(0)->IsFPRegister()) { ++ __ fst_d(MemOperand(esp, 0)); ++ } else { ++ UNREACHABLE(); ++ } ++ break; ++ case kCheckedLoadInt8: ++ ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_b); ++ break; ++ case kCheckedLoadUint8: ++ ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_b); ++ break; ++ case kCheckedLoadInt16: ++ ASSEMBLE_CHECKED_LOAD_INTEGER(movsx_w); ++ break; ++ case kCheckedLoadUint16: ++ ASSEMBLE_CHECKED_LOAD_INTEGER(movzx_w); ++ break; ++ case kCheckedLoadWord32: ++ ASSEMBLE_CHECKED_LOAD_INTEGER(mov); ++ break; ++ case kCheckedLoadFloat32: ++ ASSEMBLE_CHECKED_LOAD_FLOAT(fld_s, OutOfLineLoadFloat32NaN); ++ break; ++ case kCheckedLoadFloat64: ++ ASSEMBLE_CHECKED_LOAD_FLOAT(fld_d, OutOfLineLoadFloat64NaN); ++ break; ++ case kCheckedStoreWord8: ++ ASSEMBLE_CHECKED_STORE_INTEGER(mov_b); ++ break; ++ case kCheckedStoreWord16: ++ ASSEMBLE_CHECKED_STORE_INTEGER(mov_w); ++ break; ++ case kCheckedStoreWord32: ++ ASSEMBLE_CHECKED_STORE_INTEGER(mov); ++ break; ++ case kCheckedStoreFloat32: ++ ASSEMBLE_CHECKED_STORE_FLOAT(fst_s); ++ break; ++ case kCheckedStoreFloat64: ++ ASSEMBLE_CHECKED_STORE_FLOAT(fst_d); ++ break; ++ case kX87StackCheck: { ++ ExternalReference const stack_limit = ++ ExternalReference::address_of_stack_limit(isolate()); ++ __ cmp(esp, Operand::StaticVariable(stack_limit)); ++ break; ++ } ++ case kCheckedLoadWord64: ++ case kCheckedStoreWord64: ++ UNREACHABLE(); // currently unsupported checked int64 load/store. ++ break; ++ case kAtomicLoadInt8: ++ case kAtomicLoadUint8: ++ case kAtomicLoadInt16: ++ case kAtomicLoadUint16: ++ case kAtomicLoadWord32: ++ case kAtomicStoreWord8: ++ case kAtomicStoreWord16: ++ case kAtomicStoreWord32: ++ UNREACHABLE(); // Won't be generated by instruction selector. ++ break; ++ } ++ return kSuccess; ++} // NOLINT(readability/fn_size) ++ ++static Condition FlagsConditionToCondition(FlagsCondition condition) { ++ switch (condition) { ++ case kUnorderedEqual: ++ case kEqual: ++ return equal; ++ break; ++ case kUnorderedNotEqual: ++ case kNotEqual: ++ return not_equal; ++ break; ++ case kSignedLessThan: ++ return less; ++ break; ++ case kSignedGreaterThanOrEqual: ++ return greater_equal; ++ break; ++ case kSignedLessThanOrEqual: ++ return less_equal; ++ break; ++ case kSignedGreaterThan: ++ return greater; ++ break; ++ case kUnsignedLessThan: ++ return below; ++ break; ++ case kUnsignedGreaterThanOrEqual: ++ return above_equal; ++ break; ++ case kUnsignedLessThanOrEqual: ++ return below_equal; ++ break; ++ case kUnsignedGreaterThan: ++ return above; ++ break; ++ case kOverflow: ++ return overflow; ++ break; ++ case kNotOverflow: ++ return no_overflow; ++ break; ++ default: ++ UNREACHABLE(); ++ break; ++ } ++} ++ ++// Assembles a branch after an instruction. ++void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) { ++ Label::Distance flabel_distance = ++ branch->fallthru ? Label::kNear : Label::kFar; ++ ++ Label done; ++ Label tlabel_tmp; ++ Label flabel_tmp; ++ Label* tlabel = &tlabel_tmp; ++ Label* flabel = &flabel_tmp; ++ ++ Label* tlabel_dst = branch->true_label; ++ Label* flabel_dst = branch->false_label; ++ ++ if (branch->condition == kUnorderedEqual) { ++ __ j(parity_even, flabel, flabel_distance); ++ } else if (branch->condition == kUnorderedNotEqual) { ++ __ j(parity_even, tlabel); ++ } ++ __ j(FlagsConditionToCondition(branch->condition), tlabel); ++ ++ // Add a jump if not falling through to the next block. ++ if (!branch->fallthru) __ jmp(flabel); ++ ++ __ jmp(&done); ++ __ bind(&tlabel_tmp); ++ FlagsMode mode = FlagsModeField::decode(instr->opcode()); ++ if (mode == kFlags_deoptimize) { ++ int double_register_param_count = 0; ++ int x87_layout = 0; ++ for (size_t i = 0; i < instr->InputCount(); i++) { ++ if (instr->InputAt(i)->IsFPRegister()) { ++ double_register_param_count++; ++ } ++ } ++ // Currently we use only one X87 register. If double_register_param_count ++ // is bigger than 1, it means duplicated double register is added to input ++ // of this instruction. ++ if (double_register_param_count > 0) { ++ x87_layout = (0 << 3) | 1; ++ } ++ // The layout of x87 register stack is loaded on the top of FPU register ++ // stack for deoptimization. ++ __ push(Immediate(x87_layout)); ++ __ fild_s(MemOperand(esp, 0)); ++ __ lea(esp, Operand(esp, kPointerSize)); ++ } ++ __ jmp(tlabel_dst); ++ __ bind(&flabel_tmp); ++ __ jmp(flabel_dst); ++ __ bind(&done); ++} ++ ++ ++void CodeGenerator::AssembleArchJump(RpoNumber target) { ++ if (!IsNextInAssemblyOrder(target)) __ jmp(GetLabel(target)); ++} ++ ++void CodeGenerator::AssembleArchTrap(Instruction* instr, ++ FlagsCondition condition) { ++ class OutOfLineTrap final : public OutOfLineCode { ++ public: ++ OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr) ++ : OutOfLineCode(gen), ++ frame_elided_(frame_elided), ++ instr_(instr), ++ gen_(gen) {} ++ ++ void Generate() final { ++ X87OperandConverter i(gen_, instr_); ++ ++ Runtime::FunctionId trap_id = static_cast( ++ i.InputInt32(instr_->InputCount() - 1)); ++ bool old_has_frame = __ has_frame(); ++ if (frame_elided_) { ++ __ set_has_frame(true); ++ __ EnterFrame(StackFrame::WASM_COMPILED); ++ } ++ GenerateCallToTrap(trap_id); ++ if (frame_elided_) { ++ ReferenceMap* reference_map = ++ new (gen_->zone()) ReferenceMap(gen_->zone()); ++ gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0, ++ Safepoint::kNoLazyDeopt); ++ __ set_has_frame(old_has_frame); ++ } ++ if (FLAG_debug_code) { ++ __ ud2(); ++ } ++ } ++ ++ private: ++ void GenerateCallToTrap(Runtime::FunctionId trap_id) { ++ if (trap_id == Runtime::kNumFunctions) { ++ // We cannot test calls to the runtime in cctest/test-run-wasm. ++ // Therefore we emit a call to C here instead of a call to the runtime. ++ __ PrepareCallCFunction(0, esi); ++ __ CallCFunction( ++ ExternalReference::wasm_call_trap_callback_for_testing(isolate()), ++ 0); ++ } else { ++ __ Move(esi, isolate()->native_context()); ++ gen_->AssembleSourcePosition(instr_); ++ __ CallRuntime(trap_id); ++ } ++ } ++ ++ bool frame_elided_; ++ Instruction* instr_; ++ CodeGenerator* gen_; ++ }; ++ bool frame_elided = !frame_access_state()->has_frame(); ++ auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr); ++ Label* tlabel = ool->entry(); ++ Label end; ++ if (condition == kUnorderedEqual) { ++ __ j(parity_even, &end); ++ } else if (condition == kUnorderedNotEqual) { ++ __ j(parity_even, tlabel); ++ } ++ __ j(FlagsConditionToCondition(condition), tlabel); ++ __ bind(&end); ++} ++ ++// Assembles boolean materializations after an instruction. ++void CodeGenerator::AssembleArchBoolean(Instruction* instr, ++ FlagsCondition condition) { ++ X87OperandConverter i(this, instr); ++ Label done; ++ ++ // Materialize a full 32-bit 1 or 0 value. The result register is always the ++ // last output of the instruction. ++ Label check; ++ DCHECK_NE(0u, instr->OutputCount()); ++ Register reg = i.OutputRegister(instr->OutputCount() - 1); ++ if (condition == kUnorderedEqual) { ++ __ j(parity_odd, &check, Label::kNear); ++ __ Move(reg, Immediate(0)); ++ __ jmp(&done, Label::kNear); ++ } else if (condition == kUnorderedNotEqual) { ++ __ j(parity_odd, &check, Label::kNear); ++ __ mov(reg, Immediate(1)); ++ __ jmp(&done, Label::kNear); ++ } ++ Condition cc = FlagsConditionToCondition(condition); ++ ++ __ bind(&check); ++ if (reg.is_byte_register()) { ++ // setcc for byte registers (al, bl, cl, dl). ++ __ setcc(cc, reg); ++ __ movzx_b(reg, reg); ++ } else { ++ // Emit a branch to set a register to either 1 or 0. ++ Label set; ++ __ j(cc, &set, Label::kNear); ++ __ Move(reg, Immediate(0)); ++ __ jmp(&done, Label::kNear); ++ __ bind(&set); ++ __ mov(reg, Immediate(1)); ++ } ++ __ bind(&done); ++} ++ ++ ++void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) { ++ X87OperandConverter i(this, instr); ++ Register input = i.InputRegister(0); ++ for (size_t index = 2; index < instr->InputCount(); index += 2) { ++ __ cmp(input, Immediate(i.InputInt32(index + 0))); ++ __ j(equal, GetLabel(i.InputRpo(index + 1))); ++ } ++ AssembleArchJump(i.InputRpo(1)); ++} ++ ++ ++void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) { ++ X87OperandConverter i(this, instr); ++ Register input = i.InputRegister(0); ++ size_t const case_count = instr->InputCount() - 2; ++ Label** cases = zone()->NewArray(case_count); ++ for (size_t index = 0; index < case_count; ++index) { ++ cases[index] = GetLabel(i.InputRpo(index + 2)); ++ } ++ Label* const table = AddJumpTable(cases, case_count); ++ __ cmp(input, Immediate(case_count)); ++ __ j(above_equal, GetLabel(i.InputRpo(1))); ++ __ jmp(Operand::JumpTable(input, times_4, table)); ++} ++ ++CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( ++ int deoptimization_id, SourcePosition pos) { ++ DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id); ++ DeoptimizeReason deoptimization_reason = ++ GetDeoptimizationReason(deoptimization_id); ++ Deoptimizer::BailoutType bailout_type = ++ deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT ++ : Deoptimizer::EAGER; ++ Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( ++ isolate(), deoptimization_id, bailout_type); ++ if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts; ++ __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id); ++ __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY); ++ return kSuccess; ++} ++ ++ ++// The calling convention for JSFunctions on X87 passes arguments on the ++// stack and the JSFunction and context in EDI and ESI, respectively, thus ++// the steps of the call look as follows: ++ ++// --{ before the call instruction }-------------------------------------------- ++// | caller frame | ++// ^ esp ^ ebp ++ ++// --{ push arguments and setup ESI, EDI }-------------------------------------- ++// | args + receiver | caller frame | ++// ^ esp ^ ebp ++// [edi = JSFunction, esi = context] ++ ++// --{ call [edi + kCodeEntryOffset] }------------------------------------------ ++// | RET | args + receiver | caller frame | ++// ^ esp ^ ebp ++ ++// =={ prologue of called function }============================================ ++// --{ push ebp }--------------------------------------------------------------- ++// | FP | RET | args + receiver | caller frame | ++// ^ esp ^ ebp ++ ++// --{ mov ebp, esp }----------------------------------------------------------- ++// | FP | RET | args + receiver | caller frame | ++// ^ ebp,esp ++ ++// --{ push esi }--------------------------------------------------------------- ++// | CTX | FP | RET | args + receiver | caller frame | ++// ^esp ^ ebp ++ ++// --{ push edi }--------------------------------------------------------------- ++// | FNC | CTX | FP | RET | args + receiver | caller frame | ++// ^esp ^ ebp ++ ++// --{ subi esp, #N }----------------------------------------------------------- ++// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame | ++// ^esp ^ ebp ++ ++// =={ body of called function }================================================ ++ ++// =={ epilogue of called function }============================================ ++// --{ mov esp, ebp }----------------------------------------------------------- ++// | FP | RET | args + receiver | caller frame | ++// ^ esp,ebp ++ ++// --{ pop ebp }----------------------------------------------------------- ++// | | RET | args + receiver | caller frame | ++// ^ esp ^ ebp ++ ++// --{ ret #A+1 }----------------------------------------------------------- ++// | | caller frame | ++// ^ esp ^ ebp ++ ++ ++// Runtime function calls are accomplished by doing a stub call to the ++// CEntryStub (a real code object). On X87 passes arguments on the ++// stack, the number of arguments in EAX, the address of the runtime function ++// in EBX, and the context in ESI. ++ ++// --{ before the call instruction }-------------------------------------------- ++// | caller frame | ++// ^ esp ^ ebp ++ ++// --{ push arguments and setup EAX, EBX, and ESI }----------------------------- ++// | args + receiver | caller frame | ++// ^ esp ^ ebp ++// [eax = #args, ebx = runtime function, esi = context] ++ ++// --{ call #CEntryStub }------------------------------------------------------- ++// | RET | args + receiver | caller frame | ++// ^ esp ^ ebp ++ ++// =={ body of runtime function }=============================================== ++ ++// --{ runtime returns }-------------------------------------------------------- ++// | caller frame | ++// ^ esp ^ ebp ++ ++// Other custom linkages (e.g. for calling directly into and out of C++) may ++// need to save callee-saved registers on the stack, which is done in the ++// function prologue of generated code. ++ ++// --{ before the call instruction }-------------------------------------------- ++// | caller frame | ++// ^ esp ^ ebp ++ ++// --{ set up arguments in registers on stack }--------------------------------- ++// | args | caller frame | ++// ^ esp ^ ebp ++// [r0 = arg0, r1 = arg1, ...] ++ ++// --{ call code }-------------------------------------------------------------- ++// | RET | args | caller frame | ++// ^ esp ^ ebp ++ ++// =={ prologue of called function }============================================ ++// --{ push ebp }--------------------------------------------------------------- ++// | FP | RET | args | caller frame | ++// ^ esp ^ ebp ++ ++// --{ mov ebp, esp }----------------------------------------------------------- ++// | FP | RET | args | caller frame | ++// ^ ebp,esp ++ ++// --{ save registers }--------------------------------------------------------- ++// | regs | FP | RET | args | caller frame | ++// ^ esp ^ ebp ++ ++// --{ subi esp, #N }----------------------------------------------------------- ++// | callee frame | regs | FP | RET | args | caller frame | ++// ^esp ^ ebp ++ ++// =={ body of called function }================================================ ++ ++// =={ epilogue of called function }============================================ ++// --{ restore registers }------------------------------------------------------ ++// | regs | FP | RET | args | caller frame | ++// ^ esp ^ ebp ++ ++// --{ mov esp, ebp }----------------------------------------------------------- ++// | FP | RET | args | caller frame | ++// ^ esp,ebp ++ ++// --{ pop ebp }---------------------------------------------------------------- ++// | RET | args | caller frame | ++// ^ esp ^ ebp ++ ++void CodeGenerator::FinishFrame(Frame* frame) { ++ CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); ++ const RegList saves = descriptor->CalleeSavedRegisters(); ++ if (saves != 0) { // Save callee-saved registers. ++ DCHECK(!info()->is_osr()); ++ int pushed = 0; ++ for (int i = Register::kNumRegisters - 1; i >= 0; i--) { ++ if (!((1 << i) & saves)) continue; ++ ++pushed; ++ } ++ frame->AllocateSavedCalleeRegisterSlots(pushed); ++ } ++ ++ // Initailize FPU state. ++ __ fninit(); ++ __ fld1(); ++} ++ ++void CodeGenerator::AssembleConstructFrame() { ++ CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); ++ if (frame_access_state()->has_frame()) { ++ if (descriptor->IsCFunctionCall()) { ++ __ push(ebp); ++ __ mov(ebp, esp); ++ } else if (descriptor->IsJSFunctionCall()) { ++ __ Prologue(this->info()->GeneratePreagedPrologue()); ++ if (descriptor->PushArgumentCount()) { ++ __ push(kJavaScriptCallArgCountRegister); ++ } ++ } else { ++ __ StubPrologue(info()->GetOutputStackFrameType()); ++ } ++ } ++ ++ int shrink_slots = ++ frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize(); ++ ++ if (info()->is_osr()) { ++ // TurboFan OSR-compiled functions cannot be entered directly. ++ __ Abort(kShouldNotDirectlyEnterOsrFunction); ++ ++ // Unoptimized code jumps directly to this entrypoint while the unoptimized ++ // frame is still on the stack. Optimized code uses OSR values directly from ++ // the unoptimized frame. Thus, all that needs to be done is to allocate the ++ // remaining stack slots. ++ if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); ++ osr_pc_offset_ = __ pc_offset(); ++ shrink_slots -= osr_helper()->UnoptimizedFrameSlots(); ++ ++ // Initailize FPU state. ++ __ fninit(); ++ __ fld1(); ++ } ++ ++ const RegList saves = descriptor->CalleeSavedRegisters(); ++ if (shrink_slots > 0) { ++ __ sub(esp, Immediate(shrink_slots * kPointerSize)); ++ } ++ ++ if (saves != 0) { // Save callee-saved registers. ++ DCHECK(!info()->is_osr()); ++ int pushed = 0; ++ for (int i = Register::kNumRegisters - 1; i >= 0; i--) { ++ if (!((1 << i) & saves)) continue; ++ __ push(Register::from_code(i)); ++ ++pushed; ++ } ++ } ++} ++ ++void CodeGenerator::AssembleReturn(InstructionOperand* pop) { ++ CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); ++ ++ // Clear the FPU stack only if there is no return value in the stack. ++ if (FLAG_debug_code && FLAG_enable_slow_asserts) { ++ __ VerifyX87StackDepth(1); ++ } ++ bool clear_stack = true; ++ for (size_t i = 0; i < descriptor->ReturnCount(); i++) { ++ MachineRepresentation rep = descriptor->GetReturnType(i).representation(); ++ LinkageLocation loc = descriptor->GetReturnLocation(i); ++ if (IsFloatingPoint(rep) && loc == LinkageLocation::ForRegister(0)) { ++ clear_stack = false; ++ break; ++ } ++ } ++ if (clear_stack) __ fstp(0); ++ ++ const RegList saves = descriptor->CalleeSavedRegisters(); ++ // Restore registers. ++ if (saves != 0) { ++ for (int i = 0; i < Register::kNumRegisters; i++) { ++ if (!((1 << i) & saves)) continue; ++ __ pop(Register::from_code(i)); ++ } ++ } ++ ++ // Might need ecx for scratch if pop_size is too big or if there is a variable ++ // pop count. ++ DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit()); ++ size_t pop_size = descriptor->StackParameterCount() * kPointerSize; ++ X87OperandConverter g(this, nullptr); ++ if (descriptor->IsCFunctionCall()) { ++ AssembleDeconstructFrame(); ++ } else if (frame_access_state()->has_frame()) { ++ // Canonicalize JSFunction return sites for now if they always have the same ++ // number of return args. ++ if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) { ++ if (return_label_.is_bound()) { ++ __ jmp(&return_label_); ++ return; ++ } else { ++ __ bind(&return_label_); ++ AssembleDeconstructFrame(); ++ } ++ } else { ++ AssembleDeconstructFrame(); ++ } ++ } ++ DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & edx.bit()); ++ DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit()); ++ if (pop->IsImmediate()) { ++ DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type()); ++ pop_size += g.ToConstant(pop).ToInt32() * kPointerSize; ++ __ Ret(static_cast(pop_size), ecx); ++ } else { ++ Register pop_reg = g.ToRegister(pop); ++ Register scratch_reg = pop_reg.is(ecx) ? edx : ecx; ++ __ pop(scratch_reg); ++ __ lea(esp, Operand(esp, pop_reg, times_4, static_cast(pop_size))); ++ __ jmp(scratch_reg); ++ } ++} ++ ++void CodeGenerator::FinishCode() {} ++ ++void CodeGenerator::AssembleMove(InstructionOperand* source, ++ InstructionOperand* destination) { ++ X87OperandConverter g(this, nullptr); ++ // Dispatch on the source and destination operand kinds. Not all ++ // combinations are possible. ++ if (source->IsRegister()) { ++ DCHECK(destination->IsRegister() || destination->IsStackSlot()); ++ Register src = g.ToRegister(source); ++ Operand dst = g.ToOperand(destination); ++ __ mov(dst, src); ++ } else if (source->IsStackSlot()) { ++ DCHECK(destination->IsRegister() || destination->IsStackSlot()); ++ Operand src = g.ToOperand(source); ++ if (destination->IsRegister()) { ++ Register dst = g.ToRegister(destination); ++ __ mov(dst, src); ++ } else { ++ Operand dst = g.ToOperand(destination); ++ __ push(src); ++ __ pop(dst); ++ } ++ } else if (source->IsConstant()) { ++ Constant src_constant = g.ToConstant(source); ++ if (src_constant.type() == Constant::kHeapObject) { ++ Handle src = src_constant.ToHeapObject(); ++ if (destination->IsRegister()) { ++ Register dst = g.ToRegister(destination); ++ __ LoadHeapObject(dst, src); ++ } else { ++ DCHECK(destination->IsStackSlot()); ++ Operand dst = g.ToOperand(destination); ++ AllowDeferredHandleDereference embedding_raw_address; ++ if (isolate()->heap()->InNewSpace(*src)) { ++ __ PushHeapObject(src); ++ __ pop(dst); ++ } else { ++ __ mov(dst, src); ++ } ++ } ++ } else if (destination->IsRegister()) { ++ Register dst = g.ToRegister(destination); ++ __ Move(dst, g.ToImmediate(source)); ++ } else if (destination->IsStackSlot()) { ++ Operand dst = g.ToOperand(destination); ++ __ Move(dst, g.ToImmediate(source)); ++ } else if (src_constant.type() == Constant::kFloat32) { ++ // TODO(turbofan): Can we do better here? ++ uint32_t src = src_constant.ToFloat32AsInt(); ++ if (destination->IsFPRegister()) { ++ __ sub(esp, Immediate(kInt32Size)); ++ __ mov(MemOperand(esp, 0), Immediate(src)); ++ // always only push one value into the x87 stack. ++ __ fstp(0); ++ __ fld_s(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kInt32Size)); ++ } else { ++ DCHECK(destination->IsFPStackSlot()); ++ Operand dst = g.ToOperand(destination); ++ __ Move(dst, Immediate(src)); ++ } ++ } else { ++ DCHECK_EQ(Constant::kFloat64, src_constant.type()); ++ uint64_t src = src_constant.ToFloat64().AsUint64(); ++ uint32_t lower = static_cast(src); ++ uint32_t upper = static_cast(src >> 32); ++ if (destination->IsFPRegister()) { ++ __ sub(esp, Immediate(kDoubleSize)); ++ __ mov(MemOperand(esp, 0), Immediate(lower)); ++ __ mov(MemOperand(esp, kInt32Size), Immediate(upper)); ++ // always only push one value into the x87 stack. ++ __ fstp(0); ++ __ fld_d(MemOperand(esp, 0)); ++ __ add(esp, Immediate(kDoubleSize)); ++ } else { ++ DCHECK(destination->IsFPStackSlot()); ++ Operand dst0 = g.ToOperand(destination); ++ Operand dst1 = g.HighOperand(destination); ++ __ Move(dst0, Immediate(lower)); ++ __ Move(dst1, Immediate(upper)); ++ } ++ } ++ } else if (source->IsFPRegister()) { ++ DCHECK(destination->IsFPStackSlot()); ++ Operand dst = g.ToOperand(destination); ++ auto allocated = AllocatedOperand::cast(*source); ++ switch (allocated.representation()) { ++ case MachineRepresentation::kFloat32: ++ __ fst_s(dst); ++ break; ++ case MachineRepresentation::kFloat64: ++ __ fst_d(dst); ++ break; ++ default: ++ UNREACHABLE(); ++ } ++ } else if (source->IsFPStackSlot()) { ++ DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot()); ++ Operand src = g.ToOperand(source); ++ auto allocated = AllocatedOperand::cast(*source); ++ if (destination->IsFPRegister()) { ++ // always only push one value into the x87 stack. ++ __ fstp(0); ++ switch (allocated.representation()) { ++ case MachineRepresentation::kFloat32: ++ __ fld_s(src); ++ break; ++ case MachineRepresentation::kFloat64: ++ __ fld_d(src); ++ break; ++ default: ++ UNREACHABLE(); ++ } ++ } else { ++ Operand dst = g.ToOperand(destination); ++ switch (allocated.representation()) { ++ case MachineRepresentation::kFloat32: ++ __ fld_s(src); ++ __ fstp_s(dst); ++ break; ++ case MachineRepresentation::kFloat64: ++ __ fld_d(src); ++ __ fstp_d(dst); ++ break; ++ default: ++ UNREACHABLE(); ++ } ++ } ++ } else { ++ UNREACHABLE(); ++ } ++} ++ ++ ++void CodeGenerator::AssembleSwap(InstructionOperand* source, ++ InstructionOperand* destination) { ++ X87OperandConverter g(this, nullptr); ++ // Dispatch on the source and destination operand kinds. Not all ++ // combinations are possible. ++ if (source->IsRegister() && destination->IsRegister()) { ++ // Register-register. ++ Register src = g.ToRegister(source); ++ Register dst = g.ToRegister(destination); ++ __ xchg(dst, src); ++ } else if (source->IsRegister() && destination->IsStackSlot()) { ++ // Register-memory. ++ __ xchg(g.ToRegister(source), g.ToOperand(destination)); ++ } else if (source->IsStackSlot() && destination->IsStackSlot()) { ++ // Memory-memory. ++ Operand dst1 = g.ToOperand(destination); ++ __ push(dst1); ++ frame_access_state()->IncreaseSPDelta(1); ++ Operand src1 = g.ToOperand(source); ++ __ push(src1); ++ Operand dst2 = g.ToOperand(destination); ++ __ pop(dst2); ++ frame_access_state()->IncreaseSPDelta(-1); ++ Operand src2 = g.ToOperand(source); ++ __ pop(src2); ++ } else if (source->IsFPRegister() && destination->IsFPRegister()) { ++ UNREACHABLE(); ++ } else if (source->IsFPRegister() && destination->IsFPStackSlot()) { ++ auto allocated = AllocatedOperand::cast(*source); ++ switch (allocated.representation()) { ++ case MachineRepresentation::kFloat32: ++ __ fld_s(g.ToOperand(destination)); ++ __ fxch(); ++ __ fstp_s(g.ToOperand(destination)); ++ break; ++ case MachineRepresentation::kFloat64: ++ __ fld_d(g.ToOperand(destination)); ++ __ fxch(); ++ __ fstp_d(g.ToOperand(destination)); ++ break; ++ default: ++ UNREACHABLE(); ++ } ++ } else if (source->IsFPStackSlot() && destination->IsFPStackSlot()) { ++ auto allocated = AllocatedOperand::cast(*source); ++ switch (allocated.representation()) { ++ case MachineRepresentation::kFloat32: ++ __ fld_s(g.ToOperand(source)); ++ __ fld_s(g.ToOperand(destination)); ++ __ fstp_s(g.ToOperand(source)); ++ __ fstp_s(g.ToOperand(destination)); ++ break; ++ case MachineRepresentation::kFloat64: ++ __ fld_d(g.ToOperand(source)); ++ __ fld_d(g.ToOperand(destination)); ++ __ fstp_d(g.ToOperand(source)); ++ __ fstp_d(g.ToOperand(destination)); ++ break; ++ default: ++ UNREACHABLE(); ++ } ++ } else { ++ // No other combinations are possible. ++ UNREACHABLE(); ++ } ++} ++ ++ ++void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) { ++ for (size_t index = 0; index < target_count; ++index) { ++ __ dd(targets[index]); ++ } ++} ++ ++ ++void CodeGenerator::EnsureSpaceForLazyDeopt() { ++ if (!info()->ShouldEnsureSpaceForLazyDeopt()) { ++ return; ++ } ++ ++ int space_needed = Deoptimizer::patch_size(); ++ // Ensure that we have enough space after the previous lazy-bailout ++ // instruction for patching the code here. ++ int current_pc = masm()->pc_offset(); ++ if (current_pc < last_lazy_deopt_pc_ + space_needed) { ++ int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; ++ __ Nop(padding_size); ++ } ++} ++ ++#undef __ ++ ++} // namespace compiler ++} // namespace internal ++} // namespace v8 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-codes-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-codes-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-codes-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-codes-x87.h 2017-12-25 17:42:57.208465749 +0100 +@@ -0,0 +1,144 @@ ++// Copyright 2014 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_COMPILER_X87_INSTRUCTION_CODES_X87_H_ ++#define V8_COMPILER_X87_INSTRUCTION_CODES_X87_H_ ++ ++#include "src/compiler/instruction.h" ++#include "src/compiler/instruction-codes.h" ++namespace v8 { ++namespace internal { ++namespace compiler { ++ ++// X87-specific opcodes that specify which assembly sequence to emit. ++// Most opcodes specify a single instruction. ++#define TARGET_ARCH_OPCODE_LIST(V) \ ++ V(X87Add) \ ++ V(X87And) \ ++ V(X87Cmp) \ ++ V(X87Cmp16) \ ++ V(X87Cmp8) \ ++ V(X87Test) \ ++ V(X87Test16) \ ++ V(X87Test8) \ ++ V(X87Or) \ ++ V(X87Xor) \ ++ V(X87Sub) \ ++ V(X87Imul) \ ++ V(X87ImulHigh) \ ++ V(X87UmulHigh) \ ++ V(X87Idiv) \ ++ V(X87Udiv) \ ++ V(X87Not) \ ++ V(X87Neg) \ ++ V(X87Shl) \ ++ V(X87Shr) \ ++ V(X87Sar) \ ++ V(X87AddPair) \ ++ V(X87SubPair) \ ++ V(X87MulPair) \ ++ V(X87ShlPair) \ ++ V(X87ShrPair) \ ++ V(X87SarPair) \ ++ V(X87Ror) \ ++ V(X87Lzcnt) \ ++ V(X87Popcnt) \ ++ V(X87Float32Cmp) \ ++ V(X87Float32Add) \ ++ V(X87Float32Sub) \ ++ V(X87Float32Mul) \ ++ V(X87Float32Div) \ ++ V(X87Float32Abs) \ ++ V(X87Float32Neg) \ ++ V(X87Float32Sqrt) \ ++ V(X87Float32Round) \ ++ V(X87LoadFloat64Constant) \ ++ V(X87Float64Add) \ ++ V(X87Float64Sub) \ ++ V(X87Float64Mul) \ ++ V(X87Float64Div) \ ++ V(X87Float64Mod) \ ++ V(X87Float32Max) \ ++ V(X87Float64Max) \ ++ V(X87Float32Min) \ ++ V(X87Float64Min) \ ++ V(X87Float64Abs) \ ++ V(X87Float64Neg) \ ++ V(X87Int32ToFloat32) \ ++ V(X87Uint32ToFloat32) \ ++ V(X87Int32ToFloat64) \ ++ V(X87Float32ToFloat64) \ ++ V(X87Uint32ToFloat64) \ ++ V(X87Float64ToInt32) \ ++ V(X87Float32ToInt32) \ ++ V(X87Float32ToUint32) \ ++ V(X87Float64ToFloat32) \ ++ V(X87Float64ToUint32) \ ++ V(X87Float64ExtractHighWord32) \ ++ V(X87Float64ExtractLowWord32) \ ++ V(X87Float64InsertHighWord32) \ ++ V(X87Float64InsertLowWord32) \ ++ V(X87Float64Sqrt) \ ++ V(X87Float64Round) \ ++ V(X87Float64Cmp) \ ++ V(X87Float64SilenceNaN) \ ++ V(X87Movsxbl) \ ++ V(X87Movzxbl) \ ++ V(X87Movb) \ ++ V(X87Movsxwl) \ ++ V(X87Movzxwl) \ ++ V(X87Movw) \ ++ V(X87Movl) \ ++ V(X87Movss) \ ++ V(X87Movsd) \ ++ V(X87Lea) \ ++ V(X87BitcastFI) \ ++ V(X87BitcastIF) \ ++ V(X87Push) \ ++ V(X87PushFloat64) \ ++ V(X87PushFloat32) \ ++ V(X87Poke) \ ++ V(X87StackCheck) \ ++ V(X87Xchgb) \ ++ V(X87Xchgw) \ ++ V(X87Xchgl) ++ ++// Addressing modes represent the "shape" of inputs to an instruction. ++// Many instructions support multiple addressing modes. Addressing modes ++// are encoded into the InstructionCode of the instruction and tell the ++// code generator after register allocation which assembler method to call. ++// ++// We use the following local notation for addressing modes: ++// ++// M = memory operand ++// R = base register ++// N = index register * N for N in {1, 2, 4, 8} ++// I = immediate displacement (int32_t) ++ ++#define TARGET_ADDRESSING_MODE_LIST(V) \ ++ V(MR) /* [%r1 ] */ \ ++ V(MRI) /* [%r1 + K] */ \ ++ V(MR1) /* [%r1 + %r2*1 ] */ \ ++ V(MR2) /* [%r1 + %r2*2 ] */ \ ++ V(MR4) /* [%r1 + %r2*4 ] */ \ ++ V(MR8) /* [%r1 + %r2*8 ] */ \ ++ V(MR1I) /* [%r1 + %r2*1 + K] */ \ ++ V(MR2I) /* [%r1 + %r2*2 + K] */ \ ++ V(MR4I) /* [%r1 + %r2*3 + K] */ \ ++ V(MR8I) /* [%r1 + %r2*4 + K] */ \ ++ V(M1) /* [ %r2*1 ] */ \ ++ V(M2) /* [ %r2*2 ] */ \ ++ V(M4) /* [ %r2*4 ] */ \ ++ V(M8) /* [ %r2*8 ] */ \ ++ V(M1I) /* [ %r2*1 + K] */ \ ++ V(M2I) /* [ %r2*2 + K] */ \ ++ V(M4I) /* [ %r2*4 + K] */ \ ++ V(M8I) /* [ %r2*8 + K] */ \ ++ V(MI) /* [ K] */ ++ ++} // namespace compiler ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_COMPILER_X87_INSTRUCTION_CODES_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-scheduler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-scheduler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-scheduler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-scheduler-x87.cc 2017-12-25 17:42:57.208465749 +0100 +@@ -0,0 +1,26 @@ ++// Copyright 2015 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "src/compiler/instruction-scheduler.h" ++ ++namespace v8 { ++namespace internal { ++namespace compiler { ++ ++bool InstructionScheduler::SchedulerSupported() { return false; } ++ ++ ++int InstructionScheduler::GetTargetInstructionFlags( ++ const Instruction* instr) const { ++ UNIMPLEMENTED(); ++} ++ ++ ++int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { ++ UNIMPLEMENTED(); ++} ++ ++} // namespace compiler ++} // namespace internal ++} // namespace v8 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-selector-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-selector-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/instruction-selector-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/instruction-selector-x87.cc 2017-12-25 17:42:57.210465720 +0100 +@@ -0,0 +1,1871 @@ ++// Copyright 2014 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "src/base/adapters.h" ++#include "src/compiler/instruction-selector-impl.h" ++#include "src/compiler/node-matchers.h" ++#include "src/compiler/node-properties.h" ++ ++namespace v8 { ++namespace internal { ++namespace compiler { ++ ++// Adds X87-specific methods for generating operands. ++class X87OperandGenerator final : public OperandGenerator { ++ public: ++ explicit X87OperandGenerator(InstructionSelector* selector) ++ : OperandGenerator(selector) {} ++ ++ InstructionOperand UseByteRegister(Node* node) { ++ // TODO(titzer): encode byte register use constraints. ++ return UseFixed(node, edx); ++ } ++ ++ InstructionOperand DefineAsByteRegister(Node* node) { ++ // TODO(titzer): encode byte register def constraints. ++ return DefineAsRegister(node); ++ } ++ ++ bool CanBeMemoryOperand(InstructionCode opcode, Node* node, Node* input, ++ int effect_level) { ++ if (input->opcode() != IrOpcode::kLoad || ++ !selector()->CanCover(node, input)) { ++ return false; ++ } ++ if (effect_level != selector()->GetEffectLevel(input)) { ++ return false; ++ } ++ MachineRepresentation rep = ++ LoadRepresentationOf(input->op()).representation(); ++ switch (opcode) { ++ case kX87Cmp: ++ case kX87Test: ++ return rep == MachineRepresentation::kWord32 || ++ rep == MachineRepresentation::kTagged; ++ case kX87Cmp16: ++ case kX87Test16: ++ return rep == MachineRepresentation::kWord16; ++ case kX87Cmp8: ++ case kX87Test8: ++ return rep == MachineRepresentation::kWord8; ++ default: ++ break; ++ } ++ return false; ++ } ++ ++ InstructionOperand CreateImmediate(int imm) { ++ return sequence()->AddImmediate(Constant(imm)); ++ } ++ ++ bool CanBeImmediate(Node* node) { ++ switch (node->opcode()) { ++ case IrOpcode::kInt32Constant: ++ case IrOpcode::kNumberConstant: ++ case IrOpcode::kExternalConstant: ++ case IrOpcode::kRelocatableInt32Constant: ++ case IrOpcode::kRelocatableInt64Constant: ++ return true; ++ case IrOpcode::kHeapConstant: { ++// TODO(bmeurer): We must not dereference handles concurrently. If we ++// really have to this here, then we need to find a way to put this ++// information on the HeapConstant node already. ++#if 0 ++ // Constants in new space cannot be used as immediates in V8 because ++ // the GC does not scan code objects when collecting the new generation. ++ Handle value = OpParameter>(node); ++ Isolate* isolate = value->GetIsolate(); ++ return !isolate->heap()->InNewSpace(*value); ++#endif ++ } ++ default: ++ return false; ++ } ++ } ++ ++ AddressingMode GenerateMemoryOperandInputs(Node* index, int scale, Node* base, ++ Node* displacement_node, ++ DisplacementMode displacement_mode, ++ InstructionOperand inputs[], ++ size_t* input_count) { ++ AddressingMode mode = kMode_MRI; ++ int32_t displacement = (displacement_node == nullptr) ++ ? 0 ++ : OpParameter(displacement_node); ++ if (displacement_mode == kNegativeDisplacement) { ++ displacement = -displacement; ++ } ++ if (base != nullptr) { ++ if (base->opcode() == IrOpcode::kInt32Constant) { ++ displacement += OpParameter(base); ++ base = nullptr; ++ } ++ } ++ if (base != nullptr) { ++ inputs[(*input_count)++] = UseRegister(base); ++ if (index != nullptr) { ++ DCHECK(scale >= 0 && scale <= 3); ++ inputs[(*input_count)++] = UseRegister(index); ++ if (displacement != 0) { ++ inputs[(*input_count)++] = TempImmediate(displacement); ++ static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I, ++ kMode_MR4I, kMode_MR8I}; ++ mode = kMRnI_modes[scale]; ++ } else { ++ static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2, ++ kMode_MR4, kMode_MR8}; ++ mode = kMRn_modes[scale]; ++ } ++ } else { ++ if (displacement == 0) { ++ mode = kMode_MR; ++ } else { ++ inputs[(*input_count)++] = TempImmediate(displacement); ++ mode = kMode_MRI; ++ } ++ } ++ } else { ++ DCHECK(scale >= 0 && scale <= 3); ++ if (index != nullptr) { ++ inputs[(*input_count)++] = UseRegister(index); ++ if (displacement != 0) { ++ inputs[(*input_count)++] = TempImmediate(displacement); ++ static const AddressingMode kMnI_modes[] = {kMode_MRI, kMode_M2I, ++ kMode_M4I, kMode_M8I}; ++ mode = kMnI_modes[scale]; ++ } else { ++ static const AddressingMode kMn_modes[] = {kMode_MR, kMode_M2, ++ kMode_M4, kMode_M8}; ++ mode = kMn_modes[scale]; ++ } ++ } else { ++ inputs[(*input_count)++] = TempImmediate(displacement); ++ return kMode_MI; ++ } ++ } ++ return mode; ++ } ++ ++ AddressingMode GetEffectiveAddressMemoryOperand(Node* node, ++ InstructionOperand inputs[], ++ size_t* input_count) { ++ BaseWithIndexAndDisplacement32Matcher m(node, AddressOption::kAllowAll); ++ DCHECK(m.matches()); ++ if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) { ++ return GenerateMemoryOperandInputs( ++ m.index(), m.scale(), m.base(), m.displacement(), ++ m.displacement_mode(), inputs, input_count); ++ } else { ++ inputs[(*input_count)++] = UseRegister(node->InputAt(0)); ++ inputs[(*input_count)++] = UseRegister(node->InputAt(1)); ++ return kMode_MR1; ++ } ++ } ++ ++ bool CanBeBetterLeftOperand(Node* node) const { ++ return !selector()->IsLive(node); ++ } ++}; ++ ++void InstructionSelector::VisitStackSlot(Node* node) { ++ StackSlotRepresentation rep = StackSlotRepresentationOf(node->op()); ++ int slot = frame_->AllocateSpillSlot(rep.size()); ++ OperandGenerator g(this); ++ ++ Emit(kArchStackSlot, g.DefineAsRegister(node), ++ sequence()->AddImmediate(Constant(slot)), 0, nullptr); ++} ++ ++void InstructionSelector::VisitLoad(Node* node) { ++ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); ++ ++ ArchOpcode opcode = kArchNop; ++ switch (load_rep.representation()) { ++ case MachineRepresentation::kFloat32: ++ opcode = kX87Movss; ++ break; ++ case MachineRepresentation::kFloat64: ++ opcode = kX87Movsd; ++ break; ++ case MachineRepresentation::kBit: // Fall through. ++ case MachineRepresentation::kWord8: ++ opcode = load_rep.IsSigned() ? kX87Movsxbl : kX87Movzxbl; ++ break; ++ case MachineRepresentation::kWord16: ++ opcode = load_rep.IsSigned() ? kX87Movsxwl : kX87Movzxwl; ++ break; ++ case MachineRepresentation::kTaggedSigned: // Fall through. ++ case MachineRepresentation::kTaggedPointer: // Fall through. ++ case MachineRepresentation::kTagged: // Fall through. ++ case MachineRepresentation::kWord32: ++ opcode = kX87Movl; ++ break; ++ case MachineRepresentation::kWord64: // Fall through. ++ case MachineRepresentation::kSimd128: // Fall through. ++ case MachineRepresentation::kNone: ++ UNREACHABLE(); ++ return; ++ } ++ ++ X87OperandGenerator g(this); ++ InstructionOperand outputs[1]; ++ outputs[0] = g.DefineAsRegister(node); ++ InstructionOperand inputs[3]; ++ size_t input_count = 0; ++ AddressingMode mode = ++ g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); ++ InstructionCode code = opcode | AddressingModeField::encode(mode); ++ Emit(code, 1, outputs, input_count, inputs); ++} ++ ++void InstructionSelector::VisitProtectedLoad(Node* node) { ++ // TODO(eholk) ++ UNIMPLEMENTED(); ++} ++ ++void InstructionSelector::VisitStore(Node* node) { ++ X87OperandGenerator g(this); ++ Node* base = node->InputAt(0); ++ Node* index = node->InputAt(1); ++ Node* value = node->InputAt(2); ++ ++ StoreRepresentation store_rep = StoreRepresentationOf(node->op()); ++ WriteBarrierKind write_barrier_kind = store_rep.write_barrier_kind(); ++ MachineRepresentation rep = store_rep.representation(); ++ ++ if (write_barrier_kind != kNoWriteBarrier) { ++ DCHECK(CanBeTaggedPointer(rep)); ++ AddressingMode addressing_mode; ++ InstructionOperand inputs[3]; ++ size_t input_count = 0; ++ inputs[input_count++] = g.UseUniqueRegister(base); ++ if (g.CanBeImmediate(index)) { ++ inputs[input_count++] = g.UseImmediate(index); ++ addressing_mode = kMode_MRI; ++ } else { ++ inputs[input_count++] = g.UseUniqueRegister(index); ++ addressing_mode = kMode_MR1; ++ } ++ inputs[input_count++] = g.UseUniqueRegister(value); ++ RecordWriteMode record_write_mode = RecordWriteMode::kValueIsAny; ++ switch (write_barrier_kind) { ++ case kNoWriteBarrier: ++ UNREACHABLE(); ++ break; ++ case kMapWriteBarrier: ++ record_write_mode = RecordWriteMode::kValueIsMap; ++ break; ++ case kPointerWriteBarrier: ++ record_write_mode = RecordWriteMode::kValueIsPointer; ++ break; ++ case kFullWriteBarrier: ++ record_write_mode = RecordWriteMode::kValueIsAny; ++ break; ++ } ++ InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; ++ size_t const temp_count = arraysize(temps); ++ InstructionCode code = kArchStoreWithWriteBarrier; ++ code |= AddressingModeField::encode(addressing_mode); ++ code |= MiscField::encode(static_cast(record_write_mode)); ++ Emit(code, 0, nullptr, input_count, inputs, temp_count, temps); ++ } else { ++ ArchOpcode opcode = kArchNop; ++ switch (rep) { ++ case MachineRepresentation::kFloat32: ++ opcode = kX87Movss; ++ break; ++ case MachineRepresentation::kFloat64: ++ opcode = kX87Movsd; ++ break; ++ case MachineRepresentation::kBit: // Fall through. ++ case MachineRepresentation::kWord8: ++ opcode = kX87Movb; ++ break; ++ case MachineRepresentation::kWord16: ++ opcode = kX87Movw; ++ break; ++ case MachineRepresentation::kTaggedSigned: // Fall through. ++ case MachineRepresentation::kTaggedPointer: // Fall through. ++ case MachineRepresentation::kTagged: // Fall through. ++ case MachineRepresentation::kWord32: ++ opcode = kX87Movl; ++ break; ++ case MachineRepresentation::kWord64: // Fall through. ++ case MachineRepresentation::kSimd128: // Fall through. ++ case MachineRepresentation::kNone: ++ UNREACHABLE(); ++ return; ++ } ++ ++ InstructionOperand val; ++ if (g.CanBeImmediate(value)) { ++ val = g.UseImmediate(value); ++ } else if (rep == MachineRepresentation::kWord8 || ++ rep == MachineRepresentation::kBit) { ++ val = g.UseByteRegister(value); ++ } else { ++ val = g.UseRegister(value); ++ } ++ ++ InstructionOperand inputs[4]; ++ size_t input_count = 0; ++ AddressingMode addressing_mode = ++ g.GetEffectiveAddressMemoryOperand(node, inputs, &input_count); ++ InstructionCode code = ++ opcode | AddressingModeField::encode(addressing_mode); ++ inputs[input_count++] = val; ++ Emit(code, 0, static_cast(nullptr), input_count, ++ inputs); ++ } ++} ++ ++void InstructionSelector::VisitProtectedStore(Node* node) { ++ // TODO(eholk) ++ UNIMPLEMENTED(); ++} ++ ++// Architecture supports unaligned access, therefore VisitLoad is used instead ++void InstructionSelector::VisitUnalignedLoad(Node* node) { UNREACHABLE(); } ++ ++// Architecture supports unaligned access, therefore VisitStore is used instead ++void InstructionSelector::VisitUnalignedStore(Node* node) { UNREACHABLE(); } ++ ++void InstructionSelector::VisitCheckedLoad(Node* node) { ++ CheckedLoadRepresentation load_rep = CheckedLoadRepresentationOf(node->op()); ++ X87OperandGenerator g(this); ++ Node* const buffer = node->InputAt(0); ++ Node* const offset = node->InputAt(1); ++ Node* const length = node->InputAt(2); ++ ArchOpcode opcode = kArchNop; ++ switch (load_rep.representation()) { ++ case MachineRepresentation::kWord8: ++ opcode = load_rep.IsSigned() ? kCheckedLoadInt8 : kCheckedLoadUint8; ++ break; ++ case MachineRepresentation::kWord16: ++ opcode = load_rep.IsSigned() ? kCheckedLoadInt16 : kCheckedLoadUint16; ++ break; ++ case MachineRepresentation::kWord32: ++ opcode = kCheckedLoadWord32; ++ break; ++ case MachineRepresentation::kFloat32: ++ opcode = kCheckedLoadFloat32; ++ break; ++ case MachineRepresentation::kFloat64: ++ opcode = kCheckedLoadFloat64; ++ break; ++ case MachineRepresentation::kBit: // Fall through. ++ case MachineRepresentation::kTaggedSigned: // Fall through. ++ case MachineRepresentation::kTaggedPointer: // Fall through. ++ case MachineRepresentation::kTagged: // Fall through. ++ case MachineRepresentation::kWord64: // Fall through. ++ case MachineRepresentation::kSimd128: // Fall through. ++ case MachineRepresentation::kNone: ++ UNREACHABLE(); ++ return; ++ } ++ InstructionOperand offset_operand = g.UseRegister(offset); ++ InstructionOperand length_operand = ++ g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); ++ if (g.CanBeImmediate(buffer)) { ++ Emit(opcode | AddressingModeField::encode(kMode_MRI), ++ g.DefineAsRegister(node), offset_operand, length_operand, ++ offset_operand, g.UseImmediate(buffer)); ++ } else { ++ Emit(opcode | AddressingModeField::encode(kMode_MR1), ++ g.DefineAsRegister(node), offset_operand, length_operand, ++ g.UseRegister(buffer), offset_operand); ++ } ++} ++ ++ ++void InstructionSelector::VisitCheckedStore(Node* node) { ++ MachineRepresentation rep = CheckedStoreRepresentationOf(node->op()); ++ X87OperandGenerator g(this); ++ Node* const buffer = node->InputAt(0); ++ Node* const offset = node->InputAt(1); ++ Node* const length = node->InputAt(2); ++ Node* const value = node->InputAt(3); ++ ArchOpcode opcode = kArchNop; ++ switch (rep) { ++ case MachineRepresentation::kWord8: ++ opcode = kCheckedStoreWord8; ++ break; ++ case MachineRepresentation::kWord16: ++ opcode = kCheckedStoreWord16; ++ break; ++ case MachineRepresentation::kWord32: ++ opcode = kCheckedStoreWord32; ++ break; ++ case MachineRepresentation::kFloat32: ++ opcode = kCheckedStoreFloat32; ++ break; ++ case MachineRepresentation::kFloat64: ++ opcode = kCheckedStoreFloat64; ++ break; ++ case MachineRepresentation::kBit: // Fall through. ++ case MachineRepresentation::kTaggedSigned: // Fall through. ++ case MachineRepresentation::kTaggedPointer: // Fall through. ++ case MachineRepresentation::kTagged: // Fall through. ++ case MachineRepresentation::kWord64: // Fall through. ++ case MachineRepresentation::kSimd128: // Fall through. ++ case MachineRepresentation::kNone: ++ UNREACHABLE(); ++ return; ++ } ++ InstructionOperand value_operand = ++ g.CanBeImmediate(value) ? g.UseImmediate(value) ++ : ((rep == MachineRepresentation::kWord8 || ++ rep == MachineRepresentation::kBit) ++ ? g.UseByteRegister(value) ++ : g.UseRegister(value)); ++ InstructionOperand offset_operand = g.UseRegister(offset); ++ InstructionOperand length_operand = ++ g.CanBeImmediate(length) ? g.UseImmediate(length) : g.UseRegister(length); ++ if (g.CanBeImmediate(buffer)) { ++ Emit(opcode | AddressingModeField::encode(kMode_MRI), g.NoOutput(), ++ offset_operand, length_operand, value_operand, offset_operand, ++ g.UseImmediate(buffer)); ++ } else { ++ Emit(opcode | AddressingModeField::encode(kMode_MR1), g.NoOutput(), ++ offset_operand, length_operand, value_operand, g.UseRegister(buffer), ++ offset_operand); ++ } ++} ++ ++namespace { ++ ++// Shared routine for multiple binary operations. ++void VisitBinop(InstructionSelector* selector, Node* node, ++ InstructionCode opcode, FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ Int32BinopMatcher m(node); ++ Node* left = m.left().node(); ++ Node* right = m.right().node(); ++ InstructionOperand inputs[4]; ++ size_t input_count = 0; ++ InstructionOperand outputs[2]; ++ size_t output_count = 0; ++ ++ // TODO(turbofan): match complex addressing modes. ++ if (left == right) { ++ // If both inputs refer to the same operand, enforce allocating a register ++ // for both of them to ensure that we don't end up generating code like ++ // this: ++ // ++ // mov eax, [ebp-0x10] ++ // add eax, [ebp-0x10] ++ // jo label ++ InstructionOperand const input = g.UseRegister(left); ++ inputs[input_count++] = input; ++ inputs[input_count++] = input; ++ } else if (g.CanBeImmediate(right)) { ++ inputs[input_count++] = g.UseRegister(left); ++ inputs[input_count++] = g.UseImmediate(right); ++ } else { ++ if (node->op()->HasProperty(Operator::kCommutative) && ++ g.CanBeBetterLeftOperand(right)) { ++ std::swap(left, right); ++ } ++ inputs[input_count++] = g.UseRegister(left); ++ inputs[input_count++] = g.Use(right); ++ } ++ ++ if (cont->IsBranch()) { ++ inputs[input_count++] = g.Label(cont->true_block()); ++ inputs[input_count++] = g.Label(cont->false_block()); ++ } ++ ++ outputs[output_count++] = g.DefineSameAsFirst(node); ++ if (cont->IsSet()) { ++ outputs[output_count++] = g.DefineAsRegister(cont->result()); ++ } ++ ++ DCHECK_NE(0u, input_count); ++ DCHECK_NE(0u, output_count); ++ DCHECK_GE(arraysize(inputs), input_count); ++ DCHECK_GE(arraysize(outputs), output_count); ++ ++ opcode = cont->Encode(opcode); ++ if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, ++ cont->kind(), cont->reason(), cont->frame_state()); ++ } else { ++ selector->Emit(opcode, output_count, outputs, input_count, inputs); ++ } ++} ++ ++ ++// Shared routine for multiple binary operations. ++void VisitBinop(InstructionSelector* selector, Node* node, ++ InstructionCode opcode) { ++ FlagsContinuation cont; ++ VisitBinop(selector, node, opcode, &cont); ++} ++ ++} // namespace ++ ++void InstructionSelector::VisitWord32And(Node* node) { ++ VisitBinop(this, node, kX87And); ++} ++ ++ ++void InstructionSelector::VisitWord32Or(Node* node) { ++ VisitBinop(this, node, kX87Or); ++} ++ ++ ++void InstructionSelector::VisitWord32Xor(Node* node) { ++ X87OperandGenerator g(this); ++ Int32BinopMatcher m(node); ++ if (m.right().Is(-1)) { ++ Emit(kX87Not, g.DefineSameAsFirst(node), g.UseRegister(m.left().node())); ++ } else { ++ VisitBinop(this, node, kX87Xor); ++ } ++} ++ ++ ++// Shared routine for multiple shift operations. ++static inline void VisitShift(InstructionSelector* selector, Node* node, ++ ArchOpcode opcode) { ++ X87OperandGenerator g(selector); ++ Node* left = node->InputAt(0); ++ Node* right = node->InputAt(1); ++ ++ if (g.CanBeImmediate(right)) { ++ selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), ++ g.UseImmediate(right)); ++ } else { ++ selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left), ++ g.UseFixed(right, ecx)); ++ } ++} ++ ++ ++namespace { ++ ++void VisitMulHigh(InstructionSelector* selector, Node* node, ++ ArchOpcode opcode) { ++ X87OperandGenerator g(selector); ++ InstructionOperand temps[] = {g.TempRegister(eax)}; ++ selector->Emit( ++ opcode, g.DefineAsFixed(node, edx), g.UseFixed(node->InputAt(0), eax), ++ g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps); ++} ++ ++ ++void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) { ++ X87OperandGenerator g(selector); ++ InstructionOperand temps[] = {g.TempRegister(edx)}; ++ selector->Emit(opcode, g.DefineAsFixed(node, eax), ++ g.UseFixed(node->InputAt(0), eax), ++ g.UseUnique(node->InputAt(1)), arraysize(temps), temps); ++} ++ ++ ++void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) { ++ X87OperandGenerator g(selector); ++ InstructionOperand temps[] = {g.TempRegister(eax)}; ++ selector->Emit(opcode, g.DefineAsFixed(node, edx), ++ g.UseFixed(node->InputAt(0), eax), ++ g.UseUnique(node->InputAt(1)), arraysize(temps), temps); ++} ++ ++void EmitLea(InstructionSelector* selector, Node* result, Node* index, ++ int scale, Node* base, Node* displacement, ++ DisplacementMode displacement_mode) { ++ X87OperandGenerator g(selector); ++ InstructionOperand inputs[4]; ++ size_t input_count = 0; ++ AddressingMode mode = ++ g.GenerateMemoryOperandInputs(index, scale, base, displacement, ++ displacement_mode, inputs, &input_count); ++ ++ DCHECK_NE(0u, input_count); ++ DCHECK_GE(arraysize(inputs), input_count); ++ ++ InstructionOperand outputs[1]; ++ outputs[0] = g.DefineAsRegister(result); ++ ++ InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea; ++ ++ selector->Emit(opcode, 1, outputs, input_count, inputs); ++} ++ ++} // namespace ++ ++ ++void InstructionSelector::VisitWord32Shl(Node* node) { ++ Int32ScaleMatcher m(node, true); ++ if (m.matches()) { ++ Node* index = node->InputAt(0); ++ Node* base = m.power_of_two_plus_one() ? index : nullptr; ++ EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement); ++ return; ++ } ++ VisitShift(this, node, kX87Shl); ++} ++ ++ ++void InstructionSelector::VisitWord32Shr(Node* node) { ++ VisitShift(this, node, kX87Shr); ++} ++ ++ ++void InstructionSelector::VisitWord32Sar(Node* node) { ++ VisitShift(this, node, kX87Sar); ++} ++ ++void InstructionSelector::VisitInt32PairAdd(Node* node) { ++ X87OperandGenerator g(this); ++ ++ Node* projection1 = NodeProperties::FindProjection(node, 1); ++ if (projection1) { ++ // We use UseUniqueRegister here to avoid register sharing with the temp ++ // register. ++ InstructionOperand inputs[] = { ++ g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)), ++ g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))}; ++ ++ InstructionOperand outputs[] = {g.DefineSameAsFirst(node), ++ g.DefineAsRegister(projection1)}; ++ ++ InstructionOperand temps[] = {g.TempRegister()}; ++ ++ Emit(kX87AddPair, 2, outputs, 4, inputs, 1, temps); ++ } else { ++ // The high word of the result is not used, so we emit the standard 32 bit ++ // instruction. ++ Emit(kX87Add, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)), ++ g.Use(node->InputAt(2))); ++ } ++} ++ ++void InstructionSelector::VisitInt32PairSub(Node* node) { ++ X87OperandGenerator g(this); ++ ++ Node* projection1 = NodeProperties::FindProjection(node, 1); ++ if (projection1) { ++ // We use UseUniqueRegister here to avoid register sharing with the temp ++ // register. ++ InstructionOperand inputs[] = { ++ g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)), ++ g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))}; ++ ++ InstructionOperand outputs[] = {g.DefineSameAsFirst(node), ++ g.DefineAsRegister(projection1)}; ++ ++ InstructionOperand temps[] = {g.TempRegister()}; ++ ++ Emit(kX87SubPair, 2, outputs, 4, inputs, 1, temps); ++ } else { ++ // The high word of the result is not used, so we emit the standard 32 bit ++ // instruction. ++ Emit(kX87Sub, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)), ++ g.Use(node->InputAt(2))); ++ } ++} ++ ++void InstructionSelector::VisitInt32PairMul(Node* node) { ++ X87OperandGenerator g(this); ++ ++ Node* projection1 = NodeProperties::FindProjection(node, 1); ++ if (projection1) { ++ // InputAt(3) explicitly shares ecx with OutputRegister(1) to save one ++ // register and one mov instruction. ++ InstructionOperand inputs[] = {g.UseUnique(node->InputAt(0)), ++ g.UseUnique(node->InputAt(1)), ++ g.UseUniqueRegister(node->InputAt(2)), ++ g.UseFixed(node->InputAt(3), ecx)}; ++ ++ InstructionOperand outputs[] = { ++ g.DefineAsFixed(node, eax), ++ g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)}; ++ ++ InstructionOperand temps[] = {g.TempRegister(edx)}; ++ ++ Emit(kX87MulPair, 2, outputs, 4, inputs, 1, temps); ++ } else { ++ // The high word of the result is not used, so we emit the standard 32 bit ++ // instruction. ++ Emit(kX87Imul, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)), ++ g.Use(node->InputAt(2))); ++ } ++} ++ ++void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode, ++ Node* node) { ++ X87OperandGenerator g(selector); ++ ++ Node* shift = node->InputAt(2); ++ InstructionOperand shift_operand; ++ if (g.CanBeImmediate(shift)) { ++ shift_operand = g.UseImmediate(shift); ++ } else { ++ shift_operand = g.UseFixed(shift, ecx); ++ } ++ InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax), ++ g.UseFixed(node->InputAt(1), edx), ++ shift_operand}; ++ ++ InstructionOperand outputs[2]; ++ InstructionOperand temps[1]; ++ int32_t output_count = 0; ++ int32_t temp_count = 0; ++ outputs[output_count++] = g.DefineAsFixed(node, eax); ++ Node* projection1 = NodeProperties::FindProjection(node, 1); ++ if (projection1) { ++ outputs[output_count++] = g.DefineAsFixed(projection1, edx); ++ } else { ++ temps[temp_count++] = g.TempRegister(edx); ++ } ++ ++ selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps); ++} ++ ++void InstructionSelector::VisitWord32PairShl(Node* node) { ++ VisitWord32PairShift(this, kX87ShlPair, node); ++} ++ ++void InstructionSelector::VisitWord32PairShr(Node* node) { ++ VisitWord32PairShift(this, kX87ShrPair, node); ++} ++ ++void InstructionSelector::VisitWord32PairSar(Node* node) { ++ VisitWord32PairShift(this, kX87SarPair, node); ++} ++ ++void InstructionSelector::VisitWord32Ror(Node* node) { ++ VisitShift(this, node, kX87Ror); ++} ++ ++ ++void InstructionSelector::VisitWord32Clz(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Lzcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } ++ ++ ++void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } ++ ++void InstructionSelector::VisitWord64ReverseBytes(Node* node) { UNREACHABLE(); } ++ ++void InstructionSelector::VisitWord32ReverseBytes(Node* node) { UNREACHABLE(); } ++ ++void InstructionSelector::VisitWord32Popcnt(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitInt32Add(Node* node) { ++ X87OperandGenerator g(this); ++ ++ // Try to match the Add to a lea pattern ++ BaseWithIndexAndDisplacement32Matcher m(node); ++ if (m.matches() && ++ (m.displacement() == nullptr || g.CanBeImmediate(m.displacement()))) { ++ InstructionOperand inputs[4]; ++ size_t input_count = 0; ++ AddressingMode mode = g.GenerateMemoryOperandInputs( ++ m.index(), m.scale(), m.base(), m.displacement(), m.displacement_mode(), ++ inputs, &input_count); ++ ++ DCHECK_NE(0u, input_count); ++ DCHECK_GE(arraysize(inputs), input_count); ++ ++ InstructionOperand outputs[1]; ++ outputs[0] = g.DefineAsRegister(node); ++ ++ InstructionCode opcode = AddressingModeField::encode(mode) | kX87Lea; ++ Emit(opcode, 1, outputs, input_count, inputs); ++ return; ++ } ++ ++ // No lea pattern match, use add ++ VisitBinop(this, node, kX87Add); ++} ++ ++ ++void InstructionSelector::VisitInt32Sub(Node* node) { ++ X87OperandGenerator g(this); ++ Int32BinopMatcher m(node); ++ if (m.left().Is(0)) { ++ Emit(kX87Neg, g.DefineSameAsFirst(node), g.Use(m.right().node())); ++ } else { ++ VisitBinop(this, node, kX87Sub); ++ } ++} ++ ++ ++void InstructionSelector::VisitInt32Mul(Node* node) { ++ Int32ScaleMatcher m(node, true); ++ if (m.matches()) { ++ Node* index = node->InputAt(0); ++ Node* base = m.power_of_two_plus_one() ? index : nullptr; ++ EmitLea(this, node, index, m.scale(), base, nullptr, kPositiveDisplacement); ++ return; ++ } ++ X87OperandGenerator g(this); ++ Node* left = node->InputAt(0); ++ Node* right = node->InputAt(1); ++ if (g.CanBeImmediate(right)) { ++ Emit(kX87Imul, g.DefineAsRegister(node), g.Use(left), ++ g.UseImmediate(right)); ++ } else { ++ if (g.CanBeBetterLeftOperand(right)) { ++ std::swap(left, right); ++ } ++ Emit(kX87Imul, g.DefineSameAsFirst(node), g.UseRegister(left), ++ g.Use(right)); ++ } ++} ++ ++ ++void InstructionSelector::VisitInt32MulHigh(Node* node) { ++ VisitMulHigh(this, node, kX87ImulHigh); ++} ++ ++ ++void InstructionSelector::VisitUint32MulHigh(Node* node) { ++ VisitMulHigh(this, node, kX87UmulHigh); ++} ++ ++ ++void InstructionSelector::VisitInt32Div(Node* node) { ++ VisitDiv(this, node, kX87Idiv); ++} ++ ++ ++void InstructionSelector::VisitUint32Div(Node* node) { ++ VisitDiv(this, node, kX87Udiv); ++} ++ ++ ++void InstructionSelector::VisitInt32Mod(Node* node) { ++ VisitMod(this, node, kX87Idiv); ++} ++ ++ ++void InstructionSelector::VisitUint32Mod(Node* node) { ++ VisitMod(this, node, kX87Udiv); ++} ++ ++ ++void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32ToFloat64, g.DefineAsFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Int32ToFloat32, g.DefineAsFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Uint32ToFloat32, g.DefineAsFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Int32ToFloat64, g.DefineAsFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Uint32ToFloat64, g.DefineAsFixed(node, stX_0), ++ g.UseRegister(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitTruncateFloat32ToInt32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitTruncateFloat32ToUint32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitChangeFloat64ToInt32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++void InstructionSelector::VisitTruncateFloat64ToUint32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ToUint32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ToFloat32, g.DefineAsFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++void InstructionSelector::VisitTruncateFloat64ToWord32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node), ++ g.Use(node->InputAt(0))); ++} ++ ++void InstructionSelector::VisitRoundFloat64ToInt32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ToInt32, g.DefineAsRegister(node), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitBitcastFloat32ToInt32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87BitcastFI, g.DefineAsRegister(node), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87BitcastIF, g.DefineAsFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat32Add(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Add, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Add(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Add, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat32Sub(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Sub, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat64Sub(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Sub, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat32Mul(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Mul, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Mul(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Mul, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat32Div(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Div, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Div(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Div, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Mod(Node* node) { ++ X87OperandGenerator g(this); ++ InstructionOperand temps[] = {g.TempRegister(eax)}; ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Mod, g.DefineAsFixed(node, stX_0), 1, temps)->MarkAsCall(); ++} ++ ++void InstructionSelector::VisitFloat32Max(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Max, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat64Max(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Max, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat32Min(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float32Min, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat64Min(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(kX87Float64Min, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat32Abs(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float32Abs, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Abs(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float64Abs, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat32Sqrt(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float32Sqrt, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat64Sqrt(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float64Sqrt, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++ ++void InstructionSelector::VisitFloat32RoundDown(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32Round | MiscField::encode(kRoundDown), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64RoundDown(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64Round | MiscField::encode(kRoundDown), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat32RoundUp(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32Round | MiscField::encode(kRoundUp), g.UseFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64RoundUp(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64Round | MiscField::encode(kRoundUp), g.UseFixed(node, stX_0), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat32RoundTruncate(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32Round | MiscField::encode(kRoundToZero), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64RoundTruncate(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64Round | MiscField::encode(kRoundToZero), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) { ++ UNREACHABLE(); ++} ++ ++ ++void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float32Round | MiscField::encode(kRoundToNearest), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64Round | MiscField::encode(kRoundToNearest), ++ g.UseFixed(node, stX_0), g.Use(node->InputAt(0))); ++} ++ ++void InstructionSelector::VisitFloat32Neg(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float32Neg, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat64Neg(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float64Neg, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitFloat64Ieee754Binop(Node* node, ++ InstructionCode opcode) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ Emit(opcode, g.DefineAsFixed(node, stX_0), 0, nullptr)->MarkAsCall(); ++} ++ ++void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, ++ InstructionCode opcode) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(opcode, g.DefineAsFixed(node, stX_0), 0, nullptr)->MarkAsCall(); ++} ++ ++void InstructionSelector::EmitPrepareArguments( ++ ZoneVector* arguments, const CallDescriptor* descriptor, ++ Node* node) { ++ X87OperandGenerator g(this); ++ ++ // Prepare for C function call. ++ if (descriptor->IsCFunctionCall()) { ++ InstructionOperand temps[] = {g.TempRegister()}; ++ size_t const temp_count = arraysize(temps); ++ Emit(kArchPrepareCallCFunction | ++ MiscField::encode(static_cast(descriptor->ParameterCount())), ++ 0, nullptr, 0, nullptr, temp_count, temps); ++ ++ // Poke any stack arguments. ++ for (size_t n = 0; n < arguments->size(); ++n) { ++ PushParameter input = (*arguments)[n]; ++ if (input.node()) { ++ int const slot = static_cast(n); ++ InstructionOperand value = g.CanBeImmediate(input.node()) ++ ? g.UseImmediate(input.node()) ++ : g.UseRegister(input.node()); ++ Emit(kX87Poke | MiscField::encode(slot), g.NoOutput(), value); ++ } ++ } ++ } else { ++ // Push any stack arguments. ++ for (PushParameter input : base::Reversed(*arguments)) { ++ // TODO(titzer): handle pushing double parameters. ++ if (input.node() == nullptr) continue; ++ InstructionOperand value = ++ g.CanBeImmediate(input.node()) ++ ? g.UseImmediate(input.node()) ++ : IsSupported(ATOM) || ++ sequence()->IsFP(GetVirtualRegister(input.node())) ++ ? g.UseRegister(input.node()) ++ : g.Use(input.node()); ++ Emit(kX87Push, g.NoOutput(), value); ++ } ++ } ++} ++ ++ ++bool InstructionSelector::IsTailCallAddressImmediate() { return true; } ++ ++int InstructionSelector::GetTempsCountForTailCallFromJSFunction() { return 0; } ++ ++namespace { ++ ++void VisitCompareWithMemoryOperand(InstructionSelector* selector, ++ InstructionCode opcode, Node* left, ++ InstructionOperand right, ++ FlagsContinuation* cont) { ++ DCHECK(left->opcode() == IrOpcode::kLoad); ++ X87OperandGenerator g(selector); ++ size_t input_count = 0; ++ InstructionOperand inputs[6]; ++ AddressingMode addressing_mode = ++ g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count); ++ opcode |= AddressingModeField::encode(addressing_mode); ++ opcode = cont->Encode(opcode); ++ inputs[input_count++] = right; ++ ++ if (cont->IsBranch()) { ++ inputs[input_count++] = g.Label(cont->true_block()); ++ inputs[input_count++] = g.Label(cont->false_block()); ++ selector->Emit(opcode, 0, nullptr, input_count, inputs); ++ } else if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs, ++ cont->kind(), cont->reason(), cont->frame_state()); ++ } else if (cont->IsSet()) { ++ InstructionOperand output = g.DefineAsRegister(cont->result()); ++ selector->Emit(opcode, 1, &output, input_count, inputs); ++ } else { ++ DCHECK(cont->IsTrap()); ++ inputs[input_count++] = g.UseImmediate(cont->trap_id()); ++ selector->Emit(opcode, 0, nullptr, input_count, inputs); ++ } ++} ++ ++// Shared routine for multiple compare operations. ++void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ++ InstructionOperand left, InstructionOperand right, ++ FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ opcode = cont->Encode(opcode); ++ if (cont->IsBranch()) { ++ selector->Emit(opcode, g.NoOutput(), left, right, ++ g.Label(cont->true_block()), g.Label(cont->false_block())); ++ } else if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, cont->kind(), ++ cont->reason(), cont->frame_state()); ++ } else if (cont->IsSet()) { ++ selector->Emit(opcode, g.DefineAsByteRegister(cont->result()), left, right); ++ } else { ++ DCHECK(cont->IsTrap()); ++ selector->Emit(opcode, g.NoOutput(), left, right, ++ g.UseImmediate(cont->trap_id())); ++ } ++} ++ ++ ++// Shared routine for multiple compare operations. ++void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ++ Node* left, Node* right, FlagsContinuation* cont, ++ bool commutative) { ++ X87OperandGenerator g(selector); ++ if (commutative && g.CanBeBetterLeftOperand(right)) { ++ std::swap(left, right); ++ } ++ VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont); ++} ++ ++MachineType MachineTypeForNarrow(Node* node, Node* hint_node) { ++ if (hint_node->opcode() == IrOpcode::kLoad) { ++ MachineType hint = LoadRepresentationOf(hint_node->op()); ++ if (node->opcode() == IrOpcode::kInt32Constant || ++ node->opcode() == IrOpcode::kInt64Constant) { ++ int64_t constant = node->opcode() == IrOpcode::kInt32Constant ++ ? OpParameter(node) ++ : OpParameter(node); ++ if (hint == MachineType::Int8()) { ++ if (constant >= std::numeric_limits::min() && ++ constant <= std::numeric_limits::max()) { ++ return hint; ++ } ++ } else if (hint == MachineType::Uint8()) { ++ if (constant >= std::numeric_limits::min() && ++ constant <= std::numeric_limits::max()) { ++ return hint; ++ } ++ } else if (hint == MachineType::Int16()) { ++ if (constant >= std::numeric_limits::min() && ++ constant <= std::numeric_limits::max()) { ++ return hint; ++ } ++ } else if (hint == MachineType::Uint16()) { ++ if (constant >= std::numeric_limits::min() && ++ constant <= std::numeric_limits::max()) { ++ return hint; ++ } ++ } else if (hint == MachineType::Int32()) { ++ return hint; ++ } else if (hint == MachineType::Uint32()) { ++ if (constant >= 0) return hint; ++ } ++ } ++ } ++ return node->opcode() == IrOpcode::kLoad ? LoadRepresentationOf(node->op()) ++ : MachineType::None(); ++} ++ ++// Tries to match the size of the given opcode to that of the operands, if ++// possible. ++InstructionCode TryNarrowOpcodeSize(InstructionCode opcode, Node* left, ++ Node* right, FlagsContinuation* cont) { ++ // TODO(epertoso): we can probably get some size information out of phi nodes. ++ // If the load representations don't match, both operands will be ++ // zero/sign-extended to 32bit. ++ MachineType left_type = MachineTypeForNarrow(left, right); ++ MachineType right_type = MachineTypeForNarrow(right, left); ++ if (left_type == right_type) { ++ switch (left_type.representation()) { ++ case MachineRepresentation::kBit: ++ case MachineRepresentation::kWord8: { ++ if (opcode == kX87Test) return kX87Test8; ++ if (opcode == kX87Cmp) { ++ if (left_type.semantic() == MachineSemantic::kUint32) { ++ cont->OverwriteUnsignedIfSigned(); ++ } else { ++ CHECK_EQ(MachineSemantic::kInt32, left_type.semantic()); ++ } ++ return kX87Cmp8; ++ } ++ break; ++ } ++ case MachineRepresentation::kWord16: ++ if (opcode == kX87Test) return kX87Test16; ++ if (opcode == kX87Cmp) { ++ if (left_type.semantic() == MachineSemantic::kUint32) { ++ cont->OverwriteUnsignedIfSigned(); ++ } else { ++ CHECK_EQ(MachineSemantic::kInt32, left_type.semantic()); ++ } ++ return kX87Cmp16; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ return opcode; ++} ++ ++// Shared routine for multiple float32 compare operations (inputs commuted). ++void VisitFloat32Compare(InstructionSelector* selector, Node* node, ++ FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(0))); ++ selector->Emit(kX87PushFloat32, g.NoOutput(), g.Use(node->InputAt(1))); ++ if (cont->IsBranch()) { ++ selector->Emit(cont->Encode(kX87Float32Cmp), g.NoOutput(), ++ g.Label(cont->true_block()), g.Label(cont->false_block())); ++ } else if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(cont->Encode(kX87Float32Cmp), g.NoOutput(), ++ g.Use(node->InputAt(0)), g.Use(node->InputAt(1)), ++ cont->kind(), cont->reason(), cont->frame_state()); ++ } else if (cont->IsSet()) { ++ selector->Emit(cont->Encode(kX87Float32Cmp), ++ g.DefineAsByteRegister(cont->result())); ++ } else { ++ DCHECK(cont->IsTrap()); ++ selector->Emit(cont->Encode(kX87Float32Cmp), g.NoOutput(), ++ g.UseImmediate(cont->trap_id())); ++ } ++} ++ ++ ++// Shared routine for multiple float64 compare operations (inputs commuted). ++void VisitFloat64Compare(InstructionSelector* selector, Node* node, ++ FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ selector->Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(1))); ++ if (cont->IsBranch()) { ++ selector->Emit(cont->Encode(kX87Float64Cmp), g.NoOutput(), ++ g.Label(cont->true_block()), g.Label(cont->false_block())); ++ } else if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(cont->Encode(kX87Float64Cmp), g.NoOutput(), ++ g.Use(node->InputAt(0)), g.Use(node->InputAt(1)), ++ cont->kind(), cont->reason(), cont->frame_state()); ++ } else if (cont->IsSet()) { ++ selector->Emit(cont->Encode(kX87Float64Cmp), ++ g.DefineAsByteRegister(cont->result())); ++ } else { ++ DCHECK(cont->IsTrap()); ++ selector->Emit(cont->Encode(kX87Float64Cmp), g.NoOutput(), ++ g.UseImmediate(cont->trap_id())); ++ } ++} ++ ++// Shared routine for multiple word compare operations. ++void VisitWordCompare(InstructionSelector* selector, Node* node, ++ InstructionCode opcode, FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ Node* left = node->InputAt(0); ++ Node* right = node->InputAt(1); ++ ++ InstructionCode narrowed_opcode = ++ TryNarrowOpcodeSize(opcode, left, right, cont); ++ ++ int effect_level = selector->GetEffectLevel(node); ++ if (cont->IsBranch()) { ++ effect_level = selector->GetEffectLevel( ++ cont->true_block()->PredecessorAt(0)->control_input()); ++ } ++ ++ // If one of the two inputs is an immediate, make sure it's on the right, or ++ // if one of the two inputs is a memory operand, make sure it's on the left. ++ if ((!g.CanBeImmediate(right) && g.CanBeImmediate(left)) || ++ (g.CanBeMemoryOperand(narrowed_opcode, node, right, effect_level) && ++ !g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level))) { ++ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); ++ std::swap(left, right); ++ } ++ ++ // Match immediates on right side of comparison. ++ if (g.CanBeImmediate(right)) { ++ if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) { ++ return VisitCompareWithMemoryOperand(selector, narrowed_opcode, left, ++ g.UseImmediate(right), cont); ++ } ++ return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), ++ cont); ++ } ++ ++ // Match memory operands on left side of comparison. ++ if (g.CanBeMemoryOperand(narrowed_opcode, node, left, effect_level)) { ++ bool needs_byte_register = ++ narrowed_opcode == kX87Test8 || narrowed_opcode == kX87Cmp8; ++ return VisitCompareWithMemoryOperand( ++ selector, narrowed_opcode, left, ++ needs_byte_register ? g.UseByteRegister(right) : g.UseRegister(right), ++ cont); ++ } ++ ++ if (g.CanBeBetterLeftOperand(right)) { ++ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); ++ std::swap(left, right); ++ } ++ ++ return VisitCompare(selector, opcode, left, right, cont, ++ node->op()->HasProperty(Operator::kCommutative)); ++} ++ ++void VisitWordCompare(InstructionSelector* selector, Node* node, ++ FlagsContinuation* cont) { ++ X87OperandGenerator g(selector); ++ Int32BinopMatcher m(node); ++ if (m.left().IsLoad() && m.right().IsLoadStackPointer()) { ++ LoadMatcher mleft(m.left().node()); ++ ExternalReference js_stack_limit = ++ ExternalReference::address_of_stack_limit(selector->isolate()); ++ if (mleft.object().Is(js_stack_limit) && mleft.index().Is(0)) { ++ // Compare(Load(js_stack_limit), LoadStackPointer) ++ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); ++ InstructionCode opcode = cont->Encode(kX87StackCheck); ++ if (cont->IsBranch()) { ++ selector->Emit(opcode, g.NoOutput(), g.Label(cont->true_block()), ++ g.Label(cont->false_block())); ++ } else if (cont->IsDeoptimize()) { ++ selector->EmitDeoptimize(opcode, 0, nullptr, 0, nullptr, cont->kind(), ++ cont->reason(), cont->frame_state()); ++ } else { ++ DCHECK(cont->IsSet()); ++ selector->Emit(opcode, g.DefineAsRegister(cont->result())); ++ } ++ return; ++ } ++ } ++ VisitWordCompare(selector, node, kX87Cmp, cont); ++} ++ ++ ++// Shared routine for word comparison with zero. ++void VisitWordCompareZero(InstructionSelector* selector, Node* user, ++ Node* value, FlagsContinuation* cont) { ++ // Try to combine with comparisons against 0 by simply inverting the branch. ++ while (value->opcode() == IrOpcode::kWord32Equal && ++ selector->CanCover(user, value)) { ++ Int32BinopMatcher m(value); ++ if (!m.right().Is(0)) break; ++ ++ user = value; ++ value = m.left().node(); ++ cont->Negate(); ++ } ++ ++ if (selector->CanCover(user, value)) { ++ switch (value->opcode()) { ++ case IrOpcode::kWord32Equal: ++ cont->OverwriteAndNegateIfEqual(kEqual); ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kInt32LessThan: ++ cont->OverwriteAndNegateIfEqual(kSignedLessThan); ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kInt32LessThanOrEqual: ++ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kUint32LessThan: ++ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kUint32LessThanOrEqual: ++ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kFloat32Equal: ++ cont->OverwriteAndNegateIfEqual(kUnorderedEqual); ++ return VisitFloat32Compare(selector, value, cont); ++ case IrOpcode::kFloat32LessThan: ++ cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan); ++ return VisitFloat32Compare(selector, value, cont); ++ case IrOpcode::kFloat32LessThanOrEqual: ++ cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual); ++ return VisitFloat32Compare(selector, value, cont); ++ case IrOpcode::kFloat64Equal: ++ cont->OverwriteAndNegateIfEqual(kUnorderedEqual); ++ return VisitFloat64Compare(selector, value, cont); ++ case IrOpcode::kFloat64LessThan: ++ cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThan); ++ return VisitFloat64Compare(selector, value, cont); ++ case IrOpcode::kFloat64LessThanOrEqual: ++ cont->OverwriteAndNegateIfEqual(kUnsignedGreaterThanOrEqual); ++ return VisitFloat64Compare(selector, value, cont); ++ case IrOpcode::kProjection: ++ // Check if this is the overflow output projection of an ++ // WithOverflow node. ++ if (ProjectionIndexOf(value->op()) == 1u) { ++ // We cannot combine the WithOverflow with this branch ++ // unless the 0th projection (the use of the actual value of the ++ // is either nullptr, which means there's no use of the ++ // actual value, or was already defined, which means it is scheduled ++ // *AFTER* this branch). ++ Node* const node = value->InputAt(0); ++ Node* const result = NodeProperties::FindProjection(node, 0); ++ if (result == nullptr || selector->IsDefined(result)) { ++ switch (node->opcode()) { ++ case IrOpcode::kInt32AddWithOverflow: ++ cont->OverwriteAndNegateIfEqual(kOverflow); ++ return VisitBinop(selector, node, kX87Add, cont); ++ case IrOpcode::kInt32SubWithOverflow: ++ cont->OverwriteAndNegateIfEqual(kOverflow); ++ return VisitBinop(selector, node, kX87Sub, cont); ++ case IrOpcode::kInt32MulWithOverflow: ++ cont->OverwriteAndNegateIfEqual(kOverflow); ++ return VisitBinop(selector, node, kX87Imul, cont); ++ default: ++ break; ++ } ++ } ++ } ++ break; ++ case IrOpcode::kInt32Sub: ++ return VisitWordCompare(selector, value, cont); ++ case IrOpcode::kWord32And: ++ return VisitWordCompare(selector, value, kX87Test, cont); ++ default: ++ break; ++ } ++ } ++ ++ // Continuation could not be combined with a compare, emit compare against 0. ++ X87OperandGenerator g(selector); ++ VisitCompare(selector, kX87Cmp, g.Use(value), g.TempImmediate(0), cont); ++} ++ ++} // namespace ++ ++ ++void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, ++ BasicBlock* fbranch) { ++ FlagsContinuation cont(kNotEqual, tbranch, fbranch); ++ VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); ++} ++ ++void InstructionSelector::VisitDeoptimizeIf(Node* node) { ++ DeoptimizeParameters p = DeoptimizeParametersOf(node->op()); ++ FlagsContinuation cont = FlagsContinuation::ForDeoptimize( ++ kNotEqual, p.kind(), p.reason(), node->InputAt(1)); ++ VisitWordCompareZero(this, node, node->InputAt(0), &cont); ++} ++ ++void InstructionSelector::VisitDeoptimizeUnless(Node* node) { ++ DeoptimizeParameters p = DeoptimizeParametersOf(node->op()); ++ FlagsContinuation cont = FlagsContinuation::ForDeoptimize( ++ kEqual, p.kind(), p.reason(), node->InputAt(1)); ++ VisitWordCompareZero(this, node, node->InputAt(0), &cont); ++} ++ ++void InstructionSelector::VisitTrapIf(Node* node, Runtime::FunctionId func_id) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForTrap(kNotEqual, func_id, node->InputAt(1)); ++ VisitWordCompareZero(this, node, node->InputAt(0), &cont); ++} ++ ++void InstructionSelector::VisitTrapUnless(Node* node, ++ Runtime::FunctionId func_id) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForTrap(kEqual, func_id, node->InputAt(1)); ++ VisitWordCompareZero(this, node, node->InputAt(0), &cont); ++} ++ ++void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { ++ X87OperandGenerator g(this); ++ InstructionOperand value_operand = g.UseRegister(node->InputAt(0)); ++ ++ // Emit either ArchTableSwitch or ArchLookupSwitch. ++ static const size_t kMaxTableSwitchValueRange = 2 << 16; ++ size_t table_space_cost = 4 + sw.value_range; ++ size_t table_time_cost = 3; ++ size_t lookup_space_cost = 3 + 2 * sw.case_count; ++ size_t lookup_time_cost = sw.case_count; ++ if (sw.case_count > 4 && ++ table_space_cost + 3 * table_time_cost <= ++ lookup_space_cost + 3 * lookup_time_cost && ++ sw.min_value > std::numeric_limits::min() && ++ sw.value_range <= kMaxTableSwitchValueRange) { ++ InstructionOperand index_operand = value_operand; ++ if (sw.min_value) { ++ index_operand = g.TempRegister(); ++ Emit(kX87Lea | AddressingModeField::encode(kMode_MRI), index_operand, ++ value_operand, g.TempImmediate(-sw.min_value)); ++ } ++ // Generate a table lookup. ++ return EmitTableSwitch(sw, index_operand); ++ } ++ ++ // Generate a sequence of conditional jumps. ++ return EmitLookupSwitch(sw, value_operand); ++} ++ ++ ++void InstructionSelector::VisitWord32Equal(Node* const node) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); ++ Int32BinopMatcher m(node); ++ if (m.right().Is(0)) { ++ return VisitWordCompareZero(this, m.node(), m.left().node(), &cont); ++ } ++ VisitWordCompare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitInt32LessThan(Node* node) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); ++ VisitWordCompare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); ++ VisitWordCompare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitUint32LessThan(Node* node) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); ++ VisitWordCompare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); ++ VisitWordCompare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { ++ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); ++ return VisitBinop(this, node, kX87Add, &cont); ++ } ++ FlagsContinuation cont; ++ VisitBinop(this, node, kX87Add, &cont); ++} ++ ++ ++void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { ++ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); ++ return VisitBinop(this, node, kX87Sub, &cont); ++ } ++ FlagsContinuation cont; ++ VisitBinop(this, node, kX87Sub, &cont); ++} ++ ++void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { ++ if (Node* ovf = NodeProperties::FindProjection(node, 1)) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); ++ return VisitBinop(this, node, kX87Imul, &cont); ++ } ++ FlagsContinuation cont; ++ VisitBinop(this, node, kX87Imul, &cont); ++} ++ ++void InstructionSelector::VisitFloat32Equal(Node* node) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node); ++ VisitFloat32Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat32LessThan(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kUnsignedGreaterThan, node); ++ VisitFloat32Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node); ++ VisitFloat32Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat64Equal(Node* node) { ++ FlagsContinuation cont = FlagsContinuation::ForSet(kUnorderedEqual, node); ++ VisitFloat64Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat64LessThan(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kUnsignedGreaterThan, node); ++ VisitFloat64Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { ++ FlagsContinuation cont = ++ FlagsContinuation::ForSet(kUnsignedGreaterThanOrEqual, node); ++ VisitFloat64Compare(this, node, &cont); ++} ++ ++ ++void InstructionSelector::VisitFloat64ExtractLowWord32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ExtractLowWord32, g.DefineAsRegister(node), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64ExtractHighWord32(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87Float64ExtractHighWord32, g.DefineAsRegister(node), ++ g.Use(node->InputAt(0))); ++} ++ ++ ++void InstructionSelector::VisitFloat64InsertLowWord32(Node* node) { ++ X87OperandGenerator g(this); ++ Node* left = node->InputAt(0); ++ Node* right = node->InputAt(1); ++ Emit(kX87Float64InsertLowWord32, g.UseFixed(node, stX_0), g.UseRegister(left), ++ g.UseRegister(right)); ++} ++ ++ ++void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { ++ X87OperandGenerator g(this); ++ Node* left = node->InputAt(0); ++ Node* right = node->InputAt(1); ++ Emit(kX87Float64InsertHighWord32, g.UseFixed(node, stX_0), ++ g.UseRegister(left), g.UseRegister(right)); ++} ++ ++void InstructionSelector::VisitFloat64SilenceNaN(Node* node) { ++ X87OperandGenerator g(this); ++ Emit(kX87PushFloat64, g.NoOutput(), g.Use(node->InputAt(0))); ++ Emit(kX87Float64SilenceNaN, g.DefineAsFixed(node, stX_0), 0, nullptr); ++} ++ ++void InstructionSelector::VisitAtomicLoad(Node* node) { ++ LoadRepresentation load_rep = LoadRepresentationOf(node->op()); ++ DCHECK(load_rep.representation() == MachineRepresentation::kWord8 || ++ load_rep.representation() == MachineRepresentation::kWord16 || ++ load_rep.representation() == MachineRepresentation::kWord32); ++ USE(load_rep); ++ VisitLoad(node); ++} ++ ++void InstructionSelector::VisitAtomicStore(Node* node) { ++ X87OperandGenerator g(this); ++ Node* base = node->InputAt(0); ++ Node* index = node->InputAt(1); ++ Node* value = node->InputAt(2); ++ ++ MachineRepresentation rep = AtomicStoreRepresentationOf(node->op()); ++ ArchOpcode opcode = kArchNop; ++ switch (rep) { ++ case MachineRepresentation::kWord8: ++ opcode = kX87Xchgb; ++ break; ++ case MachineRepresentation::kWord16: ++ opcode = kX87Xchgw; ++ break; ++ case MachineRepresentation::kWord32: ++ opcode = kX87Xchgl; ++ break; ++ default: ++ UNREACHABLE(); ++ break; ++ } ++ AddressingMode addressing_mode; ++ InstructionOperand inputs[4]; ++ size_t input_count = 0; ++ inputs[input_count++] = g.UseUniqueRegister(base); ++ if (g.CanBeImmediate(index)) { ++ inputs[input_count++] = g.UseImmediate(index); ++ addressing_mode = kMode_MRI; ++ } else { ++ inputs[input_count++] = g.UseUniqueRegister(index); ++ addressing_mode = kMode_MR1; ++ } ++ inputs[input_count++] = g.UseUniqueRegister(value); ++ InstructionCode code = opcode | AddressingModeField::encode(addressing_mode); ++ Emit(code, 0, nullptr, input_count, inputs); ++} ++ ++void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) { ++ UNREACHABLE(); ++} ++ ++void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) { ++ UNREACHABLE(); ++} ++ ++// static ++MachineOperatorBuilder::Flags ++InstructionSelector::SupportedMachineOperatorFlags() { ++ MachineOperatorBuilder::Flags flags = ++ MachineOperatorBuilder::kWord32ShiftIsSafe; ++ if (CpuFeatures::IsSupported(POPCNT)) { ++ flags |= MachineOperatorBuilder::kWord32Popcnt; ++ } ++ ++ flags |= MachineOperatorBuilder::kFloat32RoundDown | ++ MachineOperatorBuilder::kFloat64RoundDown | ++ MachineOperatorBuilder::kFloat32RoundUp | ++ MachineOperatorBuilder::kFloat64RoundUp | ++ MachineOperatorBuilder::kFloat32RoundTruncate | ++ MachineOperatorBuilder::kFloat64RoundTruncate | ++ MachineOperatorBuilder::kFloat32RoundTiesEven | ++ MachineOperatorBuilder::kFloat64RoundTiesEven; ++ return flags; ++} ++ ++// static ++MachineOperatorBuilder::AlignmentRequirements ++InstructionSelector::AlignmentRequirements() { ++ return MachineOperatorBuilder::AlignmentRequirements:: ++ FullUnalignedAccessSupport(); ++} ++ ++} // namespace compiler ++} // namespace internal ++} // namespace v8 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/compiler/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/compiler/x87/OWNERS 2017-12-25 17:42:57.205465793 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/debug/x87/debug-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/debug/x87/debug-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/debug/x87/debug-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/debug/x87/debug-x87.cc 2017-12-25 17:42:57.210465720 +0100 +@@ -0,0 +1,157 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/debug/debug.h" ++ ++#include "src/codegen.h" ++#include "src/debug/liveedit.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm) ++ ++ ++void EmitDebugBreakSlot(MacroAssembler* masm) { ++ Label check_codesize; ++ __ bind(&check_codesize); ++ __ Nop(Assembler::kDebugBreakSlotLength); ++ DCHECK_EQ(Assembler::kDebugBreakSlotLength, ++ masm->SizeOfCodeGeneratedSince(&check_codesize)); ++} ++ ++ ++void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) { ++ // Generate enough nop's to make space for a call instruction. ++ masm->RecordDebugBreakSlot(mode); ++ EmitDebugBreakSlot(masm); ++} ++ ++ ++void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { ++ CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength); ++ EmitDebugBreakSlot(patcher.masm()); ++} ++ ++ ++void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, ++ Handle code) { ++ DCHECK(code->is_debug_stub()); ++ static const int kSize = Assembler::kDebugBreakSlotLength; ++ CodePatcher patcher(isolate, pc, kSize); ++ ++ // Add a label for checking the size of the code used for returning. ++ Label check_codesize; ++ patcher.masm()->bind(&check_codesize); ++ patcher.masm()->call(code->entry(), RelocInfo::NONE32); ++ // Check that the size of the code generated is as expected. ++ DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); ++} ++ ++bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { ++ return !Assembler::IsNop(pc); ++} ++ ++void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, ++ DebugBreakCallHelperMode mode) { ++ __ RecordComment("Debug break"); ++ ++ // Enter an internal frame. ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Load padding words on stack. ++ for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { ++ __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); ++ } ++ __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); ++ ++ // Push arguments for DebugBreak call. ++ if (mode == SAVE_RESULT_REGISTER) { ++ // Break on return. ++ __ push(eax); ++ } else { ++ // Non-return breaks. ++ __ Push(masm->isolate()->factory()->the_hole_value()); ++ } ++ __ Move(eax, Immediate(1)); ++ __ mov(ebx, ++ Immediate(ExternalReference( ++ Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); ++ ++ CEntryStub ceb(masm->isolate(), 1); ++ __ CallStub(&ceb); ++ ++ if (FLAG_debug_code) { ++ for (int i = 0; i < kNumJSCallerSaved; ++i) { ++ Register reg = {JSCallerSavedCode(i)}; ++ // Do not clobber eax if mode is SAVE_RESULT_REGISTER. It will ++ // contain return value of the function. ++ if (!(reg.is(eax) && (mode == SAVE_RESULT_REGISTER))) { ++ __ Move(reg, Immediate(kDebugZapValue)); ++ } ++ } ++ } ++ ++ __ pop(ebx); ++ // We divide stored value by 2 (untagging) and multiply it by word's size. ++ STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); ++ __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0)); ++ ++ // Get rid of the internal frame. ++ } ++ ++ // This call did not replace a call , so there will be an unwanted ++ // return address left on the stack. Here we get rid of that. ++ __ add(esp, Immediate(kPointerSize)); ++ ++ // Now that the break point has been handled, resume normal execution by ++ // jumping to the target address intended by the caller and that was ++ // overwritten by the address of DebugBreakXXX. ++ ExternalReference after_break_target = ++ ExternalReference::debug_after_break_target_address(masm->isolate()); ++ __ jmp(Operand::StaticVariable(after_break_target)); ++} ++ ++ ++void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { ++ // We do not know our frame height, but set esp based on ebp. ++ __ lea(esp, Operand(ebp, FrameDropperFrameConstants::kFunctionOffset)); ++ __ pop(edi); // Function. ++ __ add(esp, Immediate(-FrameDropperFrameConstants::kCodeOffset)); // INTERNAL ++ // frame ++ // marker ++ // and code ++ __ pop(ebp); ++ ++ ParameterCount dummy(0); ++ __ CheckDebugHook(edi, no_reg, dummy, dummy); ++ ++ // Load context from the function. ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ // Clear new.target register as a safety measure. ++ __ mov(edx, masm->isolate()->factory()->undefined_value()); ++ ++ // Get function code. ++ __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset)); ++ __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); ++ ++ // Re-run JSFunction, edi is function, esi is context. ++ __ jmp(ebx); ++} ++ ++ ++const bool LiveEdit::kFrameDropperSupported = true; ++ ++#undef __ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/debug/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/debug/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/debug/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/debug/x87/OWNERS 2017-12-25 17:42:57.210465720 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/frames-inl.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/frames-inl.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/frames-inl.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/frames-inl.h 2017-12-25 17:42:57.210465720 +0100 +@@ -26,6 +26,8 @@ + #include "src/mips64/frames-mips64.h" // NOLINT + #elif V8_TARGET_ARCH_S390 + #include "src/s390/frames-s390.h" // NOLINT ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/frames-x87.h" // NOLINT + #else + #error Unsupported target architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/full-codegen.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/full-codegen.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/full-codegen.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/full-codegen.h 2017-12-25 17:42:57.211465705 +0100 +@@ -45,7 +45,7 @@ + static const int kMaxBackEdgeWeight = 127; + + // Platform-specific code size multiplier. +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + static const int kCodeSizeMultiplier = 105; + #elif V8_TARGET_ARCH_X64 + static const int kCodeSizeMultiplier = 165; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/x87/full-codegen-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/x87/full-codegen-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/x87/full-codegen-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/x87/full-codegen-x87.cc 2017-12-25 17:42:57.213465676 +0100 +@@ -0,0 +1,2425 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/ast/compile-time-value.h" ++#include "src/ast/scopes.h" ++#include "src/builtins/builtins-constructor.h" ++#include "src/code-factory.h" ++#include "src/code-stubs.h" ++#include "src/codegen.h" ++#include "src/compilation-info.h" ++#include "src/compiler.h" ++#include "src/debug/debug.h" ++#include "src/full-codegen/full-codegen.h" ++#include "src/ic/ic.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm()) ++ ++class JumpPatchSite BASE_EMBEDDED { ++ public: ++ explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { ++#ifdef DEBUG ++ info_emitted_ = false; ++#endif ++ } ++ ++ ~JumpPatchSite() { ++ DCHECK(patch_site_.is_bound() == info_emitted_); ++ } ++ ++ void EmitJumpIfNotSmi(Register reg, ++ Label* target, ++ Label::Distance distance = Label::kFar) { ++ __ test(reg, Immediate(kSmiTagMask)); ++ EmitJump(not_carry, target, distance); // Always taken before patched. ++ } ++ ++ void EmitJumpIfSmi(Register reg, ++ Label* target, ++ Label::Distance distance = Label::kFar) { ++ __ test(reg, Immediate(kSmiTagMask)); ++ EmitJump(carry, target, distance); // Never taken before patched. ++ } ++ ++ void EmitPatchInfo() { ++ if (patch_site_.is_bound()) { ++ int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); ++ DCHECK(is_uint8(delta_to_patch_site)); ++ __ test(eax, Immediate(delta_to_patch_site)); ++#ifdef DEBUG ++ info_emitted_ = true; ++#endif ++ } else { ++ __ nop(); // Signals no inlined code. ++ } ++ } ++ ++ private: ++ // jc will be patched with jz, jnc will become jnz. ++ void EmitJump(Condition cc, Label* target, Label::Distance distance) { ++ DCHECK(!patch_site_.is_bound() && !info_emitted_); ++ DCHECK(cc == carry || cc == not_carry); ++ __ bind(&patch_site_); ++ __ j(cc, target, distance); ++ } ++ ++ MacroAssembler* masm() { return masm_; } ++ MacroAssembler* masm_; ++ Label patch_site_; ++#ifdef DEBUG ++ bool info_emitted_; ++#endif ++}; ++ ++ ++// Generate code for a JS function. On entry to the function the receiver ++// and arguments have been pushed on the stack left to right, with the ++// return address on top of them. The actual argument count matches the ++// formal parameter count expected by the function. ++// ++// The live registers are: ++// o edi: the JS function object being called (i.e. ourselves) ++// o edx: the new target value ++// o esi: our context ++// o ebp: our caller's frame pointer ++// o esp: stack pointer (pointing to return address) ++// ++// The function builds a JS frame. Please see JavaScriptFrameConstants in ++// frames-x87.h for its layout. ++void FullCodeGenerator::Generate() { ++ CompilationInfo* info = info_; ++ profiling_counter_ = isolate()->factory()->NewCell( ++ Handle(Smi::FromInt(FLAG_interrupt_budget), isolate())); ++ SetFunctionPosition(literal()); ++ Comment cmnt(masm_, "[ function compiled by full code generator"); ++ ++ ProfileEntryHookStub::MaybeCallEntryHook(masm_); ++ ++ if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) { ++ int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; ++ __ mov(ecx, Operand(esp, receiver_offset)); ++ __ AssertNotSmi(ecx); ++ __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ Assert(above_equal, kSloppyFunctionExpectsJSReceiverReceiver); ++ } ++ ++ // Open a frame scope to indicate that there is a frame on the stack. The ++ // MANUAL indicates that the scope shouldn't actually generate code to set up ++ // the frame (that is done below). ++ FrameScope frame_scope(masm_, StackFrame::MANUAL); ++ ++ info->set_prologue_offset(masm_->pc_offset()); ++ __ Prologue(info->GeneratePreagedPrologue()); ++ ++ // Increment invocation count for the function. ++ { ++ Comment cmnt(masm_, "[ Increment invocation count"); ++ __ mov(ecx, FieldOperand(edi, JSFunction::kFeedbackVectorOffset)); ++ __ mov(ecx, FieldOperand(ecx, Cell::kValueOffset)); ++ __ add( ++ FieldOperand(ecx, FeedbackVector::kInvocationCountIndex * kPointerSize + ++ FeedbackVector::kHeaderSize), ++ Immediate(Smi::FromInt(1))); ++ } ++ ++ { Comment cmnt(masm_, "[ Allocate locals"); ++ int locals_count = info->scope()->num_stack_slots(); ++ OperandStackDepthIncrement(locals_count); ++ if (locals_count == 1) { ++ __ push(Immediate(isolate()->factory()->undefined_value())); ++ } else if (locals_count > 1) { ++ if (locals_count >= 128) { ++ Label ok; ++ __ mov(ecx, esp); ++ __ sub(ecx, Immediate(locals_count * kPointerSize)); ++ ExternalReference stack_limit = ++ ExternalReference::address_of_real_stack_limit(isolate()); ++ __ cmp(ecx, Operand::StaticVariable(stack_limit)); ++ __ j(above_equal, &ok, Label::kNear); ++ __ CallRuntime(Runtime::kThrowStackOverflow); ++ __ bind(&ok); ++ } ++ __ mov(eax, Immediate(isolate()->factory()->undefined_value())); ++ const int kMaxPushes = 32; ++ if (locals_count >= kMaxPushes) { ++ int loop_iterations = locals_count / kMaxPushes; ++ __ mov(ecx, loop_iterations); ++ Label loop_header; ++ __ bind(&loop_header); ++ // Do pushes. ++ for (int i = 0; i < kMaxPushes; i++) { ++ __ push(eax); ++ } ++ __ dec(ecx); ++ __ j(not_zero, &loop_header, Label::kNear); ++ } ++ int remaining = locals_count % kMaxPushes; ++ // Emit the remaining pushes. ++ for (int i = 0; i < remaining; i++) { ++ __ push(eax); ++ } ++ } ++ } ++ ++ bool function_in_register = true; ++ ++ // Possibly allocate a local context. ++ if (info->scope()->NeedsContext()) { ++ Comment cmnt(masm_, "[ Allocate context"); ++ bool need_write_barrier = true; ++ int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; ++ // Argument to NewContext is the function, which is still in edi. ++ if (info->scope()->is_script_scope()) { ++ __ push(edi); ++ __ Push(info->scope()->scope_info()); ++ __ CallRuntime(Runtime::kNewScriptContext); ++ // The new target value is not used, clobbering is safe. ++ DCHECK_NULL(info->scope()->new_target_var()); ++ } else { ++ if (info->scope()->new_target_var() != nullptr) { ++ __ push(edx); // Preserve new target. ++ } ++ if (slots <= ConstructorBuiltins::MaximumFunctionContextSlots()) { ++ Callable callable = CodeFactory::FastNewFunctionContext( ++ isolate(), info->scope()->scope_type()); ++ __ mov(FastNewFunctionContextDescriptor::SlotsRegister(), ++ Immediate(slots)); ++ __ Call(callable.code(), RelocInfo::CODE_TARGET); ++ // Result of the FastNewFunctionContext builtin is always in new space. ++ need_write_barrier = false; ++ } else { ++ __ push(edi); ++ __ Push(Smi::FromInt(info->scope()->scope_type())); ++ __ CallRuntime(Runtime::kNewFunctionContext); ++ } ++ if (info->scope()->new_target_var() != nullptr) { ++ __ pop(edx); // Restore new target. ++ } ++ } ++ function_in_register = false; ++ // Context is returned in eax. It replaces the context passed to us. ++ // It's saved in the stack and kept live in esi. ++ __ mov(esi, eax); ++ __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax); ++ ++ // Copy parameters into context if necessary. ++ int num_parameters = info->scope()->num_parameters(); ++ int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; ++ for (int i = first_parameter; i < num_parameters; i++) { ++ Variable* var = ++ (i == -1) ? info->scope()->receiver() : info->scope()->parameter(i); ++ if (var->IsContextSlot()) { ++ int parameter_offset = StandardFrameConstants::kCallerSPOffset + ++ (num_parameters - 1 - i) * kPointerSize; ++ // Load parameter from stack. ++ __ mov(eax, Operand(ebp, parameter_offset)); ++ // Store it in the context. ++ int context_offset = Context::SlotOffset(var->index()); ++ __ mov(Operand(esi, context_offset), eax); ++ // Update the write barrier. This clobbers eax and ebx. ++ if (need_write_barrier) { ++ __ RecordWriteContextSlot(esi, context_offset, eax, ebx, ++ kDontSaveFPRegs); ++ } else if (FLAG_debug_code) { ++ Label done; ++ __ JumpIfInNewSpace(esi, eax, &done, Label::kNear); ++ __ Abort(kExpectedNewSpaceObject); ++ __ bind(&done); ++ } ++ } ++ } ++ } ++ ++ // We don't support new.target and rest parameters here. ++ DCHECK_NULL(info->scope()->new_target_var()); ++ DCHECK_NULL(info->scope()->rest_parameter()); ++ DCHECK_NULL(info->scope()->this_function_var()); ++ ++ Variable* arguments = info->scope()->arguments(); ++ if (arguments != NULL) { ++ // Arguments object must be allocated after the context object, in ++ // case the "arguments" or ".arguments" variables are in the context. ++ Comment cmnt(masm_, "[ Allocate arguments object"); ++ if (!function_in_register) { ++ __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ } ++ if (is_strict(language_mode()) || !has_simple_parameters()) { ++ FastNewStrictArgumentsStub stub(isolate()); ++ __ CallStub(&stub); ++ } else if (literal()->has_duplicate_parameters()) { ++ __ Push(edi); ++ __ CallRuntime(Runtime::kNewSloppyArguments_Generic); ++ } else { ++ FastNewSloppyArgumentsStub stub(isolate()); ++ __ CallStub(&stub); ++ } ++ ++ SetVar(arguments, eax, ebx, edx); ++ } ++ ++ if (FLAG_trace) { ++ __ CallRuntime(Runtime::kTraceEnter); ++ } ++ ++ // Visit the declarations and body. ++ { ++ Comment cmnt(masm_, "[ Declarations"); ++ VisitDeclarations(scope()->declarations()); ++ } ++ ++ // Assert that the declarations do not use ICs. Otherwise the debugger ++ // won't be able to redirect a PC at an IC to the correct IC in newly ++ // recompiled code. ++ DCHECK_EQ(0, ic_total_count_); ++ ++ { ++ Comment cmnt(masm_, "[ Stack check"); ++ Label ok; ++ ExternalReference stack_limit = ++ ExternalReference::address_of_stack_limit(isolate()); ++ __ cmp(esp, Operand::StaticVariable(stack_limit)); ++ __ j(above_equal, &ok, Label::kNear); ++ __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); ++ __ bind(&ok); ++ } ++ ++ { ++ Comment cmnt(masm_, "[ Body"); ++ DCHECK(loop_depth() == 0); ++ VisitStatements(literal()->body()); ++ DCHECK(loop_depth() == 0); ++ } ++ ++ // Always emit a 'return undefined' in case control fell off the end of ++ // the body. ++ { Comment cmnt(masm_, "[ return ;"); ++ __ mov(eax, isolate()->factory()->undefined_value()); ++ EmitReturnSequence(); ++ } ++} ++ ++ ++void FullCodeGenerator::ClearAccumulator() { ++ __ Move(eax, Immediate(Smi::kZero)); ++} ++ ++ ++void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { ++ __ mov(ebx, Immediate(profiling_counter_)); ++ __ sub(FieldOperand(ebx, Cell::kValueOffset), ++ Immediate(Smi::FromInt(delta))); ++} ++ ++ ++void FullCodeGenerator::EmitProfilingCounterReset() { ++ int reset_value = FLAG_interrupt_budget; ++ __ mov(ebx, Immediate(profiling_counter_)); ++ __ mov(FieldOperand(ebx, Cell::kValueOffset), ++ Immediate(Smi::FromInt(reset_value))); ++} ++ ++ ++void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, ++ Label* back_edge_target) { ++ Comment cmnt(masm_, "[ Back edge bookkeeping"); ++ Label ok; ++ ++ DCHECK(back_edge_target->is_bound()); ++ int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); ++ int weight = Min(kMaxBackEdgeWeight, ++ Max(1, distance / kCodeSizeMultiplier)); ++ EmitProfilingCounterDecrement(weight); ++ __ j(positive, &ok, Label::kNear); ++ __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); ++ ++ // Record a mapping of this PC offset to the OSR id. This is used to find ++ // the AST id from the unoptimized code in order to use it as a key into ++ // the deoptimization input data found in the optimized code. ++ RecordBackEdge(stmt->OsrEntryId()); ++ ++ EmitProfilingCounterReset(); ++ ++ __ bind(&ok); ++} ++ ++void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence( ++ bool is_tail_call) { ++ // Pretend that the exit is a backwards jump to the entry. ++ int weight = 1; ++ if (info_->ShouldSelfOptimize()) { ++ weight = FLAG_interrupt_budget / FLAG_self_opt_count; ++ } else { ++ int distance = masm_->pc_offset(); ++ weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); ++ } ++ EmitProfilingCounterDecrement(weight); ++ Label ok; ++ __ j(positive, &ok, Label::kNear); ++ // Don't need to save result register if we are going to do a tail call. ++ if (!is_tail_call) { ++ __ push(eax); ++ } ++ __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); ++ if (!is_tail_call) { ++ __ pop(eax); ++ } ++ EmitProfilingCounterReset(); ++ __ bind(&ok); ++} ++ ++void FullCodeGenerator::EmitReturnSequence() { ++ Comment cmnt(masm_, "[ Return sequence"); ++ if (return_label_.is_bound()) { ++ __ jmp(&return_label_); ++ } else { ++ // Common return label ++ __ bind(&return_label_); ++ if (FLAG_trace) { ++ __ push(eax); ++ __ CallRuntime(Runtime::kTraceExit); ++ } ++ EmitProfilingCounterHandlingForReturnSequence(false); ++ ++ SetReturnPosition(literal()); ++ __ leave(); ++ ++ int arg_count = info_->scope()->num_parameters() + 1; ++ int arguments_bytes = arg_count * kPointerSize; ++ __ Ret(arguments_bytes, ecx); ++ } ++} ++ ++void FullCodeGenerator::RestoreContext() { ++ __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); ++} ++ ++void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { ++ DCHECK(var->IsStackAllocated() || var->IsContextSlot()); ++ MemOperand operand = codegen()->VarOperand(var, result_register()); ++ // Memory operands can be pushed directly. ++ codegen()->PushOperand(operand); ++} ++ ++ ++void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { ++ UNREACHABLE(); // Not used on X87. ++} ++ ++ ++void FullCodeGenerator::AccumulatorValueContext::Plug( ++ Heap::RootListIndex index) const { ++ UNREACHABLE(); // Not used on X87. ++} ++ ++ ++void FullCodeGenerator::StackValueContext::Plug( ++ Heap::RootListIndex index) const { ++ UNREACHABLE(); // Not used on X87. ++} ++ ++ ++void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { ++ UNREACHABLE(); // Not used on X87. ++} ++ ++ ++void FullCodeGenerator::EffectContext::Plug(Handle lit) const { ++} ++ ++ ++void FullCodeGenerator::AccumulatorValueContext::Plug( ++ Handle lit) const { ++ if (lit->IsSmi()) { ++ __ SafeMove(result_register(), Immediate(lit)); ++ } else { ++ __ Move(result_register(), Immediate(lit)); ++ } ++} ++ ++ ++void FullCodeGenerator::StackValueContext::Plug(Handle lit) const { ++ codegen()->OperandStackDepthIncrement(1); ++ if (lit->IsSmi()) { ++ __ SafePush(Immediate(lit)); ++ } else { ++ __ push(Immediate(lit)); ++ } ++} ++ ++ ++void FullCodeGenerator::TestContext::Plug(Handle lit) const { ++ DCHECK(lit->IsNullOrUndefined(isolate()) || !lit->IsUndetectable()); ++ if (lit->IsNullOrUndefined(isolate()) || lit->IsFalse(isolate())) { ++ if (false_label_ != fall_through_) __ jmp(false_label_); ++ } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) { ++ if (true_label_ != fall_through_) __ jmp(true_label_); ++ } else if (lit->IsString()) { ++ if (String::cast(*lit)->length() == 0) { ++ if (false_label_ != fall_through_) __ jmp(false_label_); ++ } else { ++ if (true_label_ != fall_through_) __ jmp(true_label_); ++ } ++ } else if (lit->IsSmi()) { ++ if (Smi::ToInt(*lit) == 0) { ++ if (false_label_ != fall_through_) __ jmp(false_label_); ++ } else { ++ if (true_label_ != fall_through_) __ jmp(true_label_); ++ } ++ } else { ++ // For simplicity we always test the accumulator register. ++ __ mov(result_register(), lit); ++ codegen()->DoTest(this); ++ } ++} ++ ++ ++void FullCodeGenerator::StackValueContext::DropAndPlug(int count, ++ Register reg) const { ++ DCHECK(count > 0); ++ if (count > 1) codegen()->DropOperands(count - 1); ++ __ mov(Operand(esp, 0), reg); ++} ++ ++ ++void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, ++ Label* materialize_false) const { ++ DCHECK(materialize_true == materialize_false); ++ __ bind(materialize_true); ++} ++ ++ ++void FullCodeGenerator::AccumulatorValueContext::Plug( ++ Label* materialize_true, ++ Label* materialize_false) const { ++ Label done; ++ __ bind(materialize_true); ++ __ mov(result_register(), isolate()->factory()->true_value()); ++ __ jmp(&done, Label::kNear); ++ __ bind(materialize_false); ++ __ mov(result_register(), isolate()->factory()->false_value()); ++ __ bind(&done); ++} ++ ++ ++void FullCodeGenerator::StackValueContext::Plug( ++ Label* materialize_true, ++ Label* materialize_false) const { ++ codegen()->OperandStackDepthIncrement(1); ++ Label done; ++ __ bind(materialize_true); ++ __ push(Immediate(isolate()->factory()->true_value())); ++ __ jmp(&done, Label::kNear); ++ __ bind(materialize_false); ++ __ push(Immediate(isolate()->factory()->false_value())); ++ __ bind(&done); ++} ++ ++ ++void FullCodeGenerator::TestContext::Plug(Label* materialize_true, ++ Label* materialize_false) const { ++ DCHECK(materialize_true == true_label_); ++ DCHECK(materialize_false == false_label_); ++} ++ ++ ++void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { ++ Handle value = flag ++ ? isolate()->factory()->true_value() ++ : isolate()->factory()->false_value(); ++ __ mov(result_register(), value); ++} ++ ++ ++void FullCodeGenerator::StackValueContext::Plug(bool flag) const { ++ codegen()->OperandStackDepthIncrement(1); ++ Handle value = flag ++ ? isolate()->factory()->true_value() ++ : isolate()->factory()->false_value(); ++ __ push(Immediate(value)); ++} ++ ++ ++void FullCodeGenerator::TestContext::Plug(bool flag) const { ++ if (flag) { ++ if (true_label_ != fall_through_) __ jmp(true_label_); ++ } else { ++ if (false_label_ != fall_through_) __ jmp(false_label_); ++ } ++} ++ ++ ++void FullCodeGenerator::DoTest(Expression* condition, ++ Label* if_true, ++ Label* if_false, ++ Label* fall_through) { ++ Callable callable = Builtins::CallableFor(isolate(), Builtins::kToBoolean); ++ __ Call(callable.code(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); ++ Split(equal, if_true, if_false, fall_through); ++} ++ ++ ++void FullCodeGenerator::Split(Condition cc, ++ Label* if_true, ++ Label* if_false, ++ Label* fall_through) { ++ if (if_false == fall_through) { ++ __ j(cc, if_true); ++ } else if (if_true == fall_through) { ++ __ j(NegateCondition(cc), if_false); ++ } else { ++ __ j(cc, if_true); ++ __ jmp(if_false); ++ } ++} ++ ++ ++MemOperand FullCodeGenerator::StackOperand(Variable* var) { ++ DCHECK(var->IsStackAllocated()); ++ // Offset is negative because higher indexes are at lower addresses. ++ int offset = -var->index() * kPointerSize; ++ // Adjust by a (parameter or local) base offset. ++ if (var->IsParameter()) { ++ offset += (info_->scope()->num_parameters() + 1) * kPointerSize; ++ } else { ++ offset += JavaScriptFrameConstants::kLocal0Offset; ++ } ++ return Operand(ebp, offset); ++} ++ ++ ++MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { ++ DCHECK(var->IsContextSlot() || var->IsStackAllocated()); ++ if (var->IsContextSlot()) { ++ int context_chain_length = scope()->ContextChainLength(var->scope()); ++ __ LoadContext(scratch, context_chain_length); ++ return ContextOperand(scratch, var->index()); ++ } else { ++ return StackOperand(var); ++ } ++} ++ ++ ++void FullCodeGenerator::GetVar(Register dest, Variable* var) { ++ DCHECK(var->IsContextSlot() || var->IsStackAllocated()); ++ MemOperand location = VarOperand(var, dest); ++ __ mov(dest, location); ++} ++ ++ ++void FullCodeGenerator::SetVar(Variable* var, ++ Register src, ++ Register scratch0, ++ Register scratch1) { ++ DCHECK(var->IsContextSlot() || var->IsStackAllocated()); ++ DCHECK(!scratch0.is(src)); ++ DCHECK(!scratch0.is(scratch1)); ++ DCHECK(!scratch1.is(src)); ++ MemOperand location = VarOperand(var, scratch0); ++ __ mov(location, src); ++ ++ // Emit the write barrier code if the location is in the heap. ++ if (var->IsContextSlot()) { ++ int offset = Context::SlotOffset(var->index()); ++ DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); ++ __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs); ++ } ++} ++ ++ ++void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { ++ // The variable in the declaration always resides in the current context. ++ DCHECK_EQ(0, scope()->ContextChainLength(variable->scope())); ++ if (FLAG_debug_code) { ++ // Check that we're not inside a with or catch context. ++ __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); ++ __ cmp(ebx, isolate()->factory()->with_context_map()); ++ __ Check(not_equal, kDeclarationInWithContext); ++ __ cmp(ebx, isolate()->factory()->catch_context_map()); ++ __ Check(not_equal, kDeclarationInCatchContext); ++ } ++} ++ ++ ++void FullCodeGenerator::VisitVariableDeclaration( ++ VariableDeclaration* declaration) { ++ VariableProxy* proxy = declaration->proxy(); ++ Variable* variable = proxy->var(); ++ switch (variable->location()) { ++ case VariableLocation::UNALLOCATED: { ++ DCHECK(!variable->binding_needs_init()); ++ globals_->Add(variable->name(), zone()); ++ FeedbackSlot slot = proxy->VariableFeedbackSlot(); ++ DCHECK(!slot.IsInvalid()); ++ globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); ++ globals_->Add(isolate()->factory()->undefined_value(), zone()); ++ globals_->Add(isolate()->factory()->undefined_value(), zone()); ++ break; ++ } ++ case VariableLocation::PARAMETER: ++ case VariableLocation::LOCAL: ++ if (variable->binding_needs_init()) { ++ Comment cmnt(masm_, "[ VariableDeclaration"); ++ __ mov(StackOperand(variable), ++ Immediate(isolate()->factory()->the_hole_value())); ++ } ++ break; ++ ++ case VariableLocation::CONTEXT: ++ if (variable->binding_needs_init()) { ++ Comment cmnt(masm_, "[ VariableDeclaration"); ++ EmitDebugCheckDeclarationContext(variable); ++ __ mov(ContextOperand(esi, variable->index()), ++ Immediate(isolate()->factory()->the_hole_value())); ++ // No write barrier since the hole value is in old space. ++ } ++ break; ++ ++ case VariableLocation::LOOKUP: ++ case VariableLocation::MODULE: ++ UNREACHABLE(); ++ } ++} ++ ++void FullCodeGenerator::VisitFunctionDeclaration( ++ FunctionDeclaration* declaration) { ++ VariableProxy* proxy = declaration->proxy(); ++ Variable* variable = proxy->var(); ++ switch (variable->location()) { ++ case VariableLocation::UNALLOCATED: { ++ globals_->Add(variable->name(), zone()); ++ FeedbackSlot slot = proxy->VariableFeedbackSlot(); ++ DCHECK(!slot.IsInvalid()); ++ globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); ++ ++ // We need the slot where the literals array lives, too. ++ slot = declaration->fun()->LiteralFeedbackSlot(); ++ DCHECK(!slot.IsInvalid()); ++ globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); ++ ++ Handle function = ++ Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_); ++ // Check for stack-overflow exception. ++ if (function.is_null()) return SetStackOverflow(); ++ globals_->Add(function, zone()); ++ break; ++ } ++ ++ case VariableLocation::PARAMETER: ++ case VariableLocation::LOCAL: { ++ Comment cmnt(masm_, "[ FunctionDeclaration"); ++ VisitForAccumulatorValue(declaration->fun()); ++ __ mov(StackOperand(variable), result_register()); ++ break; ++ } ++ ++ case VariableLocation::CONTEXT: { ++ Comment cmnt(masm_, "[ FunctionDeclaration"); ++ EmitDebugCheckDeclarationContext(variable); ++ VisitForAccumulatorValue(declaration->fun()); ++ __ mov(ContextOperand(esi, variable->index()), result_register()); ++ // We know that we have written a function, which is not a smi. ++ __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()), ++ result_register(), ecx, kDontSaveFPRegs, ++ EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); ++ break; ++ } ++ ++ case VariableLocation::LOOKUP: ++ case VariableLocation::MODULE: ++ UNREACHABLE(); ++ } ++} ++ ++ ++void FullCodeGenerator::DeclareGlobals(Handle pairs) { ++ // Call the runtime to declare the globals. ++ __ Push(pairs); ++ __ Push(Smi::FromInt(DeclareGlobalsFlags())); ++ __ EmitLoadFeedbackVector(eax); ++ __ Push(eax); ++ __ CallRuntime(Runtime::kDeclareGlobals); ++ // Return value is ignored. ++} ++ ++ ++void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { ++ Comment cmnt(masm_, "[ SwitchStatement"); ++ Breakable nested_statement(this, stmt); ++ SetStatementPosition(stmt); ++ ++ // Keep the switch value on the stack until a case matches. ++ VisitForStackValue(stmt->tag()); ++ ++ ZoneList* clauses = stmt->cases(); ++ CaseClause* default_clause = NULL; // Can occur anywhere in the list. ++ ++ Label next_test; // Recycled for each test. ++ // Compile all the tests with branches to their bodies. ++ for (int i = 0; i < clauses->length(); i++) { ++ CaseClause* clause = clauses->at(i); ++ clause->body_target()->Unuse(); ++ ++ // The default is not a test, but remember it as final fall through. ++ if (clause->is_default()) { ++ default_clause = clause; ++ continue; ++ } ++ ++ Comment cmnt(masm_, "[ Case comparison"); ++ __ bind(&next_test); ++ next_test.Unuse(); ++ ++ // Compile the label expression. ++ VisitForAccumulatorValue(clause->label()); ++ ++ // Perform the comparison as if via '==='. ++ __ mov(edx, Operand(esp, 0)); // Switch value. ++ bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); ++ JumpPatchSite patch_site(masm_); ++ if (inline_smi_code) { ++ Label slow_case; ++ __ mov(ecx, edx); ++ __ or_(ecx, eax); ++ patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); ++ ++ __ cmp(edx, eax); ++ __ j(not_equal, &next_test); ++ __ Drop(1); // Switch value is no longer needed. ++ __ jmp(clause->body_target()); ++ __ bind(&slow_case); ++ } ++ ++ SetExpressionPosition(clause); ++ Handle ic = ++ CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code(); ++ CallIC(ic); ++ patch_site.EmitPatchInfo(); ++ ++ Label skip; ++ __ jmp(&skip, Label::kNear); ++ __ cmp(eax, isolate()->factory()->true_value()); ++ __ j(not_equal, &next_test); ++ __ Drop(1); ++ __ jmp(clause->body_target()); ++ __ bind(&skip); ++ ++ __ test(eax, eax); ++ __ j(not_equal, &next_test); ++ __ Drop(1); // Switch value is no longer needed. ++ __ jmp(clause->body_target()); ++ } ++ ++ // Discard the test value and jump to the default if present, otherwise to ++ // the end of the statement. ++ __ bind(&next_test); ++ DropOperands(1); // Switch value is no longer needed. ++ if (default_clause == NULL) { ++ __ jmp(nested_statement.break_label()); ++ } else { ++ __ jmp(default_clause->body_target()); ++ } ++ ++ // Compile all the case bodies. ++ for (int i = 0; i < clauses->length(); i++) { ++ Comment cmnt(masm_, "[ Case body"); ++ CaseClause* clause = clauses->at(i); ++ __ bind(clause->body_target()); ++ VisitStatements(clause->statements()); ++ } ++ ++ __ bind(nested_statement.break_label()); ++} ++ ++ ++void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { ++ Comment cmnt(masm_, "[ ForInStatement"); ++ SetStatementPosition(stmt, SKIP_BREAK); ++ ++ FeedbackSlot slot = stmt->ForInFeedbackSlot(); ++ ++ // Get the object to enumerate over. ++ SetExpressionAsStatementPosition(stmt->enumerable()); ++ VisitForAccumulatorValue(stmt->enumerable()); ++ OperandStackDepthIncrement(5); ++ ++ Label loop, exit; ++ Iteration loop_statement(this, stmt); ++ increment_loop_depth(); ++ ++ // If the object is null or undefined, skip over the loop, otherwise convert ++ // it to a JS receiver. See ECMA-262 version 5, section 12.6.4. ++ Label convert, done_convert; ++ __ JumpIfSmi(eax, &convert, Label::kNear); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(above_equal, &done_convert, Label::kNear); ++ __ cmp(eax, isolate()->factory()->undefined_value()); ++ __ j(equal, &exit); ++ __ cmp(eax, isolate()->factory()->null_value()); ++ __ j(equal, &exit); ++ __ bind(&convert); ++ __ Call(isolate()->builtins()->ToObject(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ __ bind(&done_convert); ++ __ push(eax); ++ ++ // Check cache validity in generated code. If we cannot guarantee cache ++ // validity, call the runtime system to check cache validity or get the ++ // property names in a fixed array. Note: Proxies never have an enum cache, ++ // so will always take the slow path. ++ Label call_runtime, use_cache, fixed_array; ++ __ CheckEnumCache(&call_runtime); ++ ++ __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ jmp(&use_cache, Label::kNear); ++ ++ // Get the set of properties to enumerate. ++ __ bind(&call_runtime); ++ __ push(eax); ++ __ CallRuntime(Runtime::kForInEnumerate); ++ __ cmp(FieldOperand(eax, HeapObject::kMapOffset), ++ isolate()->factory()->meta_map()); ++ __ j(not_equal, &fixed_array); ++ ++ ++ // We got a map in register eax. Get the enumeration cache from it. ++ Label no_descriptors; ++ __ bind(&use_cache); ++ ++ __ EnumLength(edx, eax); ++ __ cmp(edx, Immediate(Smi::kZero)); ++ __ j(equal, &no_descriptors); ++ ++ __ LoadInstanceDescriptors(eax, ecx); ++ __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeOffset)); ++ __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); ++ ++ // Set up the four remaining stack slots. ++ __ push(eax); // Map. ++ __ push(ecx); // Enumeration cache. ++ __ push(edx); // Number of valid entries for the map in the enum cache. ++ __ push(Immediate(Smi::kZero)); // Initial index. ++ __ jmp(&loop); ++ ++ __ bind(&no_descriptors); ++ __ add(esp, Immediate(kPointerSize)); ++ __ jmp(&exit); ++ ++ // We got a fixed array in register eax. Iterate through that. ++ __ bind(&fixed_array); ++ ++ __ push(Immediate(Smi::FromInt(1))); // Smi(1) indicates slow check ++ __ push(eax); // Array ++ __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); ++ __ push(eax); // Fixed array length (as smi). ++ __ push(Immediate(Smi::kZero)); // Initial index. ++ ++ // Generate code for doing the condition check. ++ __ bind(&loop); ++ SetExpressionAsStatementPosition(stmt->each()); ++ ++ __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. ++ __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. ++ __ j(above_equal, loop_statement.break_label()); ++ ++ // Get the current entry of the array into register eax. ++ __ mov(ebx, Operand(esp, 2 * kPointerSize)); ++ __ mov(eax, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); ++ ++ // Get the expected map from the stack or a smi in the ++ // permanent slow case into register edx. ++ __ mov(edx, Operand(esp, 3 * kPointerSize)); ++ ++ // Check if the expected map still matches that of the enumerable. ++ // If not, we may have to filter the key. ++ Label update_each; ++ __ mov(ebx, Operand(esp, 4 * kPointerSize)); ++ __ cmp(edx, FieldOperand(ebx, HeapObject::kMapOffset)); ++ __ j(equal, &update_each, Label::kNear); ++ ++ // We need to filter the key, record slow-path here. ++ int const vector_index = SmiFromSlot(slot)->value(); ++ __ EmitLoadFeedbackVector(edx); ++ __ mov(FieldOperand(edx, FixedArray::OffsetOfElementAt(vector_index)), ++ Immediate(FeedbackVector::MegamorphicSentinel(isolate()))); ++ ++ // eax contains the key. The receiver in ebx is the second argument to the ++ // ForInFilter. ForInFilter returns undefined if the receiver doesn't ++ // have the key or returns the name-converted key. ++ __ Call(isolate()->builtins()->ForInFilter(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ __ JumpIfRoot(result_register(), Heap::kUndefinedValueRootIndex, ++ loop_statement.continue_label()); ++ ++ // Update the 'each' property or variable from the possibly filtered ++ // entry in register eax. ++ __ bind(&update_each); ++ // Perform the assignment as if via '='. ++ { EffectContext context(this); ++ EmitAssignment(stmt->each(), stmt->EachFeedbackSlot()); ++ } ++ ++ // Generate code for the body of the loop. ++ Visit(stmt->body()); ++ ++ // Generate code for going to the next element by incrementing the ++ // index (smi) stored on top of the stack. ++ __ bind(loop_statement.continue_label()); ++ __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); ++ ++ EmitBackEdgeBookkeeping(stmt, &loop); ++ __ jmp(&loop); ++ ++ // Remove the pointers stored on the stack. ++ __ bind(loop_statement.break_label()); ++ DropOperands(5); ++ ++ // Exit and decrement the loop depth. ++ __ bind(&exit); ++ decrement_loop_depth(); ++} ++ ++void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, ++ FeedbackSlot slot) { ++ DCHECK(NeedsHomeObject(initializer)); ++ __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize)); ++ CallStoreIC(slot, isolate()->factory()->home_object_symbol()); ++} ++ ++void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, ++ int offset, ++ FeedbackSlot slot) { ++ DCHECK(NeedsHomeObject(initializer)); ++ __ mov(StoreDescriptor::ReceiverRegister(), eax); ++ __ mov(StoreDescriptor::ValueRegister(), Operand(esp, offset * kPointerSize)); ++ CallStoreIC(slot, isolate()->factory()->home_object_symbol()); ++} ++ ++void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ++ TypeofMode typeof_mode) { ++ SetExpressionPosition(proxy); ++ Variable* var = proxy->var(); ++ ++ // Two cases: global variables and all other types of variables. ++ switch (var->location()) { ++ case VariableLocation::UNALLOCATED: { ++ Comment cmnt(masm_, "[ Global variable"); ++ EmitGlobalVariableLoad(proxy, typeof_mode); ++ context()->Plug(eax); ++ break; ++ } ++ ++ case VariableLocation::PARAMETER: ++ case VariableLocation::LOCAL: ++ case VariableLocation::CONTEXT: { ++ DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); ++ Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" ++ : "[ Stack variable"); ++ ++ if (proxy->hole_check_mode() == HoleCheckMode::kRequired) { ++ // Throw a reference error when using an uninitialized let/const ++ // binding in harmony mode. ++ Label done; ++ GetVar(eax, var); ++ __ cmp(eax, isolate()->factory()->the_hole_value()); ++ __ j(not_equal, &done, Label::kNear); ++ __ push(Immediate(var->name())); ++ __ CallRuntime(Runtime::kThrowReferenceError); ++ __ bind(&done); ++ context()->Plug(eax); ++ break; ++ } ++ context()->Plug(var); ++ break; ++ } ++ ++ case VariableLocation::LOOKUP: ++ case VariableLocation::MODULE: ++ UNREACHABLE(); ++ } ++} ++ ++ ++void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { ++ Expression* expression = (property == NULL) ? NULL : property->value(); ++ if (expression == NULL) { ++ PushOperand(isolate()->factory()->null_value()); ++ } else { ++ VisitForStackValue(expression); ++ if (NeedsHomeObject(expression)) { ++ DCHECK(property->kind() == ObjectLiteral::Property::GETTER || ++ property->kind() == ObjectLiteral::Property::SETTER); ++ int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3; ++ EmitSetHomeObject(expression, offset, property->GetSlot()); ++ } ++ } ++} ++ ++ ++void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ++ Comment cmnt(masm_, "[ ObjectLiteral"); ++ ++ Handle constant_properties = ++ expr->GetOrBuildConstantProperties(isolate()); ++ int flags = expr->ComputeFlags(); ++ // If any of the keys would store to the elements array, then we shouldn't ++ // allow it. ++ if (MustCreateObjectLiteralWithRuntime(expr)) { ++ __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ push(Immediate(Smi::FromInt(expr->literal_index()))); ++ __ push(Immediate(constant_properties)); ++ __ push(Immediate(Smi::FromInt(flags))); ++ __ CallRuntime(Runtime::kCreateObjectLiteral); ++ } else { ++ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); ++ __ mov(ecx, Immediate(constant_properties)); ++ __ mov(edx, Immediate(Smi::FromInt(flags))); ++ Callable callable = ++ Builtins::CallableFor(isolate(), Builtins::kFastCloneShallowObject); ++ __ Call(callable.code(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ } ++ ++ // If result_saved is true the result is on top of the stack. If ++ // result_saved is false the result is in eax. ++ bool result_saved = false; ++ ++ AccessorTable accessor_table(zone()); ++ for (int i = 0; i < expr->properties()->length(); i++) { ++ ObjectLiteral::Property* property = expr->properties()->at(i); ++ DCHECK(!property->is_computed_name()); ++ if (property->IsCompileTimeValue()) continue; ++ ++ Literal* key = property->key()->AsLiteral(); ++ Expression* value = property->value(); ++ if (!result_saved) { ++ PushOperand(eax); // Save result on the stack ++ result_saved = true; ++ } ++ switch (property->kind()) { ++ case ObjectLiteral::Property::SPREAD: ++ case ObjectLiteral::Property::CONSTANT: ++ UNREACHABLE(); ++ case ObjectLiteral::Property::MATERIALIZED_LITERAL: ++ DCHECK(!CompileTimeValue::IsCompileTimeValue(value)); ++ // Fall through. ++ case ObjectLiteral::Property::COMPUTED: ++ // It is safe to use [[Put]] here because the boilerplate already ++ // contains computed properties with an uninitialized value. ++ if (key->IsStringLiteral()) { ++ DCHECK(key->IsPropertyName()); ++ if (property->emit_store()) { ++ VisitForAccumulatorValue(value); ++ DCHECK(StoreDescriptor::ValueRegister().is(eax)); ++ __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ CallStoreIC(property->GetSlot(0), key->value(), kStoreOwn); ++ if (NeedsHomeObject(value)) { ++ EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); ++ } ++ } else { ++ VisitForEffect(value); ++ } ++ break; ++ } ++ PushOperand(Operand(esp, 0)); // Duplicate receiver. ++ VisitForStackValue(key); ++ VisitForStackValue(value); ++ if (property->emit_store()) { ++ if (NeedsHomeObject(value)) { ++ EmitSetHomeObject(value, 2, property->GetSlot()); ++ } ++ PushOperand(Smi::FromInt(SLOPPY)); // Language mode ++ CallRuntimeWithOperands(Runtime::kSetProperty); ++ } else { ++ DropOperands(3); ++ } ++ break; ++ case ObjectLiteral::Property::PROTOTYPE: ++ PushOperand(Operand(esp, 0)); // Duplicate receiver. ++ VisitForStackValue(value); ++ DCHECK(property->emit_store()); ++ CallRuntimeWithOperands(Runtime::kInternalSetPrototype); ++ break; ++ case ObjectLiteral::Property::GETTER: ++ if (property->emit_store()) { ++ AccessorTable::Iterator it = accessor_table.lookup(key); ++ it->second->getter = property; ++ } ++ break; ++ case ObjectLiteral::Property::SETTER: ++ if (property->emit_store()) { ++ AccessorTable::Iterator it = accessor_table.lookup(key); ++ it->second->setter = property; ++ } ++ break; ++ } ++ } ++ ++ // Emit code to define accessors, using only a single call to the runtime for ++ // each pair of corresponding getters and setters. ++ for (AccessorTable::Iterator it = accessor_table.begin(); ++ it != accessor_table.end(); ++ ++it) { ++ PushOperand(Operand(esp, 0)); // Duplicate receiver. ++ VisitForStackValue(it->first); ++ ++ EmitAccessor(it->second->getter); ++ EmitAccessor(it->second->setter); ++ ++ PushOperand(Smi::FromInt(NONE)); ++ CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked); ++ } ++ ++ if (result_saved) { ++ context()->PlugTOS(); ++ } else { ++ context()->Plug(eax); ++ } ++} ++ ++ ++void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ++ Comment cmnt(masm_, "[ ArrayLiteral"); ++ ++ Handle constant_elements = ++ expr->GetOrBuildConstantElements(isolate()); ++ ++ if (MustCreateArrayLiteralWithRuntime(expr)) { ++ __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ push(Immediate(Smi::FromInt(expr->literal_index()))); ++ __ push(Immediate(constant_elements)); ++ __ push(Immediate(Smi::FromInt(expr->ComputeFlags()))); ++ __ CallRuntime(Runtime::kCreateArrayLiteral); ++ } else { ++ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); ++ __ mov(ecx, Immediate(constant_elements)); ++ Callable callable = ++ CodeFactory::FastCloneShallowArray(isolate(), TRACK_ALLOCATION_SITE); ++ __ Call(callable.code(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ } ++ ++ bool result_saved = false; // Is the result saved to the stack? ++ ZoneList* subexprs = expr->values(); ++ int length = subexprs->length(); ++ ++ // Emit code to evaluate all the non-constant subexpressions and to store ++ // them into the newly cloned array. ++ for (int array_index = 0; array_index < length; array_index++) { ++ Expression* subexpr = subexprs->at(array_index); ++ DCHECK(!subexpr->IsSpread()); ++ ++ // If the subexpression is a literal or a simple materialized literal it ++ // is already set in the cloned array. ++ if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; ++ ++ if (!result_saved) { ++ PushOperand(eax); // array literal. ++ result_saved = true; ++ } ++ VisitForAccumulatorValue(subexpr); ++ ++ __ mov(StoreDescriptor::NameRegister(), ++ Immediate(Smi::FromInt(array_index))); ++ __ mov(StoreDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ CallKeyedStoreIC(expr->LiteralFeedbackSlot()); ++ } ++ ++ if (result_saved) { ++ context()->PlugTOS(); ++ } else { ++ context()->Plug(eax); ++ } ++} ++ ++ ++void FullCodeGenerator::VisitAssignment(Assignment* expr) { ++ DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); ++ ++ Comment cmnt(masm_, "[ Assignment"); ++ ++ Property* property = expr->target()->AsProperty(); ++ LhsKind assign_type = Property::GetAssignType(property); ++ ++ // Evaluate LHS expression. ++ switch (assign_type) { ++ case VARIABLE: ++ // Nothing to do here. ++ break; ++ case NAMED_PROPERTY: ++ if (expr->is_compound()) { ++ // We need the receiver both on the stack and in the register. ++ VisitForStackValue(property->obj()); ++ __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ } else { ++ VisitForStackValue(property->obj()); ++ } ++ break; ++ case KEYED_PROPERTY: { ++ if (expr->is_compound()) { ++ VisitForStackValue(property->obj()); ++ VisitForStackValue(property->key()); ++ __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, kPointerSize)); ++ __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); ++ } else { ++ VisitForStackValue(property->obj()); ++ VisitForStackValue(property->key()); ++ } ++ break; ++ } ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++ ++ // For compound assignments we need another deoptimization point after the ++ // variable/property load. ++ if (expr->is_compound()) { ++ AccumulatorValueContext result_context(this); ++ { AccumulatorValueContext left_operand_context(this); ++ switch (assign_type) { ++ case VARIABLE: ++ EmitVariableLoad(expr->target()->AsVariableProxy()); ++ break; ++ case NAMED_PROPERTY: ++ EmitNamedPropertyLoad(property); ++ break; ++ case KEYED_PROPERTY: ++ EmitKeyedPropertyLoad(property); ++ break; ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++ } ++ ++ Token::Value op = expr->binary_op(); ++ PushOperand(eax); // Left operand goes on the stack. ++ VisitForAccumulatorValue(expr->value()); ++ ++ EmitBinaryOp(expr->binary_operation(), op); ++ } else { ++ VisitForAccumulatorValue(expr->value()); ++ } ++ ++ SetExpressionPosition(expr); ++ ++ // Store the value. ++ switch (assign_type) { ++ case VARIABLE: { ++ VariableProxy* proxy = expr->target()->AsVariableProxy(); ++ EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(), ++ proxy->hole_check_mode()); ++ context()->Plug(eax); ++ break; ++ } ++ case NAMED_PROPERTY: ++ EmitNamedPropertyAssignment(expr); ++ break; ++ case KEYED_PROPERTY: ++ EmitKeyedPropertyAssignment(expr); ++ break; ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++} ++ ++void FullCodeGenerator::VisitSuspend(Suspend* expr) { ++ // Resumable functions are not supported. ++ UNREACHABLE(); ++} ++ ++void FullCodeGenerator::PushOperand(MemOperand operand) { ++ OperandStackDepthIncrement(1); ++ __ Push(operand); ++} ++ ++void FullCodeGenerator::EmitOperandStackDepthCheck() { ++ if (FLAG_debug_code) { ++ int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp + ++ operand_stack_depth_ * kPointerSize; ++ __ mov(eax, ebp); ++ __ sub(eax, esp); ++ __ cmp(eax, Immediate(expected_diff)); ++ __ Assert(equal, kUnexpectedStackDepth); ++ } ++} ++ ++ ++void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { ++ PopOperand(edx); ++ Handle code = CodeFactory::BinaryOperation(isolate(), op).code(); ++ __ Call(code, RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ context()->Plug(eax); ++} ++ ++void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackSlot slot) { ++ DCHECK(expr->IsValidReferenceExpressionOrThis()); ++ ++ Property* prop = expr->AsProperty(); ++ LhsKind assign_type = Property::GetAssignType(prop); ++ ++ switch (assign_type) { ++ case VARIABLE: { ++ VariableProxy* proxy = expr->AsVariableProxy(); ++ EffectContext context(this); ++ EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot, ++ proxy->hole_check_mode()); ++ break; ++ } ++ case NAMED_PROPERTY: { ++ PushOperand(eax); // Preserve value. ++ VisitForAccumulatorValue(prop->obj()); ++ __ Move(StoreDescriptor::ReceiverRegister(), eax); ++ PopOperand(StoreDescriptor::ValueRegister()); // Restore value. ++ CallStoreIC(slot, prop->key()->AsLiteral()->value()); ++ break; ++ } ++ case KEYED_PROPERTY: { ++ PushOperand(eax); // Preserve value. ++ VisitForStackValue(prop->obj()); ++ VisitForAccumulatorValue(prop->key()); ++ __ Move(StoreDescriptor::NameRegister(), eax); ++ PopOperand(StoreDescriptor::ReceiverRegister()); // Receiver. ++ PopOperand(StoreDescriptor::ValueRegister()); // Restore value. ++ CallKeyedStoreIC(slot); ++ break; ++ } ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++ context()->Plug(eax); ++} ++ ++ ++void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ++ Variable* var, MemOperand location) { ++ __ mov(location, eax); ++ if (var->IsContextSlot()) { ++ __ mov(edx, eax); ++ int offset = Context::SlotOffset(var->index()); ++ __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); ++ } ++} ++ ++void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ++ FeedbackSlot slot, ++ HoleCheckMode hole_check_mode) { ++ if (var->IsUnallocated()) { ++ // Global var, const, or let. ++ __ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand()); ++ __ mov(StoreDescriptor::ReceiverRegister(), ++ ContextOperand(StoreDescriptor::ReceiverRegister(), ++ Context::EXTENSION_INDEX)); ++ CallStoreIC(slot, var->name(), kStoreGlobal); ++ ++ } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { ++ DCHECK(!var->IsLookupSlot()); ++ DCHECK(var->IsStackAllocated() || var->IsContextSlot()); ++ MemOperand location = VarOperand(var, ecx); ++ // Perform an initialization check for lexically declared variables. ++ if (hole_check_mode == HoleCheckMode::kRequired) { ++ Label assign; ++ __ mov(edx, location); ++ __ cmp(edx, isolate()->factory()->the_hole_value()); ++ __ j(not_equal, &assign, Label::kNear); ++ __ push(Immediate(var->name())); ++ __ CallRuntime(Runtime::kThrowReferenceError); ++ __ bind(&assign); ++ } ++ if (var->mode() != CONST) { ++ EmitStoreToStackLocalOrContextSlot(var, location); ++ } else if (var->throw_on_const_assignment(language_mode())) { ++ __ CallRuntime(Runtime::kThrowConstAssignError); ++ } ++ } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { ++ // Initializing assignment to const {this} needs a write barrier. ++ DCHECK(var->IsStackAllocated() || var->IsContextSlot()); ++ Label uninitialized_this; ++ MemOperand location = VarOperand(var, ecx); ++ __ mov(edx, location); ++ __ cmp(edx, isolate()->factory()->the_hole_value()); ++ __ j(equal, &uninitialized_this); ++ __ push(Immediate(var->name())); ++ __ CallRuntime(Runtime::kThrowReferenceError); ++ __ bind(&uninitialized_this); ++ EmitStoreToStackLocalOrContextSlot(var, location); ++ ++ } else { ++ DCHECK(var->mode() != CONST || op == Token::INIT); ++ DCHECK(var->IsStackAllocated() || var->IsContextSlot()); ++ DCHECK(!var->IsLookupSlot()); ++ // Assignment to var or initializing assignment to let/const in harmony ++ // mode. ++ MemOperand location = VarOperand(var, ecx); ++ EmitStoreToStackLocalOrContextSlot(var, location); ++ } ++} ++ ++ ++void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { ++ // Assignment to a property, using a named store IC. ++ // eax : value ++ // esp[0] : receiver ++ Property* prop = expr->target()->AsProperty(); ++ DCHECK(prop != NULL); ++ DCHECK(prop->key()->IsLiteral()); ++ ++ PopOperand(StoreDescriptor::ReceiverRegister()); ++ CallStoreIC(expr->AssignmentSlot(), prop->key()->AsLiteral()->value()); ++ context()->Plug(eax); ++} ++ ++ ++void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { ++ // Assignment to a property, using a keyed store IC. ++ // eax : value ++ // esp[0] : key ++ // esp[kPointerSize] : receiver ++ ++ PopOperand(StoreDescriptor::NameRegister()); // Key. ++ PopOperand(StoreDescriptor::ReceiverRegister()); ++ DCHECK(StoreDescriptor::ValueRegister().is(eax)); ++ CallKeyedStoreIC(expr->AssignmentSlot()); ++ context()->Plug(eax); ++} ++ ++// Code common for calls using the IC. ++void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) { ++ Expression* callee = expr->expression(); ++ ++ // Get the target function. ++ ConvertReceiverMode convert_mode; ++ if (callee->IsVariableProxy()) { ++ { StackValueContext context(this); ++ EmitVariableLoad(callee->AsVariableProxy()); ++ } ++ // Push undefined as receiver. This is patched in the method prologue if it ++ // is a sloppy mode method. ++ PushOperand(isolate()->factory()->undefined_value()); ++ convert_mode = ConvertReceiverMode::kNullOrUndefined; ++ } else { ++ // Load the function from the receiver. ++ DCHECK(callee->IsProperty()); ++ DCHECK(!callee->AsProperty()->IsSuperAccess()); ++ __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ EmitNamedPropertyLoad(callee->AsProperty()); ++ // Push the target function under the receiver. ++ PushOperand(Operand(esp, 0)); ++ __ mov(Operand(esp, kPointerSize), eax); ++ convert_mode = ConvertReceiverMode::kNotNullOrUndefined; ++ } ++ ++ EmitCall(expr, convert_mode); ++} ++ ++ ++// Code common for calls using the IC. ++void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, ++ Expression* key) { ++ // Load the key. ++ VisitForAccumulatorValue(key); ++ ++ Expression* callee = expr->expression(); ++ ++ // Load the function from the receiver. ++ DCHECK(callee->IsProperty()); ++ __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ __ mov(LoadDescriptor::NameRegister(), eax); ++ EmitKeyedPropertyLoad(callee->AsProperty()); ++ ++ // Push the target function under the receiver. ++ PushOperand(Operand(esp, 0)); ++ __ mov(Operand(esp, kPointerSize), eax); ++ ++ EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined); ++} ++ ++ ++void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) { ++ // Load the arguments. ++ ZoneList* args = expr->arguments(); ++ int arg_count = args->length(); ++ for (int i = 0; i < arg_count; i++) { ++ VisitForStackValue(args->at(i)); ++ } ++ ++ SetCallPosition(expr, expr->tail_call_mode()); ++ if (expr->tail_call_mode() == TailCallMode::kAllow) { ++ if (FLAG_trace) { ++ __ CallRuntime(Runtime::kTraceTailCall); ++ } ++ // Update profiling counters before the tail call since we will ++ // not return to this function. ++ EmitProfilingCounterHandlingForReturnSequence(true); ++ } ++ Handle code = ++ CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode()) ++ .code(); ++ __ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot()))); ++ __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); ++ __ Move(eax, Immediate(arg_count)); ++ CallIC(code); ++ OperandStackDepthDecrement(arg_count + 1); ++ ++ RestoreContext(); ++ context()->DropAndPlug(1, eax); ++} ++ ++void FullCodeGenerator::VisitCallNew(CallNew* expr) { ++ Comment cmnt(masm_, "[ CallNew"); ++ // According to ECMA-262, section 11.2.2, page 44, the function ++ // expression in new calls must be evaluated before the ++ // arguments. ++ ++ // Push constructor on the stack. If it's not a function it's used as ++ // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is ++ // ignored. ++ DCHECK(!expr->expression()->IsSuperPropertyReference()); ++ VisitForStackValue(expr->expression()); ++ ++ // Push the arguments ("left-to-right") on the stack. ++ ZoneList* args = expr->arguments(); ++ int arg_count = args->length(); ++ for (int i = 0; i < arg_count; i++) { ++ VisitForStackValue(args->at(i)); ++ } ++ ++ // Call the construct call builtin that handles allocation and ++ // constructor invocation. ++ SetConstructCallPosition(expr); ++ ++ // Load function and argument count into edi and eax. ++ __ Move(eax, Immediate(arg_count)); ++ __ mov(edi, Operand(esp, arg_count * kPointerSize)); ++ ++ // Record call targets in unoptimized code. ++ __ EmitLoadFeedbackVector(ebx); ++ __ mov(edx, Immediate(SmiFromSlot(expr->CallNewFeedbackSlot()))); ++ ++ CallConstructStub stub(isolate()); ++ CallIC(stub.GetCode()); ++ OperandStackDepthDecrement(arg_count + 1); ++ RestoreContext(); ++ context()->Plug(eax); ++} ++ ++ ++void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ __ test(eax, Immediate(kSmiTagMask)); ++ Split(zero, if_true, if_false, fall_through); ++ ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ebx); ++ Split(above_equal, if_true, if_false, fall_through); ++ ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); ++ Split(equal, if_true, if_false, fall_through); ++ ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, &if_true, ++ &if_false, &fall_through); ++ ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, JS_TYPED_ARRAY_TYPE, ebx); ++ Split(equal, if_true, if_false, fall_through); ++ ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, &if_true, ++ &if_false, &fall_through); ++ ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, JS_PROXY_TYPE, ebx); ++ Split(equal, if_true, if_false, fall_through); ++ ++ context()->Plug(if_true, if_false); ++} ++ ++void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 1); ++ Label done, null, function, non_function_constructor; ++ ++ VisitForAccumulatorValue(args->at(0)); ++ ++ // If the object is not a JSReceiver, we return null. ++ __ JumpIfSmi(eax, &null, Label::kNear); ++ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, eax); ++ __ j(below, &null, Label::kNear); ++ ++ // Return 'Function' for JSFunction and JSBoundFunction objects. ++ __ CmpInstanceType(eax, FIRST_FUNCTION_TYPE); ++ STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); ++ __ j(above_equal, &function, Label::kNear); ++ ++ // Check if the constructor in the map is a JS function. ++ __ GetMapConstructor(eax, eax, ebx); ++ __ CmpInstanceType(ebx, JS_FUNCTION_TYPE); ++ __ j(not_equal, &non_function_constructor, Label::kNear); ++ ++ // eax now contains the constructor function. Grab the ++ // instance class name from there. ++ __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); ++ __ jmp(&done, Label::kNear); ++ ++ // Non-JS objects have class null. ++ __ bind(&null); ++ __ mov(eax, isolate()->factory()->null_value()); ++ __ jmp(&done, Label::kNear); ++ ++ // Functions have class 'Function'. ++ __ bind(&function); ++ __ mov(eax, isolate()->factory()->Function_string()); ++ __ jmp(&done, Label::kNear); ++ ++ // Objects with a non-function constructor have class 'Object'. ++ __ bind(&non_function_constructor); ++ __ mov(eax, isolate()->factory()->Object_string()); ++ ++ // All done. ++ __ bind(&done); ++ ++ context()->Plug(eax); ++} ++ ++void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK(args->length() == 2); ++ ++ VisitForStackValue(args->at(0)); ++ VisitForAccumulatorValue(args->at(1)); ++ ++ Register object = ebx; ++ Register index = eax; ++ Register result = edx; ++ ++ PopOperand(object); ++ ++ Label need_conversion; ++ Label index_out_of_range; ++ Label done; ++ StringCharCodeAtGenerator generator(object, index, result, &need_conversion, ++ &need_conversion, &index_out_of_range); ++ generator.GenerateFast(masm_); ++ __ jmp(&done); ++ ++ __ bind(&index_out_of_range); ++ // When the index is out of range, the spec requires us to return ++ // NaN. ++ __ Move(result, Immediate(isolate()->factory()->nan_value())); ++ __ jmp(&done); ++ ++ __ bind(&need_conversion); ++ // Move the undefined value into the result register, which will ++ // trigger conversion. ++ __ Move(result, Immediate(isolate()->factory()->undefined_value())); ++ __ jmp(&done); ++ ++ NopRuntimeCallHelper call_helper; ++ generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); ++ ++ __ bind(&done); ++ context()->Plug(result); ++} ++ ++ ++void FullCodeGenerator::EmitCall(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK_LE(2, args->length()); ++ // Push target, receiver and arguments onto the stack. ++ for (Expression* const arg : *args) { ++ VisitForStackValue(arg); ++ } ++ // Move target to edi. ++ int const argc = args->length() - 2; ++ __ mov(edi, Operand(esp, (argc + 1) * kPointerSize)); ++ // Call the target. ++ __ mov(eax, Immediate(argc)); ++ __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); ++ OperandStackDepthDecrement(argc + 1); ++ RestoreContext(); ++ // Discard the function left on TOS. ++ context()->DropAndPlug(1, eax); ++} ++ ++void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ DCHECK_EQ(1, args->length()); ++ VisitForAccumulatorValue(args->at(0)); ++ __ AssertFunction(eax); ++ __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ mov(eax, FieldOperand(eax, Map::kPrototypeOffset)); ++ context()->Plug(eax); ++} ++ ++void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { ++ DCHECK(expr->arguments()->length() == 0); ++ ExternalReference debug_is_active = ++ ExternalReference::debug_is_active_address(isolate()); ++ __ movzx_b(eax, Operand::StaticVariable(debug_is_active)); ++ __ SmiTag(eax); ++ context()->Plug(eax); ++} ++ ++ ++void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) { ++ // Push function. ++ __ LoadGlobalFunction(expr->context_index(), eax); ++ PushOperand(eax); ++ ++ // Push undefined as receiver. ++ PushOperand(isolate()->factory()->undefined_value()); ++} ++ ++ ++void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { ++ ZoneList* args = expr->arguments(); ++ int arg_count = args->length(); ++ ++ SetCallPosition(expr); ++ __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize)); ++ __ Set(eax, arg_count); ++ __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), ++ RelocInfo::CODE_TARGET); ++ OperandStackDepthDecrement(arg_count + 1); ++ RestoreContext(); ++} ++ ++ ++void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ++ switch (expr->op()) { ++ case Token::DELETE: { ++ Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); ++ Property* property = expr->expression()->AsProperty(); ++ VariableProxy* proxy = expr->expression()->AsVariableProxy(); ++ ++ if (property != NULL) { ++ VisitForStackValue(property->obj()); ++ VisitForStackValue(property->key()); ++ PushOperand(Smi::FromInt(language_mode())); ++ CallRuntimeWithOperands(Runtime::kDeleteProperty); ++ context()->Plug(eax); ++ } else if (proxy != NULL) { ++ Variable* var = proxy->var(); ++ // Delete of an unqualified identifier is disallowed in strict mode but ++ // "delete this" is allowed. ++ bool is_this = var->is_this(); ++ DCHECK(is_sloppy(language_mode()) || is_this); ++ if (var->IsUnallocated()) { ++ __ mov(eax, NativeContextOperand()); ++ __ push(ContextOperand(eax, Context::EXTENSION_INDEX)); ++ __ push(Immediate(var->name())); ++ __ Push(Smi::FromInt(SLOPPY)); ++ __ CallRuntime(Runtime::kDeleteProperty); ++ context()->Plug(eax); ++ } else { ++ DCHECK(!var->IsLookupSlot()); ++ DCHECK(var->IsStackAllocated() || var->IsContextSlot()); ++ // Result of deleting non-global variables is false. 'this' is ++ // not really a variable, though we implement it as one. The ++ // subexpression does not have side effects. ++ context()->Plug(is_this); ++ } ++ } else { ++ // Result of deleting non-property, non-variable reference is true. ++ // The subexpression may have side effects. ++ VisitForEffect(expr->expression()); ++ context()->Plug(true); ++ } ++ break; ++ } ++ ++ case Token::VOID: { ++ Comment cmnt(masm_, "[ UnaryOperation (VOID)"); ++ VisitForEffect(expr->expression()); ++ context()->Plug(isolate()->factory()->undefined_value()); ++ break; ++ } ++ ++ case Token::NOT: { ++ Comment cmnt(masm_, "[ UnaryOperation (NOT)"); ++ if (context()->IsEffect()) { ++ // Unary NOT has no side effects so it's only necessary to visit the ++ // subexpression. Match the optimizing compiler by not branching. ++ VisitForEffect(expr->expression()); ++ } else if (context()->IsTest()) { ++ const TestContext* test = TestContext::cast(context()); ++ // The labels are swapped for the recursive call. ++ VisitForControl(expr->expression(), ++ test->false_label(), ++ test->true_label(), ++ test->fall_through()); ++ context()->Plug(test->true_label(), test->false_label()); ++ } else { ++ // We handle value contexts explicitly rather than simply visiting ++ // for control and plugging the control flow into the context, ++ // because we need to prepare a pair of extra administrative AST ids ++ // for the optimizing compiler. ++ DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue()); ++ Label materialize_true, materialize_false, done; ++ VisitForControl(expr->expression(), ++ &materialize_false, ++ &materialize_true, ++ &materialize_true); ++ if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1); ++ __ bind(&materialize_true); ++ if (context()->IsAccumulatorValue()) { ++ __ mov(eax, isolate()->factory()->true_value()); ++ } else { ++ __ Push(isolate()->factory()->true_value()); ++ } ++ __ jmp(&done, Label::kNear); ++ __ bind(&materialize_false); ++ if (context()->IsAccumulatorValue()) { ++ __ mov(eax, isolate()->factory()->false_value()); ++ } else { ++ __ Push(isolate()->factory()->false_value()); ++ } ++ __ bind(&done); ++ } ++ break; ++ } ++ ++ case Token::TYPEOF: { ++ Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); ++ { ++ AccumulatorValueContext context(this); ++ VisitForTypeofValue(expr->expression()); ++ } ++ __ mov(ebx, eax); ++ __ Call(isolate()->builtins()->Typeof(), RelocInfo::CODE_TARGET); ++ context()->Plug(eax); ++ break; ++ } ++ ++ default: ++ UNREACHABLE(); ++ } ++} ++ ++ ++void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ++ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); ++ ++ Comment cmnt(masm_, "[ CountOperation"); ++ ++ Property* prop = expr->expression()->AsProperty(); ++ LhsKind assign_type = Property::GetAssignType(prop); ++ ++ // Evaluate expression and get value. ++ if (assign_type == VARIABLE) { ++ DCHECK(expr->expression()->AsVariableProxy()->var() != NULL); ++ AccumulatorValueContext context(this); ++ EmitVariableLoad(expr->expression()->AsVariableProxy()); ++ } else { ++ // Reserve space for result of postfix operation. ++ if (expr->is_postfix() && !context()->IsEffect()) { ++ PushOperand(Smi::kZero); ++ } ++ switch (assign_type) { ++ case NAMED_PROPERTY: { ++ // Put the object both on the stack and in the register. ++ VisitForStackValue(prop->obj()); ++ __ mov(LoadDescriptor::ReceiverRegister(), Operand(esp, 0)); ++ EmitNamedPropertyLoad(prop); ++ break; ++ } ++ ++ case KEYED_PROPERTY: { ++ VisitForStackValue(prop->obj()); ++ VisitForStackValue(prop->key()); ++ __ mov(LoadDescriptor::ReceiverRegister(), ++ Operand(esp, kPointerSize)); // Object. ++ __ mov(LoadDescriptor::NameRegister(), Operand(esp, 0)); // Key. ++ EmitKeyedPropertyLoad(prop); ++ break; ++ } ++ ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ case VARIABLE: ++ UNREACHABLE(); ++ } ++ } ++ ++ // Convert old value into a number. ++ __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ ++ // Save result for postfix expressions. ++ if (expr->is_postfix()) { ++ if (!context()->IsEffect()) { ++ // Save the result on the stack. If we have a named or keyed property ++ // we store the result under the receiver that is currently on top ++ // of the stack. ++ switch (assign_type) { ++ case VARIABLE: ++ PushOperand(eax); ++ break; ++ case NAMED_PROPERTY: ++ __ mov(Operand(esp, kPointerSize), eax); ++ break; ++ case KEYED_PROPERTY: ++ __ mov(Operand(esp, 2 * kPointerSize), eax); ++ break; ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++ } ++ } ++ ++ SetExpressionPosition(expr); ++ ++ // Call stub for +1/-1. ++ __ mov(edx, eax); ++ __ mov(eax, Immediate(Smi::FromInt(1))); ++ Handle code = ++ CodeFactory::BinaryOperation(isolate(), expr->binary_op()).code(); ++ __ Call(code, RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ ++ // Store the value returned in eax. ++ switch (assign_type) { ++ case VARIABLE: { ++ VariableProxy* proxy = expr->expression()->AsVariableProxy(); ++ if (expr->is_postfix()) { ++ // Perform the assignment as if via '='. ++ { EffectContext context(this); ++ EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), ++ proxy->hole_check_mode()); ++ context.Plug(eax); ++ } ++ // For all contexts except EffectContext We have the result on ++ // top of the stack. ++ if (!context()->IsEffect()) { ++ context()->PlugTOS(); ++ } ++ } else { ++ // Perform the assignment as if via '='. ++ EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(), ++ proxy->hole_check_mode()); ++ context()->Plug(eax); ++ } ++ break; ++ } ++ case NAMED_PROPERTY: { ++ PopOperand(StoreDescriptor::ReceiverRegister()); ++ CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); ++ if (expr->is_postfix()) { ++ if (!context()->IsEffect()) { ++ context()->PlugTOS(); ++ } ++ } else { ++ context()->Plug(eax); ++ } ++ break; ++ } ++ case KEYED_PROPERTY: { ++ PopOperand(StoreDescriptor::NameRegister()); ++ PopOperand(StoreDescriptor::ReceiverRegister()); ++ CallKeyedStoreIC(expr->CountSlot()); ++ if (expr->is_postfix()) { ++ // Result is on the stack ++ if (!context()->IsEffect()) { ++ context()->PlugTOS(); ++ } ++ } else { ++ context()->Plug(eax); ++ } ++ break; ++ } ++ case NAMED_SUPER_PROPERTY: ++ case KEYED_SUPER_PROPERTY: ++ UNREACHABLE(); ++ break; ++ } ++} ++ ++ ++void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, ++ Expression* sub_expr, ++ Handle check) { ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ { AccumulatorValueContext context(this); ++ VisitForTypeofValue(sub_expr); ++ } ++ ++ Factory* factory = isolate()->factory(); ++ if (String::Equals(check, factory->number_string())) { ++ __ JumpIfSmi(eax, if_true); ++ __ cmp(FieldOperand(eax, HeapObject::kMapOffset), ++ isolate()->factory()->heap_number_map()); ++ Split(equal, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->string_string())) { ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); ++ Split(below, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->symbol_string())) { ++ __ JumpIfSmi(eax, if_false); ++ __ CmpObjectType(eax, SYMBOL_TYPE, edx); ++ Split(equal, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->boolean_string())) { ++ __ cmp(eax, isolate()->factory()->true_value()); ++ __ j(equal, if_true); ++ __ cmp(eax, isolate()->factory()->false_value()); ++ Split(equal, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->undefined_string())) { ++ __ cmp(eax, isolate()->factory()->null_value()); ++ __ j(equal, if_false); ++ __ JumpIfSmi(eax, if_false); ++ // Check for undetectable objects => true. ++ __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(edx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsUndetectable)); ++ Split(not_zero, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->function_string())) { ++ __ JumpIfSmi(eax, if_false); ++ // Check for callable and not undetectable objects => true. ++ __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); ++ __ and_(ecx, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); ++ __ cmp(ecx, 1 << Map::kIsCallable); ++ Split(equal, if_true, if_false, fall_through); ++ } else if (String::Equals(check, factory->object_string())) { ++ __ JumpIfSmi(eax, if_false); ++ __ cmp(eax, isolate()->factory()->null_value()); ++ __ j(equal, if_true); ++ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, edx); ++ __ j(below, if_false); ++ // Check for callable or undetectable objects => false. ++ __ test_b(FieldOperand(edx, Map::kBitFieldOffset), ++ Immediate((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); ++ Split(zero, if_true, if_false, fall_through); ++ } else { ++ if (if_false != fall_through) __ jmp(if_false); ++ } ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { ++ Comment cmnt(masm_, "[ CompareOperation"); ++ ++ // First we try a fast inlined version of the compare when one of ++ // the operands is a literal. ++ if (TryLiteralCompare(expr)) return; ++ ++ // Always perform the comparison for its control flow. Pack the result ++ // into the expression's context after the comparison is performed. ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ Token::Value op = expr->op(); ++ VisitForStackValue(expr->left()); ++ switch (op) { ++ case Token::IN: ++ VisitForStackValue(expr->right()); ++ SetExpressionPosition(expr); ++ EmitHasProperty(); ++ __ cmp(eax, isolate()->factory()->true_value()); ++ Split(equal, if_true, if_false, fall_through); ++ break; ++ ++ case Token::INSTANCEOF: { ++ VisitForAccumulatorValue(expr->right()); ++ SetExpressionPosition(expr); ++ PopOperand(edx); ++ __ Call(isolate()->builtins()->InstanceOf(), RelocInfo::CODE_TARGET); ++ RestoreContext(); ++ __ cmp(eax, isolate()->factory()->true_value()); ++ Split(equal, if_true, if_false, fall_through); ++ break; ++ } ++ ++ default: { ++ VisitForAccumulatorValue(expr->right()); ++ SetExpressionPosition(expr); ++ Condition cc = CompareIC::ComputeCondition(op); ++ PopOperand(edx); ++ ++ bool inline_smi_code = ShouldInlineSmiCase(op); ++ JumpPatchSite patch_site(masm_); ++ if (inline_smi_code) { ++ Label slow_case; ++ __ mov(ecx, edx); ++ __ or_(ecx, eax); ++ patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); ++ __ cmp(edx, eax); ++ Split(cc, if_true, if_false, NULL); ++ __ bind(&slow_case); ++ } ++ ++ Handle ic = CodeFactory::CompareIC(isolate(), op).code(); ++ CallIC(ic); ++ patch_site.EmitPatchInfo(); ++ ++ __ test(eax, eax); ++ Split(cc, if_true, if_false, fall_through); ++ } ++ } ++ ++ // Convert the result of the comparison into one expected for this ++ // expression's context. ++ context()->Plug(if_true, if_false); ++} ++ ++ ++void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, ++ Expression* sub_expr, ++ NilValue nil) { ++ Label materialize_true, materialize_false; ++ Label* if_true = NULL; ++ Label* if_false = NULL; ++ Label* fall_through = NULL; ++ context()->PrepareTest(&materialize_true, &materialize_false, ++ &if_true, &if_false, &fall_through); ++ ++ VisitForAccumulatorValue(sub_expr); ++ ++ Handle nil_value = nil == kNullValue ++ ? isolate()->factory()->null_value() ++ : isolate()->factory()->undefined_value(); ++ if (expr->op() == Token::EQ_STRICT) { ++ __ cmp(eax, nil_value); ++ Split(equal, if_true, if_false, fall_through); ++ } else { ++ __ JumpIfSmi(eax, if_false); ++ __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ test_b(FieldOperand(eax, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsUndetectable)); ++ Split(not_zero, if_true, if_false, fall_through); ++ } ++ context()->Plug(if_true, if_false); ++} ++ ++ ++Register FullCodeGenerator::result_register() { ++ return eax; ++} ++ ++ ++Register FullCodeGenerator::context_register() { ++ return esi; ++} ++ ++void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) { ++ DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); ++ __ mov(value, Operand(ebp, frame_offset)); ++} ++ ++void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { ++ DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); ++ __ mov(Operand(ebp, frame_offset), value); ++} ++ ++ ++void FullCodeGenerator::LoadContextField(Register dst, int context_index) { ++ __ mov(dst, ContextOperand(esi, context_index)); ++} ++ ++ ++void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { ++ DeclarationScope* closure_scope = scope()->GetClosureScope(); ++ if (closure_scope->is_script_scope() || ++ closure_scope->is_module_scope()) { ++ // Contexts nested in the native context have a canonical empty function ++ // as their closure, not the anonymous closure containing the global ++ // code. ++ __ mov(eax, NativeContextOperand()); ++ PushOperand(ContextOperand(eax, Context::CLOSURE_INDEX)); ++ } else if (closure_scope->is_eval_scope()) { ++ // Contexts nested inside eval code have the same closure as the context ++ // calling eval, not the anonymous closure containing the eval code. ++ // Fetch it from the context. ++ PushOperand(ContextOperand(esi, Context::CLOSURE_INDEX)); ++ } else { ++ DCHECK(closure_scope->is_function_scope()); ++ PushOperand(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ } ++} ++ ++ ++#undef __ ++ ++ ++static const byte kJnsInstruction = 0x79; ++static const byte kJnsOffset = 0x11; ++static const byte kNopByteOne = 0x66; ++static const byte kNopByteTwo = 0x90; ++#ifdef DEBUG ++static const byte kCallInstruction = 0xe8; ++#endif ++ ++ ++void BackEdgeTable::PatchAt(Code* unoptimized_code, ++ Address pc, ++ BackEdgeState target_state, ++ Code* replacement_code) { ++ Address call_target_address = pc - kIntSize; ++ Address jns_instr_address = call_target_address - 3; ++ Address jns_offset_address = call_target_address - 2; ++ ++ switch (target_state) { ++ case INTERRUPT: ++ // sub , ;; Not changed ++ // jns ok ++ // call ++ // ok: ++ *jns_instr_address = kJnsInstruction; ++ *jns_offset_address = kJnsOffset; ++ break; ++ case ON_STACK_REPLACEMENT: ++ // sub , ;; Not changed ++ // nop ++ // nop ++ // call ++ // ok: ++ *jns_instr_address = kNopByteOne; ++ *jns_offset_address = kNopByteTwo; ++ break; ++ } ++ ++ Assembler::set_target_address_at(unoptimized_code->GetIsolate(), ++ call_target_address, unoptimized_code, ++ replacement_code->entry()); ++ unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( ++ unoptimized_code, call_target_address, replacement_code); ++} ++ ++ ++BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( ++ Isolate* isolate, ++ Code* unoptimized_code, ++ Address pc) { ++ Address call_target_address = pc - kIntSize; ++ Address jns_instr_address = call_target_address - 3; ++ DCHECK_EQ(kCallInstruction, *(call_target_address - 1)); ++ ++ if (*jns_instr_address == kJnsInstruction) { ++ DCHECK_EQ(kJnsOffset, *(call_target_address - 2)); ++ DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(), ++ Assembler::target_address_at(call_target_address, ++ unoptimized_code)); ++ return INTERRUPT; ++ } ++ ++ DCHECK_EQ(kNopByteOne, *jns_instr_address); ++ DCHECK_EQ(kNopByteTwo, *(call_target_address - 2)); ++ ++ DCHECK_EQ( ++ isolate->builtins()->OnStackReplacement()->entry(), ++ Assembler::target_address_at(call_target_address, unoptimized_code)); ++ return ON_STACK_REPLACEMENT; ++} ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/full-codegen/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/full-codegen/x87/OWNERS 2017-12-25 17:42:57.211465705 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/gdb-jit.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/gdb-jit.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/gdb-jit.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/gdb-jit.cc 2017-12-25 17:42:57.213465676 +0100 +@@ -199,7 +199,7 @@ + struct MachOSectionHeader { + char sectname[16]; + char segname[16]; +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + uint32_t addr; + uint32_t size; + #else +@@ -507,7 +507,7 @@ + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; +@@ -533,7 +533,7 @@ + Writer::Slot WriteHeader(Writer* w) { + DCHECK(w->position() == 0); + Writer::Slot header = w->CreateSlotHere(); +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + header->magic = 0xFEEDFACEu; + header->cputype = 7; // i386 + header->cpusubtype = 3; // CPU_SUBTYPE_I386_ALL +@@ -558,7 +558,7 @@ + uintptr_t code_size) { + Writer::Slot cmd = + w->CreateSlotHere(); +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + cmd->cmd = LC_SEGMENT_32; + #else + cmd->cmd = LC_SEGMENT_64; +@@ -646,7 +646,7 @@ + void WriteHeader(Writer* w) { + DCHECK(w->position() == 0); + Writer::Slot header = w->CreateSlotHere(); +-#if (V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || \ ++#if (V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_X87 || \ + (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT)) + const uint8_t ident[16] = + { 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +@@ -668,7 +668,7 @@ + #endif + memcpy(header->ident, ident, 16); + header->type = 1; +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + header->machine = 3; + #elif V8_TARGET_ARCH_X64 + // Processor identification value for x64 is 62 as defined in +@@ -783,8 +783,8 @@ + Binding binding() const { + return static_cast(info >> 4); + } +-#if (V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || \ +- (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT) || \ ++#if (V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_X87 || \ ++ (V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT) || \ + (V8_TARGET_ARCH_S390 && V8_TARGET_ARCH_32_BIT)) + struct SerializedLayout { + SerializedLayout(uint32_t name, +@@ -1146,7 +1146,7 @@ + w->Write(desc_->CodeStart() + desc_->CodeSize()); + Writer::Slot fb_block_size = w->CreateSlotHere(); + uintptr_t fb_block_start = w->position(); +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + w->Write(DW_OP_reg5); // The frame pointer's here on ia32 + #elif V8_TARGET_ARCH_X64 + w->Write(DW_OP_reg6); // and here on x64. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/globals.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/globals.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/globals.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/globals.h 2017-12-25 17:42:57.214465661 +0100 +@@ -167,7 +167,7 @@ + const int kPCOnStackSize = kRegisterSize; + const int kFPOnStackSize = kRegisterSize; + +-#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + const int kElidedFrameSlots = kPCOnStackSize / kPointerSize; + #else + const int kElidedFrameSlots = 0; +@@ -912,10 +912,16 @@ + }; + + // The mips architecture prior to revision 5 has inverted encoding for sNaN. ++// The x87 FPU convert the sNaN to qNaN automatically when loading sNaN from ++// memmory. ++// Use mips sNaN which is a not used qNaN in x87 port as sNaN to workaround this ++// issue ++// for some test cases. + #if (V8_TARGET_ARCH_MIPS && !defined(_MIPS_ARCH_MIPS32R6) && \ + (!defined(USE_SIMULATOR) || !defined(_MIPS_TARGET_SIMULATOR))) || \ + (V8_TARGET_ARCH_MIPS64 && !defined(_MIPS_ARCH_MIPS64R6) && \ +- (!defined(USE_SIMULATOR) || !defined(_MIPS_TARGET_SIMULATOR))) ++ (!defined(USE_SIMULATOR) || !defined(_MIPS_TARGET_SIMULATOR))) || \ ++ (V8_TARGET_ARCH_X87) + const uint32_t kHoleNanUpper32 = 0xFFFF7FFF; + const uint32_t kHoleNanLower32 = 0xFFFF7FFF; + #else +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/access-compiler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/access-compiler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/access-compiler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/access-compiler-x87.cc 2017-12-25 17:42:57.214465661 +0100 +@@ -0,0 +1,40 @@ ++// Copyright 2014 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/ic/access-compiler.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm) ++ ++void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, ++ Handle code) { ++ __ jmp(code, RelocInfo::CODE_TARGET); ++} ++ ++void PropertyAccessCompiler::InitializePlatformSpecific( ++ AccessCompilerData* data) { ++ Register receiver = LoadDescriptor::ReceiverRegister(); ++ Register name = LoadDescriptor::NameRegister(); ++ ++ // Load calling convention. ++ // receiver, name, scratch1, scratch2, scratch3. ++ Register load_registers[] = {receiver, name, ebx, eax, edi}; ++ ++ // Store calling convention. ++ // receiver, name, scratch1, scratch2. ++ Register store_registers[] = {receiver, name, ebx, edi}; ++ ++ data->Initialize(arraysize(load_registers), load_registers, ++ arraysize(store_registers), store_registers); ++} ++ ++#undef __ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/handler-compiler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/handler-compiler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/handler-compiler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/handler-compiler-x87.cc 2017-12-25 17:42:57.215465646 +0100 +@@ -0,0 +1,450 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/ic/handler-compiler.h" ++ ++#include "src/api-arguments.h" ++#include "src/field-type.h" ++#include "src/ic/call-optimization.h" ++#include "src/ic/ic.h" ++#include "src/isolate-inl.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm) ++ ++void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt( ++ MacroAssembler* masm) { ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ // If we generate a global code snippet for deoptimization only, remember ++ // the place to continue after deoptimization. ++ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); ++ // Restore context register. ++ __ pop(esi); ++ } ++ __ ret(0); ++} ++ ++ ++void PropertyHandlerCompiler::PushVectorAndSlot(Register vector, ++ Register slot) { ++ MacroAssembler* masm = this->masm(); ++ STATIC_ASSERT(LoadWithVectorDescriptor::kSlot < ++ LoadWithVectorDescriptor::kVector); ++ STATIC_ASSERT(StoreWithVectorDescriptor::kSlot < ++ StoreWithVectorDescriptor::kVector); ++ STATIC_ASSERT(StoreTransitionDescriptor::kSlot < ++ StoreTransitionDescriptor::kVector); ++ __ push(slot); ++ __ push(vector); ++} ++ ++ ++void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) { ++ MacroAssembler* masm = this->masm(); ++ __ pop(vector); ++ __ pop(slot); ++} ++ ++ ++void PropertyHandlerCompiler::DiscardVectorAndSlot() { ++ MacroAssembler* masm = this->masm(); ++ // Remove vector and slot. ++ __ add(esp, Immediate(2 * kPointerSize)); ++} ++ ++void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( ++ MacroAssembler* masm, Label* miss_label, Register receiver, ++ Handle name, Register scratch0, Register scratch1) { ++ DCHECK(name->IsUniqueName()); ++ DCHECK(!receiver.is(scratch0)); ++ Counters* counters = masm->isolate()->counters(); ++ __ IncrementCounter(counters->negative_lookups(), 1); ++ __ IncrementCounter(counters->negative_lookups_miss(), 1); ++ ++ __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); ++ ++ const int kInterceptorOrAccessCheckNeededMask = ++ (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); ++ ++ // Bail out if the receiver has a named interceptor or requires access checks. ++ __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset), ++ Immediate(kInterceptorOrAccessCheckNeededMask)); ++ __ j(not_zero, miss_label); ++ ++ // Check that receiver is a JSObject. ++ __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE); ++ __ j(below, miss_label); ++ ++ // Load properties array. ++ Register properties = scratch0; ++ __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOrHashOffset)); ++ ++ // Check that the properties array is a dictionary. ++ __ cmp(FieldOperand(properties, HeapObject::kMapOffset), ++ Immediate(masm->isolate()->factory()->hash_table_map())); ++ __ j(not_equal, miss_label); ++ ++ Label done; ++ NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, ++ properties, name, scratch1); ++ __ bind(&done); ++ __ DecrementCounter(counters->negative_lookups_miss(), 1); ++} ++ ++// Generate call to api function. ++// This function uses push() to generate smaller, faster code than ++// the version above. It is an optimization that should will be removed ++// when api call ICs are generated in hydrogen. ++void PropertyHandlerCompiler::GenerateApiAccessorCall( ++ MacroAssembler* masm, const CallOptimization& optimization, ++ Handle receiver_map, Register receiver, Register scratch, ++ bool is_store, Register store_parameter, Register accessor_holder, ++ int accessor_index) { ++ DCHECK(!accessor_holder.is(scratch)); ++ // Copy return value. ++ __ pop(scratch); ++ ++ if (is_store) { ++ // Discard stack arguments. ++ __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount * ++ kPointerSize)); ++ } ++ // Write the receiver and arguments to stack frame. ++ __ push(receiver); ++ if (is_store) { ++ DCHECK(!AreAliased(receiver, scratch, store_parameter)); ++ __ push(store_parameter); ++ } ++ __ push(scratch); ++ // Stack now matches JSFunction abi. ++ DCHECK(optimization.is_simple_api_call()); ++ ++ // Abi for CallApiCallbackStub. ++ Register callee = edi; ++ Register data = ebx; ++ Register holder = ecx; ++ Register api_function_address = edx; ++ scratch = no_reg; ++ ++ // Put callee in place. ++ __ LoadAccessor(callee, accessor_holder, accessor_index, ++ is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER); ++ ++ // Put holder in place. ++ CallOptimization::HolderLookup holder_lookup; ++ optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); ++ switch (holder_lookup) { ++ case CallOptimization::kHolderIsReceiver: ++ __ Move(holder, receiver); ++ break; ++ case CallOptimization::kHolderFound: ++ __ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset)); ++ __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset)); ++ break; ++ case CallOptimization::kHolderNotFound: ++ UNREACHABLE(); ++ break; ++ } ++ ++ Isolate* isolate = masm->isolate(); ++ Handle api_call_info = optimization.api_call_info(); ++ bool call_data_undefined = false; ++ // Put call data in place. ++ if (api_call_info->data()->IsUndefined(isolate)) { ++ call_data_undefined = true; ++ __ mov(data, Immediate(isolate->factory()->undefined_value())); ++ } else { ++ if (optimization.is_constant_call()) { ++ __ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset)); ++ __ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset)); ++ } else { ++ __ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset)); ++ } ++ __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset)); ++ } ++ ++ // Put api_function_address in place. ++ Address function_address = v8::ToCData
(api_call_info->callback()); ++ __ mov(api_function_address, Immediate(function_address)); ++ ++ // Jump to stub. ++ CallApiCallbackStub stub(isolate, is_store, call_data_undefined, ++ !optimization.is_constant_call()); ++ __ TailCallStub(&stub); ++} ++ ++ ++// Generate code to check that a global property cell is empty. Create ++// the property cell at compilation time if no cell exists for the ++// property. ++void PropertyHandlerCompiler::GenerateCheckPropertyCell( ++ MacroAssembler* masm, Handle global, Handle name, ++ Register scratch, Label* miss) { ++ Handle cell = JSGlobalObject::EnsureEmptyPropertyCell( ++ global, name, PropertyCellType::kInvalidated); ++ Isolate* isolate = masm->isolate(); ++ DCHECK(cell->value()->IsTheHole(isolate)); ++ Handle weak_cell = isolate->factory()->NewWeakCell(cell); ++ __ LoadWeakValue(scratch, weak_cell, miss); ++ __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), ++ Immediate(isolate->factory()->the_hole_value())); ++ __ j(not_equal, miss); ++} ++ ++ ++void NamedStoreHandlerCompiler::GenerateStoreViaSetter( ++ MacroAssembler* masm, Handle map, Register receiver, Register holder, ++ int accessor_index, int expected_arguments, Register scratch) { ++ // ----------- S t a t e ------------- ++ // -- esp[12] : value ++ // -- esp[8] : slot ++ // -- esp[4] : vector ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ LoadParameterFromStack(value(), Descriptor::kValue); ++ ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Save context register ++ __ push(esi); ++ // Save value register, so we can restore it later. ++ __ push(value()); ++ ++ if (accessor_index >= 0) { ++ DCHECK(!holder.is(scratch)); ++ DCHECK(!receiver.is(scratch)); ++ DCHECK(!value().is(scratch)); ++ // Call the JavaScript setter with receiver and value on the stack. ++ if (map->IsJSGlobalObjectMap()) { ++ __ mov(scratch, ++ FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); ++ receiver = scratch; ++ } ++ __ push(receiver); ++ __ push(value()); ++ __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER); ++ __ Set(eax, 1); ++ __ Call(masm->isolate()->builtins()->CallFunction( ++ ConvertReceiverMode::kNotNullOrUndefined), ++ RelocInfo::CODE_TARGET); ++ } else { ++ // If we generate a global code snippet for deoptimization only, remember ++ // the place to continue after deoptimization. ++ masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); ++ } ++ ++ // We have to return the passed value, not the return value of the setter. ++ __ pop(eax); ++ // Restore context register. ++ __ pop(esi); ++ } ++ if (accessor_index >= 0) { ++ __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize); ++ } else { ++ // If we generate a global code snippet for deoptimization only, don't try ++ // to drop stack arguments for the StoreIC because they are not a part of ++ // expression stack and deoptimizer does not reconstruct them. ++ __ ret(0); ++ } ++} ++ ++#undef __ ++#define __ ACCESS_MASM(masm()) ++ ++ ++void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, ++ Handle name) { ++ if (!label->is_unused()) { ++ __ bind(label); ++ __ mov(this->name(), Immediate(name)); ++ } ++} ++ ++void PropertyHandlerCompiler::GenerateAccessCheck( ++ Handle native_context_cell, Register scratch1, Register scratch2, ++ Label* miss, bool compare_native_contexts_only) { ++ Label done; ++ // Load current native context. ++ __ mov(scratch1, NativeContextOperand()); ++ // Load expected native context. ++ __ LoadWeakValue(scratch2, native_context_cell, miss); ++ __ cmp(scratch1, scratch2); ++ ++ if (!compare_native_contexts_only) { ++ __ j(equal, &done); ++ ++ // Compare security tokens of current and expected native contexts. ++ __ mov(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); ++ __ mov(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); ++ __ cmp(scratch1, scratch2); ++ } ++ __ j(not_equal, miss); ++ ++ __ bind(&done); ++} ++ ++Register PropertyHandlerCompiler::CheckPrototypes( ++ Register object_reg, Register holder_reg, Register scratch1, ++ Register scratch2, Handle name, Label* miss) { ++ Handle receiver_map = map(); ++ ++ // Make sure there's no overlap between holder and object registers. ++ DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); ++ DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && ++ !scratch2.is(scratch1)); ++ ++ Handle validity_cell = ++ Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); ++ if (!validity_cell.is_null()) { ++ DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); ++ // Operand::ForCell(...) points to the cell's payload! ++ __ cmp(Operand::ForCell(validity_cell), ++ Immediate(Smi::FromInt(Map::kPrototypeChainValid))); ++ __ j(not_equal, miss); ++ } ++ ++ // Keep track of the current object in register reg. ++ Register reg = object_reg; ++ int depth = 0; ++ ++ Handle current = Handle::null(); ++ if (receiver_map->IsJSGlobalObjectMap()) { ++ current = isolate()->global_object(); ++ } ++ ++ Handle current_map(receiver_map->GetPrototypeChainRootMap(isolate()), ++ isolate()); ++ Handle holder_map(holder()->map()); ++ // Traverse the prototype chain and check the maps in the prototype chain for ++ // fast and global objects or do negative lookup for normal objects. ++ while (!current_map.is_identical_to(holder_map)) { ++ ++depth; ++ ++ if (current_map->IsJSGlobalObjectMap()) { ++ GenerateCheckPropertyCell(masm(), Handle::cast(current), ++ name, scratch2, miss); ++ } else if (current_map->is_dictionary_map()) { ++ DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. ++ DCHECK(name->IsUniqueName()); ++ DCHECK(current.is_null() || ++ current->property_dictionary()->FindEntry(name) == ++ NameDictionary::kNotFound); ++ ++ if (depth > 1) { ++ Handle weak_cell = ++ Map::GetOrCreatePrototypeWeakCell(current, isolate()); ++ __ LoadWeakValue(reg, weak_cell, miss); ++ } ++ GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, ++ scratch2); ++ } ++ ++ reg = holder_reg; // From now on the object will be in holder_reg. ++ // Go to the next object in the prototype chain. ++ current = handle(JSObject::cast(current_map->prototype())); ++ current_map = handle(current->map()); ++ } ++ ++ DCHECK(!current_map->IsJSGlobalProxyMap()); ++ ++ // Log the check depth. ++ LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); ++ ++ if (depth != 0) { ++ Handle weak_cell = ++ Map::GetOrCreatePrototypeWeakCell(current, isolate()); ++ __ LoadWeakValue(reg, weak_cell, miss); ++ } ++ ++ // Return the register containing the holder. ++ return reg; ++} ++ ++ ++void NamedLoadHandlerCompiler::FrontendFooter(Handle name, Label* miss) { ++ if (!miss->is_unused()) { ++ Label success; ++ __ jmp(&success); ++ __ bind(miss); ++ if (IC::ShouldPushPopSlotAndVector(kind())) { ++ DCHECK(kind() == Code::LOAD_IC); ++ PopVectorAndSlot(); ++ } ++ TailCallBuiltin(masm(), MissBuiltin(kind())); ++ __ bind(&success); ++ } ++} ++ ++ ++void NamedStoreHandlerCompiler::FrontendFooter(Handle name, Label* miss) { ++ if (!miss->is_unused()) { ++ Label success; ++ __ jmp(&success); ++ GenerateRestoreName(miss, name); ++ DCHECK(!IC::ShouldPushPopSlotAndVector(kind())); ++ TailCallBuiltin(masm(), MissBuiltin(kind())); ++ __ bind(&success); ++ } ++} ++ ++void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { ++ // Zap register aliases of the arguments passed on the stack to ensure they ++ // are properly loaded by the handler (debug-only). ++ STATIC_ASSERT(Descriptor::kPassLastArgsOnStack); ++ STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3); ++ __ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue)); ++ __ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue)); ++ __ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue)); ++} ++ ++Handle NamedStoreHandlerCompiler::CompileStoreCallback( ++ Handle object, Handle name, Handle callback, ++ LanguageMode language_mode) { ++ Register holder_reg = Frontend(name); ++ __ LoadParameterFromStack(value(), Descriptor::kValue); ++ ++ __ pop(scratch1()); // remove the return address ++ // Discard stack arguments. ++ __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount * ++ kPointerSize)); ++ __ push(receiver()); ++ __ push(holder_reg); ++ // If the callback cannot leak, then push the callback directly, ++ // otherwise wrap it in a weak cell. ++ if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) { ++ __ Push(callback); ++ } else { ++ Handle cell = isolate()->factory()->NewWeakCell(callback); ++ __ Push(cell); ++ } ++ __ Push(name); ++ __ push(value()); ++ __ push(Immediate(Smi::FromInt(language_mode))); ++ __ push(scratch1()); // restore return address ++ ++ // Do tail-call to the runtime system. ++ __ TailCallRuntime(Runtime::kStoreCallbackProperty); ++ ++ // Return the generated code. ++ return GetCode(kind(), name); ++} ++ ++ ++Register NamedStoreHandlerCompiler::value() { ++ return StoreDescriptor::ValueRegister(); ++} ++ ++ ++#undef __ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/ic-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/ic-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/ic-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/ic-x87.cc 2017-12-25 17:42:57.215465646 +0100 +@@ -0,0 +1,84 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/codegen.h" ++#include "src/ic/ic.h" ++#include "src/ic/stub-cache.h" ++ ++namespace v8 { ++namespace internal { ++ ++ ++Condition CompareIC::ComputeCondition(Token::Value op) { ++ switch (op) { ++ case Token::EQ_STRICT: ++ case Token::EQ: ++ return equal; ++ case Token::LT: ++ return less; ++ case Token::GT: ++ return greater; ++ case Token::LTE: ++ return less_equal; ++ case Token::GTE: ++ return greater_equal; ++ default: ++ UNREACHABLE(); ++ } ++} ++ ++ ++bool CompareIC::HasInlinedSmiCode(Address address) { ++ // The address of the instruction following the call. ++ Address test_instruction_address = ++ address + Assembler::kCallTargetAddressOffset; ++ ++ // If the instruction following the call is not a test al, nothing ++ // was inlined. ++ return *test_instruction_address == Assembler::kTestAlByte; ++} ++ ++ ++void PatchInlinedSmiCode(Isolate* isolate, Address address, ++ InlinedSmiCheck check) { ++ // The address of the instruction following the call. ++ Address test_instruction_address = ++ address + Assembler::kCallTargetAddressOffset; ++ ++ // If the instruction following the call is not a test al, nothing ++ // was inlined. ++ if (*test_instruction_address != Assembler::kTestAlByte) { ++ DCHECK(*test_instruction_address == Assembler::kNopByte); ++ return; ++ } ++ ++ Address delta_address = test_instruction_address + 1; ++ // The delta to the start of the map check instruction and the ++ // condition code uses at the patched jump. ++ uint8_t delta = *reinterpret_cast(delta_address); ++ if (FLAG_trace_ic) { ++ LOG(isolate, PatchIC(address, test_instruction_address, delta)); ++ } ++ ++ // Patch with a short conditional jump. Enabling means switching from a short ++ // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the ++ // reverse operation of that. ++ Address jmp_address = test_instruction_address - delta; ++ DCHECK((check == ENABLE_INLINED_SMI_CHECK) ++ ? (*jmp_address == Assembler::kJncShortOpcode || ++ *jmp_address == Assembler::kJcShortOpcode) ++ : (*jmp_address == Assembler::kJnzShortOpcode || ++ *jmp_address == Assembler::kJzShortOpcode)); ++ Condition cc = ++ (check == ENABLE_INLINED_SMI_CHECK) ++ ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) ++ : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); ++ *jmp_address = static_cast(Assembler::kJccShortPrefix | cc); ++} ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/ic/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/ic/x87/OWNERS 2017-12-25 17:42:57.214465661 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/inspector/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/inspector/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/inspector/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/inspector/BUILD.gn 2017-12-25 13:05:24.029939435 +0100 +@@ -106,7 +106,7 @@ + "/wd4996", # Deprecated function call. + ] + } +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + defines = [ "BUILDING_V8_SHARED" ] + } + } +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/interface-descriptors.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/interface-descriptors.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/interface-descriptors.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/interface-descriptors.h 2017-12-25 17:42:57.215465646 +0100 +@@ -392,7 +392,7 @@ + static const Register ValueRegister(); + static const Register SlotRegister(); + +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + static const bool kPassLastArgsOnStack = true; + #else + static const bool kPassLastArgsOnStack = false; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/interpreter/interpreter-assembler.cc 2017-12-25 17:42:57.215465646 +0100 +@@ -1367,8 +1367,9 @@ + bool InterpreterAssembler::TargetSupportsUnalignedAccess() { + #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 + return false; +-#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_S390 || \ +- V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC ++#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87 || \ ++ V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || \ ++ V8_TARGET_ARCH_PPC + return true; + #else + #error "Unknown Architecture" +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/log.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/log.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/log.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/log.cc 2017-12-25 17:42:57.216465632 +0100 +@@ -370,6 +370,8 @@ + const char arch[] = "ppc"; + #elif V8_TARGET_ARCH_MIPS + const char arch[] = "mips"; ++#elif V8_TARGET_ARCH_X87 ++ const char arch[] = "x87"; + #elif V8_TARGET_ARCH_ARM64 + const char arch[] = "arm64"; + #elif V8_TARGET_ARCH_S390 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/macro-assembler.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/macro-assembler.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/macro-assembler.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/macro-assembler.h 2017-12-25 17:42:57.216465632 +0100 +@@ -52,6 +52,8 @@ + #elif V8_TARGET_ARCH_S390 + #include "src/s390/constants-s390.h" + #include "src/s390/macro-assembler-s390.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/macro-assembler-x87.h" + #else + #error Unsupported target architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/jsregexp.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/jsregexp.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/jsregexp.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/jsregexp.cc 2017-12-25 17:42:57.217465617 +0100 +@@ -48,6 +48,8 @@ + #include "src/regexp/mips/regexp-macro-assembler-mips.h" + #elif V8_TARGET_ARCH_MIPS64 + #include "src/regexp/mips64/regexp-macro-assembler-mips64.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/regexp/x87/regexp-macro-assembler-x87.h" + #else + #error Unsupported target architecture. + #endif +@@ -6760,6 +6762,9 @@ + #elif V8_TARGET_ARCH_MIPS64 + RegExpMacroAssemblerMIPS macro_assembler(isolate, zone, mode, + (data->capture_count + 1) * 2); ++#elif V8_TARGET_ARCH_X87 ++ RegExpMacroAssemblerX87 macro_assembler(isolate, zone, mode, ++ (data->capture_count + 1) * 2); + #else + #error "Unsupported architecture" + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/OWNERS 2017-12-25 17:42:57.217465617 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.cc 2017-12-25 17:42:57.217465617 +0100 +@@ -0,0 +1,1273 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/regexp/x87/regexp-macro-assembler-x87.h" ++ ++#include "src/log.h" ++#include "src/macro-assembler.h" ++#include "src/regexp/regexp-macro-assembler.h" ++#include "src/regexp/regexp-stack.h" ++#include "src/unicode.h" ++ ++namespace v8 { ++namespace internal { ++ ++#ifndef V8_INTERPRETED_REGEXP ++/* ++ * This assembler uses the following register assignment convention ++ * - edx : Current character. Must be loaded using LoadCurrentCharacter ++ * before using any of the dispatch methods. Temporarily stores the ++ * index of capture start after a matching pass for a global regexp. ++ * - edi : Current position in input, as negative offset from end of string. ++ * Please notice that this is the byte offset, not the character offset! ++ * - esi : end of input (points to byte after last character in input). ++ * - ebp : Frame pointer. Used to access arguments, local variables and ++ * RegExp registers. ++ * - esp : Points to tip of C stack. ++ * - ecx : Points to tip of backtrack stack ++ * ++ * The registers eax and ebx are free to use for computations. ++ * ++ * Each call to a public method should retain this convention. ++ * The stack will have the following structure: ++ * - Isolate* isolate (address of the current isolate) ++ * - direct_call (if 1, direct call from JavaScript code, if 0 ++ * call through the runtime system) ++ * - stack_area_base (high end of the memory area to use as ++ * backtracking stack) ++ * - capture array size (may fit multiple sets of matches) ++ * - int* capture_array (int[num_saved_registers_], for output). ++ * - end of input (address of end of string) ++ * - start of input (address of first character in string) ++ * - start index (character index of start) ++ * - String* input_string (location of a handle containing the string) ++ * --- frame alignment (if applicable) --- ++ * - return address ++ * ebp-> - old ebp ++ * - backup of caller esi ++ * - backup of caller edi ++ * - backup of caller ebx ++ * - success counter (only for global regexps to count matches). ++ * - Offset of location before start of input (effectively character ++ * string start - 1). Used to initialize capture registers to a ++ * non-position. ++ * - register 0 ebp[-4] (only positions must be stored in the first ++ * - register 1 ebp[-8] num_saved_registers_ registers) ++ * - ... ++ * ++ * The first num_saved_registers_ registers are initialized to point to ++ * "character -1" in the string (i.e., char_size() bytes before the first ++ * character of the string). The remaining registers starts out as garbage. ++ * ++ * The data up to the return address must be placed there by the calling ++ * code, by calling the code entry as cast to a function with the signature: ++ * int (*match)(String* input_string, ++ * int start_index, ++ * Address start, ++ * Address end, ++ * int* capture_output_array, ++ * int num_capture_registers, ++ * byte* stack_area_base, ++ * bool direct_call = false, ++ * Isolate* isolate); ++ */ ++ ++#define __ ACCESS_MASM(masm_) ++ ++RegExpMacroAssemblerX87::RegExpMacroAssemblerX87(Isolate* isolate, Zone* zone, ++ Mode mode, ++ int registers_to_save) ++ : NativeRegExpMacroAssembler(isolate, zone), ++ masm_(new MacroAssembler(isolate, NULL, kRegExpCodeSize, ++ CodeObjectRequired::kYes)), ++ mode_(mode), ++ num_registers_(registers_to_save), ++ num_saved_registers_(registers_to_save), ++ entry_label_(), ++ start_label_(), ++ success_label_(), ++ backtrack_label_(), ++ exit_label_() { ++ DCHECK_EQ(0, registers_to_save % 2); ++ __ jmp(&entry_label_); // We'll write the entry code later. ++ __ bind(&start_label_); // And then continue from here. ++} ++ ++ ++RegExpMacroAssemblerX87::~RegExpMacroAssemblerX87() { ++ delete masm_; ++ // Unuse labels in case we throw away the assembler without calling GetCode. ++ entry_label_.Unuse(); ++ start_label_.Unuse(); ++ success_label_.Unuse(); ++ backtrack_label_.Unuse(); ++ exit_label_.Unuse(); ++ check_preempt_label_.Unuse(); ++ stack_overflow_label_.Unuse(); ++} ++ ++ ++int RegExpMacroAssemblerX87::stack_limit_slack() { ++ return RegExpStack::kStackLimitSlack; ++} ++ ++ ++void RegExpMacroAssemblerX87::AdvanceCurrentPosition(int by) { ++ if (by != 0) { ++ __ add(edi, Immediate(by * char_size())); ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::AdvanceRegister(int reg, int by) { ++ DCHECK(reg >= 0); ++ DCHECK(reg < num_registers_); ++ if (by != 0) { ++ __ add(register_location(reg), Immediate(by)); ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::Backtrack() { ++ CheckPreemption(); ++ // Pop Code* offset from backtrack stack, add Code* and jump to location. ++ Pop(ebx); ++ __ add(ebx, Immediate(masm_->CodeObject())); ++ __ jmp(ebx); ++} ++ ++ ++void RegExpMacroAssemblerX87::Bind(Label* label) { ++ __ bind(label); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacter(uint32_t c, Label* on_equal) { ++ __ cmp(current_character(), c); ++ BranchOrBacktrack(equal, on_equal); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacterGT(uc16 limit, Label* on_greater) { ++ __ cmp(current_character(), limit); ++ BranchOrBacktrack(greater, on_greater); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckAtStart(Label* on_at_start) { ++ __ lea(eax, Operand(edi, -char_size())); ++ __ cmp(eax, Operand(ebp, kStringStartMinusOne)); ++ BranchOrBacktrack(equal, on_at_start); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckNotAtStart(int cp_offset, ++ Label* on_not_at_start) { ++ __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size())); ++ __ cmp(eax, Operand(ebp, kStringStartMinusOne)); ++ BranchOrBacktrack(not_equal, on_not_at_start); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacterLT(uc16 limit, Label* on_less) { ++ __ cmp(current_character(), limit); ++ BranchOrBacktrack(less, on_less); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckGreedyLoop(Label* on_equal) { ++ Label fallthrough; ++ __ cmp(edi, Operand(backtrack_stackpointer(), 0)); ++ __ j(not_equal, &fallthrough); ++ __ add(backtrack_stackpointer(), Immediate(kPointerSize)); // Pop. ++ BranchOrBacktrack(no_condition, on_equal); ++ __ bind(&fallthrough); ++} ++ ++void RegExpMacroAssemblerX87::CheckNotBackReferenceIgnoreCase( ++ int start_reg, bool read_backward, bool unicode, Label* on_no_match) { ++ Label fallthrough; ++ __ mov(edx, register_location(start_reg)); // Index of start of capture ++ __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture ++ __ sub(ebx, edx); // Length of capture. ++ ++ // At this point, the capture registers are either both set or both cleared. ++ // If the capture length is zero, then the capture is either empty or cleared. ++ // Fall through in both cases. ++ __ j(equal, &fallthrough); ++ ++ // Check that there are sufficient characters left in the input. ++ if (read_backward) { ++ __ mov(eax, Operand(ebp, kStringStartMinusOne)); ++ __ add(eax, ebx); ++ __ cmp(edi, eax); ++ BranchOrBacktrack(less_equal, on_no_match); ++ } else { ++ __ mov(eax, edi); ++ __ add(eax, ebx); ++ BranchOrBacktrack(greater, on_no_match); ++ } ++ ++ if (mode_ == LATIN1) { ++ Label success; ++ Label fail; ++ Label loop_increment; ++ // Save register contents to make the registers available below. ++ __ push(edi); ++ __ push(backtrack_stackpointer()); ++ // After this, the eax, ecx, and edi registers are available. ++ ++ __ add(edx, esi); // Start of capture ++ __ add(edi, esi); // Start of text to match against capture. ++ if (read_backward) { ++ __ sub(edi, ebx); // Offset by length when matching backwards. ++ } ++ __ add(ebx, edi); // End of text to match against capture. ++ ++ Label loop; ++ __ bind(&loop); ++ __ movzx_b(eax, Operand(edi, 0)); ++ __ cmpb_al(Operand(edx, 0)); ++ __ j(equal, &loop_increment); ++ ++ // Mismatch, try case-insensitive match (converting letters to lower-case). ++ __ or_(eax, 0x20); // Convert match character to lower-case. ++ __ lea(ecx, Operand(eax, -'a')); ++ __ cmp(ecx, static_cast('z' - 'a')); // Is eax a lowercase letter? ++ Label convert_capture; ++ __ j(below_equal, &convert_capture); // In range 'a'-'z'. ++ // Latin-1: Check for values in range [224,254] but not 247. ++ __ sub(ecx, Immediate(224 - 'a')); ++ __ cmp(ecx, Immediate(254 - 224)); ++ __ j(above, &fail); // Weren't Latin-1 letters. ++ __ cmp(ecx, Immediate(247 - 224)); // Check for 247. ++ __ j(equal, &fail); ++ __ bind(&convert_capture); ++ // Also convert capture character. ++ __ movzx_b(ecx, Operand(edx, 0)); ++ __ or_(ecx, 0x20); ++ ++ __ cmp(eax, ecx); ++ __ j(not_equal, &fail); ++ ++ __ bind(&loop_increment); ++ // Increment pointers into match and capture strings. ++ __ add(edx, Immediate(1)); ++ __ add(edi, Immediate(1)); ++ // Compare to end of match, and loop if not done. ++ __ cmp(edi, ebx); ++ __ j(below, &loop); ++ __ jmp(&success); ++ ++ __ bind(&fail); ++ // Restore original values before failing. ++ __ pop(backtrack_stackpointer()); ++ __ pop(edi); ++ BranchOrBacktrack(no_condition, on_no_match); ++ ++ __ bind(&success); ++ // Restore original value before continuing. ++ __ pop(backtrack_stackpointer()); ++ // Drop original value of character position. ++ __ add(esp, Immediate(kPointerSize)); ++ // Compute new value of character position after the matched part. ++ __ sub(edi, esi); ++ if (read_backward) { ++ // Subtract match length if we matched backward. ++ __ add(edi, register_location(start_reg)); ++ __ sub(edi, register_location(start_reg + 1)); ++ } ++ } else { ++ DCHECK(mode_ == UC16); ++ // Save registers before calling C function. ++ __ push(esi); ++ __ push(edi); ++ __ push(backtrack_stackpointer()); ++ __ push(ebx); ++ ++ static const int argument_count = 4; ++ __ PrepareCallCFunction(argument_count, ecx); ++ // Put arguments into allocated stack area, last argument highest on stack. ++ // Parameters are ++ // Address byte_offset1 - Address captured substring's start. ++ // Address byte_offset2 - Address of current character position. ++ // size_t byte_length - length of capture in bytes(!) ++// Isolate* isolate or 0 if unicode flag. ++ ++ // Set isolate. ++#ifdef V8_INTL_SUPPORT ++ if (unicode) { ++ __ mov(Operand(esp, 3 * kPointerSize), Immediate(0)); ++ } else // NOLINT ++#endif // V8_INTL_SUPPORT ++ { ++ __ mov(Operand(esp, 3 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ } ++ // Set byte_length. ++ __ mov(Operand(esp, 2 * kPointerSize), ebx); ++ // Set byte_offset2. ++ // Found by adding negative string-end offset of current position (edi) ++ // to end of string. ++ __ add(edi, esi); ++ if (read_backward) { ++ __ sub(edi, ebx); // Offset by length when matching backwards. ++ } ++ __ mov(Operand(esp, 1 * kPointerSize), edi); ++ // Set byte_offset1. ++ // Start of capture, where edx already holds string-end negative offset. ++ __ add(edx, esi); ++ __ mov(Operand(esp, 0 * kPointerSize), edx); ++ ++ { ++ AllowExternalCallThatCantCauseGC scope(masm_); ++ ExternalReference compare = ++ ExternalReference::re_case_insensitive_compare_uc16(isolate()); ++ __ CallCFunction(compare, argument_count); ++ } ++ // Pop original values before reacting on result value. ++ __ pop(ebx); ++ __ pop(backtrack_stackpointer()); ++ __ pop(edi); ++ __ pop(esi); ++ ++ // Check if function returned non-zero for success or zero for failure. ++ __ or_(eax, eax); ++ BranchOrBacktrack(zero, on_no_match); ++ // On success, advance position by length of capture. ++ if (read_backward) { ++ __ sub(edi, ebx); ++ } else { ++ __ add(edi, ebx); ++ } ++ } ++ __ bind(&fallthrough); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckNotBackReference(int start_reg, ++ bool read_backward, ++ Label* on_no_match) { ++ Label fallthrough; ++ Label success; ++ Label fail; ++ ++ // Find length of back-referenced capture. ++ __ mov(edx, register_location(start_reg)); ++ __ mov(eax, register_location(start_reg + 1)); ++ __ sub(eax, edx); // Length to check. ++ ++ // At this point, the capture registers are either both set or both cleared. ++ // If the capture length is zero, then the capture is either empty or cleared. ++ // Fall through in both cases. ++ __ j(equal, &fallthrough); ++ ++ // Check that there are sufficient characters left in the input. ++ if (read_backward) { ++ __ mov(ebx, Operand(ebp, kStringStartMinusOne)); ++ __ add(ebx, eax); ++ __ cmp(edi, ebx); ++ BranchOrBacktrack(less_equal, on_no_match); ++ } else { ++ __ mov(ebx, edi); ++ __ add(ebx, eax); ++ BranchOrBacktrack(greater, on_no_match); ++ } ++ ++ // Save register to make it available below. ++ __ push(backtrack_stackpointer()); ++ ++ // Compute pointers to match string and capture string ++ __ add(edx, esi); // Start of capture. ++ __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match. ++ if (read_backward) { ++ __ sub(ebx, eax); // Offset by length when matching backwards. ++ } ++ __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match ++ ++ Label loop; ++ __ bind(&loop); ++ if (mode_ == LATIN1) { ++ __ movzx_b(eax, Operand(edx, 0)); ++ __ cmpb_al(Operand(ebx, 0)); ++ } else { ++ DCHECK(mode_ == UC16); ++ __ movzx_w(eax, Operand(edx, 0)); ++ __ cmpw_ax(Operand(ebx, 0)); ++ } ++ __ j(not_equal, &fail); ++ // Increment pointers into capture and match string. ++ __ add(edx, Immediate(char_size())); ++ __ add(ebx, Immediate(char_size())); ++ // Check if we have reached end of match area. ++ __ cmp(ebx, ecx); ++ __ j(below, &loop); ++ __ jmp(&success); ++ ++ __ bind(&fail); ++ // Restore backtrack stackpointer. ++ __ pop(backtrack_stackpointer()); ++ BranchOrBacktrack(no_condition, on_no_match); ++ ++ __ bind(&success); ++ // Move current character position to position after match. ++ __ mov(edi, ecx); ++ __ sub(edi, esi); ++ if (read_backward) { ++ // Subtract match length if we matched backward. ++ __ add(edi, register_location(start_reg)); ++ __ sub(edi, register_location(start_reg + 1)); ++ } ++ // Restore backtrack stackpointer. ++ __ pop(backtrack_stackpointer()); ++ ++ __ bind(&fallthrough); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckNotCharacter(uint32_t c, ++ Label* on_not_equal) { ++ __ cmp(current_character(), c); ++ BranchOrBacktrack(not_equal, on_not_equal); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacterAfterAnd(uint32_t c, ++ uint32_t mask, ++ Label* on_equal) { ++ if (c == 0) { ++ __ test(current_character(), Immediate(mask)); ++ } else { ++ __ mov(eax, mask); ++ __ and_(eax, current_character()); ++ __ cmp(eax, c); ++ } ++ BranchOrBacktrack(equal, on_equal); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckNotCharacterAfterAnd(uint32_t c, ++ uint32_t mask, ++ Label* on_not_equal) { ++ if (c == 0) { ++ __ test(current_character(), Immediate(mask)); ++ } else { ++ __ mov(eax, mask); ++ __ and_(eax, current_character()); ++ __ cmp(eax, c); ++ } ++ BranchOrBacktrack(not_equal, on_not_equal); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckNotCharacterAfterMinusAnd( ++ uc16 c, ++ uc16 minus, ++ uc16 mask, ++ Label* on_not_equal) { ++ DCHECK(minus < String::kMaxUtf16CodeUnit); ++ __ lea(eax, Operand(current_character(), -minus)); ++ if (c == 0) { ++ __ test(eax, Immediate(mask)); ++ } else { ++ __ and_(eax, mask); ++ __ cmp(eax, c); ++ } ++ BranchOrBacktrack(not_equal, on_not_equal); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacterInRange( ++ uc16 from, ++ uc16 to, ++ Label* on_in_range) { ++ __ lea(eax, Operand(current_character(), -from)); ++ __ cmp(eax, to - from); ++ BranchOrBacktrack(below_equal, on_in_range); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckCharacterNotInRange( ++ uc16 from, ++ uc16 to, ++ Label* on_not_in_range) { ++ __ lea(eax, Operand(current_character(), -from)); ++ __ cmp(eax, to - from); ++ BranchOrBacktrack(above, on_not_in_range); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckBitInTable( ++ Handle table, ++ Label* on_bit_set) { ++ __ mov(eax, Immediate(table)); ++ Register index = current_character(); ++ if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) { ++ __ mov(ebx, kTableSize - 1); ++ __ and_(ebx, current_character()); ++ index = ebx; ++ } ++ __ cmpb(FieldOperand(eax, index, times_1, ByteArray::kHeaderSize), ++ Immediate(0)); ++ BranchOrBacktrack(not_equal, on_bit_set); ++} ++ ++ ++bool RegExpMacroAssemblerX87::CheckSpecialCharacterClass(uc16 type, ++ Label* on_no_match) { ++ // Range checks (c in min..max) are generally implemented by an unsigned ++ // (c - min) <= (max - min) check ++ switch (type) { ++ case 's': ++ // Match space-characters ++ if (mode_ == LATIN1) { ++ // One byte space characters are '\t'..'\r', ' ' and \u00a0. ++ Label success; ++ __ cmp(current_character(), ' '); ++ __ j(equal, &success, Label::kNear); ++ // Check range 0x09..0x0d ++ __ lea(eax, Operand(current_character(), -'\t')); ++ __ cmp(eax, '\r' - '\t'); ++ __ j(below_equal, &success, Label::kNear); ++ // \u00a0 (NBSP). ++ __ cmp(eax, 0x00a0 - '\t'); ++ BranchOrBacktrack(not_equal, on_no_match); ++ __ bind(&success); ++ return true; ++ } ++ return false; ++ case 'S': ++ // The emitted code for generic character classes is good enough. ++ return false; ++ case 'd': ++ // Match ASCII digits ('0'..'9') ++ __ lea(eax, Operand(current_character(), -'0')); ++ __ cmp(eax, '9' - '0'); ++ BranchOrBacktrack(above, on_no_match); ++ return true; ++ case 'D': ++ // Match non ASCII-digits ++ __ lea(eax, Operand(current_character(), -'0')); ++ __ cmp(eax, '9' - '0'); ++ BranchOrBacktrack(below_equal, on_no_match); ++ return true; ++ case '.': { ++ // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029) ++ __ mov(eax, current_character()); ++ __ xor_(eax, Immediate(0x01)); ++ // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c ++ __ sub(eax, Immediate(0x0b)); ++ __ cmp(eax, 0x0c - 0x0b); ++ BranchOrBacktrack(below_equal, on_no_match); ++ if (mode_ == UC16) { ++ // Compare original value to 0x2028 and 0x2029, using the already ++ // computed (current_char ^ 0x01 - 0x0b). I.e., check for ++ // 0x201d (0x2028 - 0x0b) or 0x201e. ++ __ sub(eax, Immediate(0x2028 - 0x0b)); ++ __ cmp(eax, 0x2029 - 0x2028); ++ BranchOrBacktrack(below_equal, on_no_match); ++ } ++ return true; ++ } ++ case 'w': { ++ if (mode_ != LATIN1) { ++ // Table is 256 entries, so all Latin1 characters can be tested. ++ __ cmp(current_character(), Immediate('z')); ++ BranchOrBacktrack(above, on_no_match); ++ } ++ DCHECK_EQ(0, word_character_map[0]); // Character '\0' is not a word char. ++ ExternalReference word_map = ExternalReference::re_word_character_map(); ++ __ test_b(current_character(), ++ Operand::StaticArray(current_character(), times_1, word_map)); ++ BranchOrBacktrack(zero, on_no_match); ++ return true; ++ } ++ case 'W': { ++ Label done; ++ if (mode_ != LATIN1) { ++ // Table is 256 entries, so all Latin1 characters can be tested. ++ __ cmp(current_character(), Immediate('z')); ++ __ j(above, &done); ++ } ++ DCHECK_EQ(0, word_character_map[0]); // Character '\0' is not a word char. ++ ExternalReference word_map = ExternalReference::re_word_character_map(); ++ __ test_b(current_character(), ++ Operand::StaticArray(current_character(), times_1, word_map)); ++ BranchOrBacktrack(not_zero, on_no_match); ++ if (mode_ != LATIN1) { ++ __ bind(&done); ++ } ++ return true; ++ } ++ // Non-standard classes (with no syntactic shorthand) used internally. ++ case '*': ++ // Match any character. ++ return true; ++ case 'n': { ++ // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029). ++ // The opposite of '.'. ++ __ mov(eax, current_character()); ++ __ xor_(eax, Immediate(0x01)); ++ // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c ++ __ sub(eax, Immediate(0x0b)); ++ __ cmp(eax, 0x0c - 0x0b); ++ if (mode_ == LATIN1) { ++ BranchOrBacktrack(above, on_no_match); ++ } else { ++ Label done; ++ BranchOrBacktrack(below_equal, &done); ++ DCHECK_EQ(UC16, mode_); ++ // Compare original value to 0x2028 and 0x2029, using the already ++ // computed (current_char ^ 0x01 - 0x0b). I.e., check for ++ // 0x201d (0x2028 - 0x0b) or 0x201e. ++ __ sub(eax, Immediate(0x2028 - 0x0b)); ++ __ cmp(eax, 1); ++ BranchOrBacktrack(above, on_no_match); ++ __ bind(&done); ++ } ++ return true; ++ } ++ // No custom implementation (yet): s(UC16), S(UC16). ++ default: ++ return false; ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::Fail() { ++ STATIC_ASSERT(FAILURE == 0); // Return value for failure is zero. ++ if (!global()) { ++ __ Move(eax, Immediate(FAILURE)); ++ } ++ __ jmp(&exit_label_); ++} ++ ++ ++Handle RegExpMacroAssemblerX87::GetCode(Handle source) { ++ Label return_eax; ++ // Finalize code - write the entry point code now we know how many ++ // registers we need. ++ ++ // Entry code: ++ __ bind(&entry_label_); ++ ++ // Tell the system that we have a stack frame. Because the type is MANUAL, no ++ // code is generated. ++ FrameScope scope(masm_, StackFrame::MANUAL); ++ ++ // Actually emit code to start a new stack frame. ++ __ push(ebp); ++ __ mov(ebp, esp); ++ // Save callee-save registers. Order here should correspond to order of ++ // kBackup_ebx etc. ++ __ push(esi); ++ __ push(edi); ++ __ push(ebx); // Callee-save on MacOS. ++ __ push(Immediate(0)); // Number of successful matches in a global regexp. ++ __ push(Immediate(0)); // Make room for "string start - 1" constant. ++ ++ // Check if we have space on the stack for registers. ++ Label stack_limit_hit; ++ Label stack_ok; ++ ++ ExternalReference stack_limit = ++ ExternalReference::address_of_stack_limit(isolate()); ++ __ mov(ecx, esp); ++ __ sub(ecx, Operand::StaticVariable(stack_limit)); ++ // Handle it if the stack pointer is already below the stack limit. ++ __ j(below_equal, &stack_limit_hit); ++ // Check if there is room for the variable number of registers above ++ // the stack limit. ++ __ cmp(ecx, num_registers_ * kPointerSize); ++ __ j(above_equal, &stack_ok); ++ // Exit with OutOfMemory exception. There is not enough space on the stack ++ // for our working registers. ++ __ mov(eax, EXCEPTION); ++ __ jmp(&return_eax); ++ ++ __ bind(&stack_limit_hit); ++ CallCheckStackGuardState(ebx); ++ __ or_(eax, eax); ++ // If returned value is non-zero, we exit with the returned value as result. ++ __ j(not_zero, &return_eax); ++ ++ __ bind(&stack_ok); ++ // Load start index for later use. ++ __ mov(ebx, Operand(ebp, kStartIndex)); ++ ++ // Allocate space on stack for registers. ++ __ sub(esp, Immediate(num_registers_ * kPointerSize)); ++ // Load string length. ++ __ mov(esi, Operand(ebp, kInputEnd)); ++ // Load input position. ++ __ mov(edi, Operand(ebp, kInputStart)); ++ // Set up edi to be negative offset from string end. ++ __ sub(edi, esi); ++ ++ // Set eax to address of char before start of the string. ++ // (effectively string position -1). ++ __ neg(ebx); ++ if (mode_ == UC16) { ++ __ lea(eax, Operand(edi, ebx, times_2, -char_size())); ++ } else { ++ __ lea(eax, Operand(edi, ebx, times_1, -char_size())); ++ } ++ // Store this value in a local variable, for use when clearing ++ // position registers. ++ __ mov(Operand(ebp, kStringStartMinusOne), eax); ++ ++#if V8_OS_WIN ++ // Ensure that we write to each stack page, in order. Skipping a page ++ // on Windows can cause segmentation faults. Assuming page size is 4k. ++ const int kPageSize = 4096; ++ const int kRegistersPerPage = kPageSize / kPointerSize; ++ for (int i = num_saved_registers_ + kRegistersPerPage - 1; ++ i < num_registers_; ++ i += kRegistersPerPage) { ++ __ mov(register_location(i), eax); // One write every page. ++ } ++#endif // V8_OS_WIN ++ ++ Label load_char_start_regexp, start_regexp; ++ // Load newline if index is at start, previous character otherwise. ++ __ cmp(Operand(ebp, kStartIndex), Immediate(0)); ++ __ j(not_equal, &load_char_start_regexp, Label::kNear); ++ __ mov(current_character(), '\n'); ++ __ jmp(&start_regexp, Label::kNear); ++ ++ // Global regexp restarts matching here. ++ __ bind(&load_char_start_regexp); ++ // Load previous char as initial value of current character register. ++ LoadCurrentCharacterUnchecked(-1, 1); ++ __ bind(&start_regexp); ++ ++ // Initialize on-stack registers. ++ if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. ++ // Fill saved registers with initial value = start offset - 1 ++ // Fill in stack push order, to avoid accessing across an unwritten ++ // page (a problem on Windows). ++ if (num_saved_registers_ > 8) { ++ __ mov(ecx, kRegisterZero); ++ Label init_loop; ++ __ bind(&init_loop); ++ __ mov(Operand(ebp, ecx, times_1, 0), eax); ++ __ sub(ecx, Immediate(kPointerSize)); ++ __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize); ++ __ j(greater, &init_loop); ++ } else { // Unroll the loop. ++ for (int i = 0; i < num_saved_registers_; i++) { ++ __ mov(register_location(i), eax); ++ } ++ } ++ } ++ ++ // Initialize backtrack stack pointer. ++ __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); ++ ++ __ jmp(&start_label_); ++ ++ // Exit code: ++ if (success_label_.is_linked()) { ++ // Save captures when successful. ++ __ bind(&success_label_); ++ if (num_saved_registers_ > 0) { ++ // copy captures to output ++ __ mov(ebx, Operand(ebp, kRegisterOutput)); ++ __ mov(ecx, Operand(ebp, kInputEnd)); ++ __ mov(edx, Operand(ebp, kStartIndex)); ++ __ sub(ecx, Operand(ebp, kInputStart)); ++ if (mode_ == UC16) { ++ __ lea(ecx, Operand(ecx, edx, times_2, 0)); ++ } else { ++ __ add(ecx, edx); ++ } ++ for (int i = 0; i < num_saved_registers_; i++) { ++ __ mov(eax, register_location(i)); ++ if (i == 0 && global_with_zero_length_check()) { ++ // Keep capture start in edx for the zero-length check later. ++ __ mov(edx, eax); ++ } ++ // Convert to index from start of string, not end. ++ __ add(eax, ecx); ++ if (mode_ == UC16) { ++ __ sar(eax, 1); // Convert byte index to character index. ++ } ++ __ mov(Operand(ebx, i * kPointerSize), eax); ++ } ++ } ++ ++ if (global()) { ++ // Restart matching if the regular expression is flagged as global. ++ // Increment success counter. ++ __ inc(Operand(ebp, kSuccessfulCaptures)); ++ // Capture results have been stored, so the number of remaining global ++ // output registers is reduced by the number of stored captures. ++ __ mov(ecx, Operand(ebp, kNumOutputRegisters)); ++ __ sub(ecx, Immediate(num_saved_registers_)); ++ // Check whether we have enough room for another set of capture results. ++ __ cmp(ecx, Immediate(num_saved_registers_)); ++ __ j(less, &exit_label_); ++ ++ __ mov(Operand(ebp, kNumOutputRegisters), ecx); ++ // Advance the location for output. ++ __ add(Operand(ebp, kRegisterOutput), ++ Immediate(num_saved_registers_ * kPointerSize)); ++ ++ // Prepare eax to initialize registers with its value in the next run. ++ __ mov(eax, Operand(ebp, kStringStartMinusOne)); ++ ++ if (global_with_zero_length_check()) { ++ // Special case for zero-length matches. ++ // edx: capture start index ++ __ cmp(edi, edx); ++ // Not a zero-length match, restart. ++ __ j(not_equal, &load_char_start_regexp); ++ // edi (offset from the end) is zero if we already reached the end. ++ __ test(edi, edi); ++ __ j(zero, &exit_label_, Label::kNear); ++ // Advance current position after a zero-length match. ++ Label advance; ++ __ bind(&advance); ++ if (mode_ == UC16) { ++ __ add(edi, Immediate(2)); ++ } else { ++ __ inc(edi); ++ } ++ if (global_unicode()) CheckNotInSurrogatePair(0, &advance); ++ } ++ __ jmp(&load_char_start_regexp); ++ } else { ++ __ mov(eax, Immediate(SUCCESS)); ++ } ++ } ++ ++ __ bind(&exit_label_); ++ if (global()) { ++ // Return the number of successful captures. ++ __ mov(eax, Operand(ebp, kSuccessfulCaptures)); ++ } ++ ++ __ bind(&return_eax); ++ // Skip esp past regexp registers. ++ __ lea(esp, Operand(ebp, kBackup_ebx)); ++ // Restore callee-save registers. ++ __ pop(ebx); ++ __ pop(edi); ++ __ pop(esi); ++ // Exit function frame, restore previous one. ++ __ pop(ebp); ++ __ ret(0); ++ ++ // Backtrack code (branch target for conditional backtracks). ++ if (backtrack_label_.is_linked()) { ++ __ bind(&backtrack_label_); ++ Backtrack(); ++ } ++ ++ Label exit_with_exception; ++ ++ // Preempt-code ++ if (check_preempt_label_.is_linked()) { ++ SafeCallTarget(&check_preempt_label_); ++ ++ __ push(backtrack_stackpointer()); ++ __ push(edi); ++ ++ CallCheckStackGuardState(ebx); ++ __ or_(eax, eax); ++ // If returning non-zero, we should end execution with the given ++ // result as return value. ++ __ j(not_zero, &return_eax); ++ ++ __ pop(edi); ++ __ pop(backtrack_stackpointer()); ++ // String might have moved: Reload esi from frame. ++ __ mov(esi, Operand(ebp, kInputEnd)); ++ SafeReturn(); ++ } ++ ++ // Backtrack stack overflow code. ++ if (stack_overflow_label_.is_linked()) { ++ SafeCallTarget(&stack_overflow_label_); ++ // Reached if the backtrack-stack limit has been hit. ++ ++ Label grow_failed; ++ // Save registers before calling C function ++ __ push(esi); ++ __ push(edi); ++ ++ // Call GrowStack(backtrack_stackpointer()) ++ static const int num_arguments = 3; ++ __ PrepareCallCFunction(num_arguments, ebx); ++ __ mov(Operand(esp, 2 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ __ lea(eax, Operand(ebp, kStackHighEnd)); ++ __ mov(Operand(esp, 1 * kPointerSize), eax); ++ __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer()); ++ ExternalReference grow_stack = ++ ExternalReference::re_grow_stack(isolate()); ++ __ CallCFunction(grow_stack, num_arguments); ++ // If return NULL, we have failed to grow the stack, and ++ // must exit with a stack-overflow exception. ++ __ or_(eax, eax); ++ __ j(equal, &exit_with_exception); ++ // Otherwise use return value as new stack pointer. ++ __ mov(backtrack_stackpointer(), eax); ++ // Restore saved registers and continue. ++ __ pop(edi); ++ __ pop(esi); ++ SafeReturn(); ++ } ++ ++ if (exit_with_exception.is_linked()) { ++ // If any of the code above needed to exit with an exception. ++ __ bind(&exit_with_exception); ++ // Exit with Result EXCEPTION(-1) to signal thrown exception. ++ __ mov(eax, EXCEPTION); ++ __ jmp(&return_eax); ++ } ++ ++ CodeDesc code_desc; ++ masm_->GetCode(&code_desc); ++ Handle code = ++ isolate()->factory()->NewCode(code_desc, ++ Code::ComputeFlags(Code::REGEXP), ++ masm_->CodeObject()); ++ PROFILE(masm_->isolate(), ++ RegExpCodeCreateEvent(AbstractCode::cast(*code), *source)); ++ return Handle::cast(code); ++} ++ ++ ++void RegExpMacroAssemblerX87::GoTo(Label* to) { ++ BranchOrBacktrack(no_condition, to); ++} ++ ++ ++void RegExpMacroAssemblerX87::IfRegisterGE(int reg, ++ int comparand, ++ Label* if_ge) { ++ __ cmp(register_location(reg), Immediate(comparand)); ++ BranchOrBacktrack(greater_equal, if_ge); ++} ++ ++ ++void RegExpMacroAssemblerX87::IfRegisterLT(int reg, ++ int comparand, ++ Label* if_lt) { ++ __ cmp(register_location(reg), Immediate(comparand)); ++ BranchOrBacktrack(less, if_lt); ++} ++ ++ ++void RegExpMacroAssemblerX87::IfRegisterEqPos(int reg, ++ Label* if_eq) { ++ __ cmp(edi, register_location(reg)); ++ BranchOrBacktrack(equal, if_eq); ++} ++ ++ ++RegExpMacroAssembler::IrregexpImplementation ++ RegExpMacroAssemblerX87::Implementation() { ++ return kX87Implementation; ++} ++ ++ ++void RegExpMacroAssemblerX87::LoadCurrentCharacter(int cp_offset, ++ Label* on_end_of_input, ++ bool check_bounds, ++ int characters) { ++ DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works) ++ if (check_bounds) { ++ if (cp_offset >= 0) { ++ CheckPosition(cp_offset + characters - 1, on_end_of_input); ++ } else { ++ CheckPosition(cp_offset, on_end_of_input); ++ } ++ } ++ LoadCurrentCharacterUnchecked(cp_offset, characters); ++} ++ ++ ++void RegExpMacroAssemblerX87::PopCurrentPosition() { ++ Pop(edi); ++} ++ ++ ++void RegExpMacroAssemblerX87::PopRegister(int register_index) { ++ Pop(eax); ++ __ mov(register_location(register_index), eax); ++} ++ ++ ++void RegExpMacroAssemblerX87::PushBacktrack(Label* label) { ++ Push(Immediate::CodeRelativeOffset(label)); ++ CheckStackLimit(); ++} ++ ++ ++void RegExpMacroAssemblerX87::PushCurrentPosition() { ++ Push(edi); ++} ++ ++ ++void RegExpMacroAssemblerX87::PushRegister(int register_index, ++ StackCheckFlag check_stack_limit) { ++ __ mov(eax, register_location(register_index)); ++ Push(eax); ++ if (check_stack_limit) CheckStackLimit(); ++} ++ ++ ++void RegExpMacroAssemblerX87::ReadCurrentPositionFromRegister(int reg) { ++ __ mov(edi, register_location(reg)); ++} ++ ++ ++void RegExpMacroAssemblerX87::ReadStackPointerFromRegister(int reg) { ++ __ mov(backtrack_stackpointer(), register_location(reg)); ++ __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); ++} ++ ++void RegExpMacroAssemblerX87::SetCurrentPositionFromEnd(int by) { ++ Label after_position; ++ __ cmp(edi, -by * char_size()); ++ __ j(greater_equal, &after_position, Label::kNear); ++ __ mov(edi, -by * char_size()); ++ // On RegExp code entry (where this operation is used), the character before ++ // the current position is expected to be already loaded. ++ // We have advanced the position, so it's safe to read backwards. ++ LoadCurrentCharacterUnchecked(-1, 1); ++ __ bind(&after_position); ++} ++ ++ ++void RegExpMacroAssemblerX87::SetRegister(int register_index, int to) { ++ DCHECK(register_index >= num_saved_registers_); // Reserved for positions! ++ __ mov(register_location(register_index), Immediate(to)); ++} ++ ++ ++bool RegExpMacroAssemblerX87::Succeed() { ++ __ jmp(&success_label_); ++ return global(); ++} ++ ++ ++void RegExpMacroAssemblerX87::WriteCurrentPositionToRegister(int reg, ++ int cp_offset) { ++ if (cp_offset == 0) { ++ __ mov(register_location(reg), edi); ++ } else { ++ __ lea(eax, Operand(edi, cp_offset * char_size())); ++ __ mov(register_location(reg), eax); ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::ClearRegisters(int reg_from, int reg_to) { ++ DCHECK(reg_from <= reg_to); ++ __ mov(eax, Operand(ebp, kStringStartMinusOne)); ++ for (int reg = reg_from; reg <= reg_to; reg++) { ++ __ mov(register_location(reg), eax); ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::WriteStackPointerToRegister(int reg) { ++ __ mov(eax, backtrack_stackpointer()); ++ __ sub(eax, Operand(ebp, kStackHighEnd)); ++ __ mov(register_location(reg), eax); ++} ++ ++ ++// Private methods: ++ ++void RegExpMacroAssemblerX87::CallCheckStackGuardState(Register scratch) { ++ static const int num_arguments = 3; ++ __ PrepareCallCFunction(num_arguments, scratch); ++ // RegExp code frame pointer. ++ __ mov(Operand(esp, 2 * kPointerSize), ebp); ++ // Code* of self. ++ __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject())); ++ // Next address on the stack (will be address of return address). ++ __ lea(eax, Operand(esp, -kPointerSize)); ++ __ mov(Operand(esp, 0 * kPointerSize), eax); ++ ExternalReference check_stack_guard = ++ ExternalReference::re_check_stack_guard_state(isolate()); ++ __ CallCFunction(check_stack_guard, num_arguments); ++} ++ ++ ++// Helper function for reading a value out of a stack frame. ++template ++static T& frame_entry(Address re_frame, int frame_offset) { ++ return reinterpret_cast(Memory::int32_at(re_frame + frame_offset)); ++} ++ ++ ++template ++static T* frame_entry_address(Address re_frame, int frame_offset) { ++ return reinterpret_cast(re_frame + frame_offset); ++} ++ ++ ++int RegExpMacroAssemblerX87::CheckStackGuardState(Address* return_address, ++ Code* re_code, ++ Address re_frame) { ++ return NativeRegExpMacroAssembler::CheckStackGuardState( ++ frame_entry(re_frame, kIsolate), ++ frame_entry(re_frame, kStartIndex), ++ frame_entry(re_frame, kDirectCall) == 1, return_address, re_code, ++ frame_entry_address(re_frame, kInputString), ++ frame_entry_address(re_frame, kInputStart), ++ frame_entry_address(re_frame, kInputEnd)); ++} ++ ++ ++Operand RegExpMacroAssemblerX87::register_location(int register_index) { ++ DCHECK(register_index < (1<<30)); ++ if (num_registers_ <= register_index) { ++ num_registers_ = register_index + 1; ++ } ++ return Operand(ebp, kRegisterZero - register_index * kPointerSize); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckPosition(int cp_offset, ++ Label* on_outside_input) { ++ if (cp_offset >= 0) { ++ __ cmp(edi, -cp_offset * char_size()); ++ BranchOrBacktrack(greater_equal, on_outside_input); ++ } else { ++ __ lea(eax, Operand(edi, cp_offset * char_size())); ++ __ cmp(eax, Operand(ebp, kStringStartMinusOne)); ++ BranchOrBacktrack(less_equal, on_outside_input); ++ } ++} ++ ++ ++void RegExpMacroAssemblerX87::BranchOrBacktrack(Condition condition, ++ Label* to) { ++ if (condition < 0) { // No condition ++ if (to == NULL) { ++ Backtrack(); ++ return; ++ } ++ __ jmp(to); ++ return; ++ } ++ if (to == NULL) { ++ __ j(condition, &backtrack_label_); ++ return; ++ } ++ __ j(condition, to); ++} ++ ++ ++void RegExpMacroAssemblerX87::SafeCall(Label* to) { ++ Label return_to; ++ __ push(Immediate::CodeRelativeOffset(&return_to)); ++ __ jmp(to); ++ __ bind(&return_to); ++} ++ ++ ++void RegExpMacroAssemblerX87::SafeReturn() { ++ __ pop(ebx); ++ __ add(ebx, Immediate(masm_->CodeObject())); ++ __ jmp(ebx); ++} ++ ++ ++void RegExpMacroAssemblerX87::SafeCallTarget(Label* name) { ++ __ bind(name); ++} ++ ++ ++void RegExpMacroAssemblerX87::Push(Register source) { ++ DCHECK(!source.is(backtrack_stackpointer())); ++ // Notice: This updates flags, unlike normal Push. ++ __ sub(backtrack_stackpointer(), Immediate(kPointerSize)); ++ __ mov(Operand(backtrack_stackpointer(), 0), source); ++} ++ ++ ++void RegExpMacroAssemblerX87::Push(Immediate value) { ++ // Notice: This updates flags, unlike normal Push. ++ __ sub(backtrack_stackpointer(), Immediate(kPointerSize)); ++ __ mov(Operand(backtrack_stackpointer(), 0), value); ++} ++ ++ ++void RegExpMacroAssemblerX87::Pop(Register target) { ++ DCHECK(!target.is(backtrack_stackpointer())); ++ __ mov(target, Operand(backtrack_stackpointer(), 0)); ++ // Notice: This updates flags, unlike normal Pop. ++ __ add(backtrack_stackpointer(), Immediate(kPointerSize)); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckPreemption() { ++ // Check for preemption. ++ Label no_preempt; ++ ExternalReference stack_limit = ++ ExternalReference::address_of_stack_limit(isolate()); ++ __ cmp(esp, Operand::StaticVariable(stack_limit)); ++ __ j(above, &no_preempt); ++ ++ SafeCall(&check_preempt_label_); ++ ++ __ bind(&no_preempt); ++} ++ ++ ++void RegExpMacroAssemblerX87::CheckStackLimit() { ++ Label no_stack_overflow; ++ ExternalReference stack_limit = ++ ExternalReference::address_of_regexp_stack_limit(isolate()); ++ __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit)); ++ __ j(above, &no_stack_overflow); ++ ++ SafeCall(&stack_overflow_label_); ++ ++ __ bind(&no_stack_overflow); ++} ++ ++ ++void RegExpMacroAssemblerX87::LoadCurrentCharacterUnchecked(int cp_offset, ++ int characters) { ++ if (mode_ == LATIN1) { ++ if (characters == 4) { ++ __ mov(current_character(), Operand(esi, edi, times_1, cp_offset)); ++ } else if (characters == 2) { ++ __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset)); ++ } else { ++ DCHECK(characters == 1); ++ __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset)); ++ } ++ } else { ++ DCHECK(mode_ == UC16); ++ if (characters == 2) { ++ __ mov(current_character(), ++ Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); ++ } else { ++ DCHECK(characters == 1); ++ __ movzx_w(current_character(), ++ Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); ++ } ++ } ++} ++ ++ ++#undef __ ++ ++#endif // V8_INTERPRETED_REGEXP ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/regexp/x87/regexp-macro-assembler-x87.h 2017-12-25 17:42:57.218465603 +0100 +@@ -0,0 +1,204 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_REGEXP_X87_REGEXP_MACRO_ASSEMBLER_X87_H_ ++#define V8_REGEXP_X87_REGEXP_MACRO_ASSEMBLER_X87_H_ ++ ++#include "src/macro-assembler.h" ++#include "src/regexp/regexp-macro-assembler.h" ++#include "src/x87/assembler-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++#ifndef V8_INTERPRETED_REGEXP ++class RegExpMacroAssemblerX87: public NativeRegExpMacroAssembler { ++ public: ++ RegExpMacroAssemblerX87(Isolate* isolate, Zone* zone, Mode mode, ++ int registers_to_save); ++ virtual ~RegExpMacroAssemblerX87(); ++ virtual int stack_limit_slack(); ++ virtual void AdvanceCurrentPosition(int by); ++ virtual void AdvanceRegister(int reg, int by); ++ virtual void Backtrack(); ++ virtual void Bind(Label* label); ++ virtual void CheckAtStart(Label* on_at_start); ++ virtual void CheckCharacter(uint32_t c, Label* on_equal); ++ virtual void CheckCharacterAfterAnd(uint32_t c, ++ uint32_t mask, ++ Label* on_equal); ++ virtual void CheckCharacterGT(uc16 limit, Label* on_greater); ++ virtual void CheckCharacterLT(uc16 limit, Label* on_less); ++ // A "greedy loop" is a loop that is both greedy and with a simple ++ // body. It has a particularly simple implementation. ++ virtual void CheckGreedyLoop(Label* on_tos_equals_current_position); ++ virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start); ++ virtual void CheckNotBackReference(int start_reg, bool read_backward, ++ Label* on_no_match); ++ virtual void CheckNotBackReferenceIgnoreCase(int start_reg, ++ bool read_backward, bool unicode, ++ Label* on_no_match); ++ virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal); ++ virtual void CheckNotCharacterAfterAnd(uint32_t c, ++ uint32_t mask, ++ Label* on_not_equal); ++ virtual void CheckNotCharacterAfterMinusAnd(uc16 c, ++ uc16 minus, ++ uc16 mask, ++ Label* on_not_equal); ++ virtual void CheckCharacterInRange(uc16 from, ++ uc16 to, ++ Label* on_in_range); ++ virtual void CheckCharacterNotInRange(uc16 from, ++ uc16 to, ++ Label* on_not_in_range); ++ virtual void CheckBitInTable(Handle table, Label* on_bit_set); ++ ++ // Checks whether the given offset from the current position is before ++ // the end of the string. ++ virtual void CheckPosition(int cp_offset, Label* on_outside_input); ++ virtual bool CheckSpecialCharacterClass(uc16 type, Label* on_no_match); ++ virtual void Fail(); ++ virtual Handle GetCode(Handle source); ++ virtual void GoTo(Label* label); ++ virtual void IfRegisterGE(int reg, int comparand, Label* if_ge); ++ virtual void IfRegisterLT(int reg, int comparand, Label* if_lt); ++ virtual void IfRegisterEqPos(int reg, Label* if_eq); ++ virtual IrregexpImplementation Implementation(); ++ virtual void LoadCurrentCharacter(int cp_offset, ++ Label* on_end_of_input, ++ bool check_bounds = true, ++ int characters = 1); ++ virtual void PopCurrentPosition(); ++ virtual void PopRegister(int register_index); ++ virtual void PushBacktrack(Label* label); ++ virtual void PushCurrentPosition(); ++ virtual void PushRegister(int register_index, ++ StackCheckFlag check_stack_limit); ++ virtual void ReadCurrentPositionFromRegister(int reg); ++ virtual void ReadStackPointerFromRegister(int reg); ++ virtual void SetCurrentPositionFromEnd(int by); ++ virtual void SetRegister(int register_index, int to); ++ virtual bool Succeed(); ++ virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); ++ virtual void ClearRegisters(int reg_from, int reg_to); ++ virtual void WriteStackPointerToRegister(int reg); ++ ++ // Called from RegExp if the stack-guard is triggered. ++ // If the code object is relocated, the return address is fixed before ++ // returning. ++ static int CheckStackGuardState(Address* return_address, ++ Code* re_code, ++ Address re_frame); ++ ++ private: ++ // Offsets from ebp of function parameters and stored registers. ++ static const int kFramePointer = 0; ++ // Above the frame pointer - function parameters and return address. ++ static const int kReturn_eip = kFramePointer + kPointerSize; ++ static const int kFrameAlign = kReturn_eip + kPointerSize; ++ // Parameters. ++ static const int kInputString = kFrameAlign; ++ static const int kStartIndex = kInputString + kPointerSize; ++ static const int kInputStart = kStartIndex + kPointerSize; ++ static const int kInputEnd = kInputStart + kPointerSize; ++ static const int kRegisterOutput = kInputEnd + kPointerSize; ++ // For the case of global regular expression, we have room to store at least ++ // one set of capture results. For the case of non-global regexp, we ignore ++ // this value. ++ static const int kNumOutputRegisters = kRegisterOutput + kPointerSize; ++ static const int kStackHighEnd = kNumOutputRegisters + kPointerSize; ++ static const int kDirectCall = kStackHighEnd + kPointerSize; ++ static const int kIsolate = kDirectCall + kPointerSize; ++ // Below the frame pointer - local stack variables. ++ // When adding local variables remember to push space for them in ++ // the frame in GetCode. ++ static const int kBackup_esi = kFramePointer - kPointerSize; ++ static const int kBackup_edi = kBackup_esi - kPointerSize; ++ static const int kBackup_ebx = kBackup_edi - kPointerSize; ++ static const int kSuccessfulCaptures = kBackup_ebx - kPointerSize; ++ static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; ++ // First register address. Following registers are below it on the stack. ++ static const int kRegisterZero = kStringStartMinusOne - kPointerSize; ++ ++ // Initial size of code buffer. ++ static const size_t kRegExpCodeSize = 1024; ++ ++ // Load a number of characters at the given offset from the ++ // current position, into the current-character register. ++ void LoadCurrentCharacterUnchecked(int cp_offset, int character_count); ++ ++ // Check whether preemption has been requested. ++ void CheckPreemption(); ++ ++ // Check whether we are exceeding the stack limit on the backtrack stack. ++ void CheckStackLimit(); ++ ++ // Generate a call to CheckStackGuardState. ++ void CallCheckStackGuardState(Register scratch); ++ ++ // The ebp-relative location of a regexp register. ++ Operand register_location(int register_index); ++ ++ // The register containing the current character after LoadCurrentCharacter. ++ inline Register current_character() { return edx; } ++ ++ // The register containing the backtrack stack top. Provides a meaningful ++ // name to the register. ++ inline Register backtrack_stackpointer() { return ecx; } ++ ++ // Byte size of chars in the string to match (decided by the Mode argument) ++ inline int char_size() { return static_cast(mode_); } ++ ++ // Equivalent to a conditional branch to the label, unless the label ++ // is NULL, in which case it is a conditional Backtrack. ++ void BranchOrBacktrack(Condition condition, Label* to); ++ ++ // Call and return internally in the generated code in a way that ++ // is GC-safe (i.e., doesn't leave absolute code addresses on the stack) ++ inline void SafeCall(Label* to); ++ inline void SafeReturn(); ++ inline void SafeCallTarget(Label* name); ++ ++ // Pushes the value of a register on the backtrack stack. Decrements the ++ // stack pointer (ecx) by a word size and stores the register's value there. ++ inline void Push(Register source); ++ ++ // Pushes a value on the backtrack stack. Decrements the stack pointer (ecx) ++ // by a word size and stores the value there. ++ inline void Push(Immediate value); ++ ++ // Pops a value from the backtrack stack. Reads the word at the stack pointer ++ // (ecx) and increments it by a word size. ++ inline void Pop(Register target); ++ ++ Isolate* isolate() const { return masm_->isolate(); } ++ ++ MacroAssembler* masm_; ++ ++ // Which mode to generate code for (LATIN1 or UC16). ++ Mode mode_; ++ ++ // One greater than maximal register index actually used. ++ int num_registers_; ++ ++ // Number of registers to output at the end (the saved registers ++ // are always 0..num_saved_registers_-1) ++ int num_saved_registers_; ++ ++ // Labels used internally. ++ Label entry_label_; ++ Label start_label_; ++ Label success_label_; ++ Label backtrack_label_; ++ Label exit_label_; ++ Label check_preempt_label_; ++ Label stack_overflow_label_; ++}; ++#endif // V8_INTERPRETED_REGEXP ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_REGEXP_X87_REGEXP_MACRO_ASSEMBLER_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/register-configuration.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/register-configuration.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/register-configuration.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/register-configuration.cc 2017-12-25 17:42:57.218465603 +0100 +@@ -74,6 +74,9 @@ + #if V8_TARGET_ARCH_IA32 + kMaxAllocatableGeneralRegisterCount, + kMaxAllocatableDoubleRegisterCount, ++#elif V8_TARGET_ARCH_X87 ++ kMaxAllocatableGeneralRegisterCount, ++ compiler == TURBOFAN ? 1 : kMaxAllocatableDoubleRegisterCount, + #elif V8_TARGET_ARCH_X64 + kMaxAllocatableGeneralRegisterCount, + kMaxAllocatableDoubleRegisterCount, +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/register-configuration.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/register-configuration.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/register-configuration.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/register-configuration.h 2017-12-25 17:42:57.218465603 +0100 +@@ -28,7 +28,8 @@ + static const int kMaxFPRegisters = 32; + + // Default RegisterConfigurations for the target architecture. +- // TODO(mstarzinger): Crankshaft is gone. ++ // TODO(X87): This distinction in RegisterConfigurations is temporary ++ // until x87 TF supports all of the registers that Crankshaft does. + static const RegisterConfiguration* Crankshaft(); + static const RegisterConfiguration* Turbofan(); + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/simulator.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/simulator.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/simulator.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/simulator.h 2017-12-25 17:42:57.218465603 +0100 +@@ -21,6 +21,8 @@ + #include "src/mips64/simulator-mips64.h" + #elif V8_TARGET_ARCH_S390 + #include "src/s390/simulator-s390.h" ++#elif V8_TARGET_ARCH_X87 ++#include "src/x87/simulator-x87.h" + #else + #error Unsupported target architecture. + #endif +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/strtod.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/strtod.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/strtod.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/strtod.cc 2017-12-25 17:42:57.218465603 +0100 +@@ -154,7 +154,8 @@ + static bool DoubleStrtod(Vector trimmed, + int exponent, + double* result) { +-#if (V8_TARGET_ARCH_IA32 || defined(USE_SIMULATOR)) && !defined(_MSC_VER) ++#if (V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 || defined(USE_SIMULATOR)) && \ ++ !defined(_MSC_VER) + // On x86 the floating-point stack can be 64 or 80 bits wide. If it is + // 80 bits wide (as is the case on Linux) then double-rounding occurs and the + // result is not accurate. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/utils.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/utils.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/utils.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/utils.cc 2017-12-25 17:42:57.218465603 +0100 +@@ -356,7 +356,8 @@ + } + } + +-#if V8_TARGET_ARCH_IA32 ++ ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + static void MemMoveWrapper(void* dest, const void* src, size_t size) { + memmove(dest, src, size); + } +@@ -410,7 +411,7 @@ + void init_memcopy_functions(Isolate* isolate) { + if (g_memcopy_functions_initialized) return; + g_memcopy_functions_initialized = true; +-#if V8_TARGET_ARCH_IA32 ++#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 + MemMoveFunction generated_memmove = CreateMemMoveFunction(isolate); + if (generated_memmove != NULL) { + memmove_function = generated_memmove; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/utils.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/utils.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/utils.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/utils.h 2017-12-25 17:42:57.218465603 +0100 +@@ -431,7 +431,7 @@ + // Initializes the codegen support that depends on CPU features. + void init_memcopy_functions(Isolate* isolate); + +-#if defined(V8_TARGET_ARCH_IA32) ++#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X87) + // Limit below which the extra overhead of the MemCopy function is likely + // to outweigh the benefits of faster copying. + const int kMinComplexMemCopy = 64; +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/v8.gyp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/v8.gyp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/v8.gyp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/v8.gyp 2017-12-25 17:42:57.218465603 +0100 +@@ -279,6 +279,11 @@ + 'builtins/s390/builtins-s390.cc', + ], + }], ++ ['v8_target_arch=="x87"', { ++ 'sources': [ ### gcmole(arch:x87) ### ++ 'builtins/x87/builtins-x87.cc', ++ ], ++ }], + ['v8_enable_i18n_support==0', { + 'sources!': [ + 'builtins/builtins-intl-gen.cc', +@@ -1587,6 +1592,38 @@ + 'regexp/ia32/regexp-macro-assembler-ia32.h', + ], + }], ++ ['v8_target_arch=="x87"', { ++ 'sources': [ ### gcmole(arch:x87) ### ++ 'x87/assembler-x87-inl.h', ++ 'x87/assembler-x87.cc', ++ 'x87/assembler-x87.h', ++ 'x87/code-stubs-x87.cc', ++ 'x87/code-stubs-x87.h', ++ 'x87/codegen-x87.cc', ++ 'x87/codegen-x87.h', ++ 'x87/cpu-x87.cc', ++ 'x87/deoptimizer-x87.cc', ++ 'x87/disasm-x87.cc', ++ 'x87/frames-x87.cc', ++ 'x87/frames-x87.h', ++ 'x87/interface-descriptors-x87.cc', ++ 'x87/macro-assembler-x87.cc', ++ 'x87/macro-assembler-x87.h', ++ 'x87/simulator-x87.cc', ++ 'x87/simulator-x87.h', ++ 'compiler/x87/code-generator-x87.cc', ++ 'compiler/x87/instruction-codes-x87.h', ++ 'compiler/x87/instruction-scheduler-x87.cc', ++ 'compiler/x87/instruction-selector-x87.cc', ++ 'debug/x87/debug-x87.cc', ++ 'full-codegen/x87/full-codegen-x87.cc', ++ 'ic/x87/access-compiler-x87.cc', ++ 'ic/x87/handler-compiler-x87.cc', ++ 'ic/x87/ic-x87.cc', ++ 'regexp/x87/regexp-macro-assembler-x87.cc', ++ 'regexp/x87/regexp-macro-assembler-x87.h', ++ ], ++ }], + ['v8_target_arch=="mips" or v8_target_arch=="mipsel"', { + 'sources': [ ### gcmole(arch:mipsel) ### + 'mips/assembler-mips.cc', +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87.cc 2017-12-25 17:42:57.219465588 +0100 +@@ -0,0 +1,2217 @@ ++// Copyright (c) 1994-2006 Sun Microsystems Inc. ++// All Rights Reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// - Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// ++// - Redistribution in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the ++// distribution. ++// ++// - Neither the name of Sun Microsystems or the names of contributors may ++// be used to endorse or promote products derived from this software without ++// specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++// OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++// The original source code covered by the above license above has been modified ++// significantly by Google Inc. ++// Copyright 2012 the V8 project authors. All rights reserved. ++ ++#include "src/x87/assembler-x87.h" ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/base/bits.h" ++#include "src/base/cpu.h" ++#include "src/disassembler.h" ++#include "src/macro-assembler.h" ++#include "src/v8.h" ++ ++namespace v8 { ++namespace internal { ++ ++// ----------------------------------------------------------------------------- ++// Implementation of CpuFeatures ++ ++void CpuFeatures::ProbeImpl(bool cross_compile) { ++ base::CPU cpu; ++ ++ // Only use statically determined features for cross compile (snapshot). ++ if (cross_compile) return; ++} ++ ++ ++void CpuFeatures::PrintTarget() { } ++void CpuFeatures::PrintFeatures() { } ++ ++ ++// ----------------------------------------------------------------------------- ++// Implementation of Displacement ++ ++void Displacement::init(Label* L, Type type) { ++ DCHECK(!L->is_bound()); ++ int next = 0; ++ if (L->is_linked()) { ++ next = L->pos(); ++ DCHECK(next > 0); // Displacements must be at positions > 0 ++ } ++ // Ensure that we _never_ overflow the next field. ++ DCHECK(NextField::is_valid(Assembler::kMaximalBufferSize)); ++ data_ = NextField::encode(next) | TypeField::encode(type); ++} ++ ++ ++// ----------------------------------------------------------------------------- ++// Implementation of RelocInfo ++ ++ ++const int RelocInfo::kApplyMask = ++ RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY | ++ 1 << RelocInfo::INTERNAL_REFERENCE | 1 << RelocInfo::CODE_AGE_SEQUENCE | ++ RelocInfo::kDebugBreakSlotMask; ++ ++ ++bool RelocInfo::IsCodedSpecially() { ++ // The deserializer needs to know whether a pointer is specially coded. Being ++ // specially coded on IA32 means that it is a relative address, as used by ++ // branch instructions. These are also the ones that need changing when a ++ // code object moves. ++ return (1 << rmode_) & kApplyMask; ++} ++ ++ ++bool RelocInfo::IsInConstantPool() { ++ return false; ++} ++ ++Address RelocInfo::wasm_memory_reference() { ++ DCHECK(IsWasmMemoryReference(rmode_)); ++ return Memory::Address_at(pc_); ++} ++ ++Address RelocInfo::wasm_global_reference() { ++ DCHECK(IsWasmGlobalReference(rmode_)); ++ return Memory::Address_at(pc_); ++} ++ ++uint32_t RelocInfo::wasm_memory_size_reference() { ++ DCHECK(IsWasmMemorySizeReference(rmode_)); ++ return Memory::uint32_at(pc_); ++} ++ ++uint32_t RelocInfo::wasm_function_table_size_reference() { ++ DCHECK(IsWasmFunctionTableSizeReference(rmode_)); ++ return Memory::uint32_at(pc_); ++} ++ ++void RelocInfo::unchecked_update_wasm_memory_reference( ++ Isolate* isolate, Address address, ICacheFlushMode icache_flush_mode) { ++ Memory::Address_at(pc_) = address; ++ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { ++ Assembler::FlushICache(isolate, pc_, sizeof(Address)); ++ } ++} ++ ++void RelocInfo::unchecked_update_wasm_size(Isolate* isolate, uint32_t size, ++ ICacheFlushMode icache_flush_mode) { ++ Memory::uint32_at(pc_) = size; ++ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { ++ Assembler::FlushICache(isolate, pc_, sizeof(uint32_t)); ++ } ++} ++ ++// ----------------------------------------------------------------------------- ++// Implementation of Operand ++ ++Operand::Operand(Register base, int32_t disp, RelocInfo::Mode rmode) { ++ // [base + disp/r] ++ if (disp == 0 && RelocInfo::IsNone(rmode) && !base.is(ebp)) { ++ // [base] ++ set_modrm(0, base); ++ if (base.is(esp)) set_sib(times_1, esp, base); ++ } else if (is_int8(disp) && RelocInfo::IsNone(rmode)) { ++ // [base + disp8] ++ set_modrm(1, base); ++ if (base.is(esp)) set_sib(times_1, esp, base); ++ set_disp8(disp); ++ } else { ++ // [base + disp/r] ++ set_modrm(2, base); ++ if (base.is(esp)) set_sib(times_1, esp, base); ++ set_dispr(disp, rmode); ++ } ++} ++ ++ ++Operand::Operand(Register base, ++ Register index, ++ ScaleFactor scale, ++ int32_t disp, ++ RelocInfo::Mode rmode) { ++ DCHECK(!index.is(esp)); // illegal addressing mode ++ // [base + index*scale + disp/r] ++ if (disp == 0 && RelocInfo::IsNone(rmode) && !base.is(ebp)) { ++ // [base + index*scale] ++ set_modrm(0, esp); ++ set_sib(scale, index, base); ++ } else if (is_int8(disp) && RelocInfo::IsNone(rmode)) { ++ // [base + index*scale + disp8] ++ set_modrm(1, esp); ++ set_sib(scale, index, base); ++ set_disp8(disp); ++ } else { ++ // [base + index*scale + disp/r] ++ set_modrm(2, esp); ++ set_sib(scale, index, base); ++ set_dispr(disp, rmode); ++ } ++} ++ ++ ++Operand::Operand(Register index, ++ ScaleFactor scale, ++ int32_t disp, ++ RelocInfo::Mode rmode) { ++ DCHECK(!index.is(esp)); // illegal addressing mode ++ // [index*scale + disp/r] ++ set_modrm(0, esp); ++ set_sib(scale, index, ebp); ++ set_dispr(disp, rmode); ++} ++ ++ ++bool Operand::is_reg(Register reg) const { ++ return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. ++ && ((buf_[0] & 0x07) == reg.code()); // register codes match. ++} ++ ++ ++bool Operand::is_reg_only() const { ++ return (buf_[0] & 0xF8) == 0xC0; // Addressing mode is register only. ++} ++ ++ ++Register Operand::reg() const { ++ DCHECK(is_reg_only()); ++ return Register::from_code(buf_[0] & 0x07); ++} ++ ++ ++// ----------------------------------------------------------------------------- ++// Implementation of Assembler. ++ ++// Emit a single byte. Must always be inlined. ++#define EMIT(x) \ ++ *pc_++ = (x) ++ ++Assembler::Assembler(IsolateData isolate_data, void* buffer, int buffer_size) ++ : AssemblerBase(isolate_data, buffer, buffer_size) { ++// Clear the buffer in debug mode unless it was provided by the ++// caller in which case we can't be sure it's okay to overwrite ++// existing code in it; see CodePatcher::CodePatcher(...). ++#ifdef DEBUG ++ if (own_buffer_) { ++ memset(buffer_, 0xCC, buffer_size_); // int3 ++ } ++#endif ++ ++ reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); ++} ++ ++ ++void Assembler::GetCode(CodeDesc* desc) { ++ // Finalize code (at this point overflow() may be true, but the gap ensures ++ // that we are still not overlapping instructions and relocation info). ++ DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap. ++ // Set up code descriptor. ++ desc->buffer = buffer_; ++ desc->buffer_size = buffer_size_; ++ desc->instr_size = pc_offset(); ++ desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); ++ desc->origin = this; ++ desc->constant_pool_size = 0; ++ desc->unwinding_info_size = 0; ++ desc->unwinding_info = nullptr; ++} ++ ++ ++void Assembler::Align(int m) { ++ DCHECK(base::bits::IsPowerOfTwo(m)); ++ int mask = m - 1; ++ int addr = pc_offset(); ++ Nop((m - (addr & mask)) & mask); ++} ++ ++ ++bool Assembler::IsNop(Address addr) { ++ Address a = addr; ++ while (*a == 0x66) a++; ++ if (*a == 0x90) return true; ++ if (a[0] == 0xf && a[1] == 0x1f) return true; ++ return false; ++} ++ ++ ++void Assembler::Nop(int bytes) { ++ EnsureSpace ensure_space(this); ++ ++ // Older CPUs that do not support SSE2 may not support multibyte NOP ++ // instructions. ++ for (; bytes > 0; bytes--) { ++ EMIT(0x90); ++ } ++ return; ++} ++ ++ ++void Assembler::CodeTargetAlign() { ++ Align(16); // Preferred alignment of jump targets on ia32. ++} ++ ++ ++void Assembler::cpuid() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xA2); ++} ++ ++ ++void Assembler::pushad() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x60); ++} ++ ++ ++void Assembler::popad() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x61); ++} ++ ++ ++void Assembler::pushfd() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x9C); ++} ++ ++ ++void Assembler::popfd() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x9D); ++} ++ ++ ++void Assembler::push(const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ if (x.is_int8()) { ++ EMIT(0x6a); ++ EMIT(x.x_); ++ } else { ++ EMIT(0x68); ++ emit(x); ++ } ++} ++ ++ ++void Assembler::push_imm32(int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x68); ++ emit(imm32); ++} ++ ++ ++void Assembler::push(Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x50 | src.code()); ++} ++ ++ ++void Assembler::push(const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFF); ++ emit_operand(esi, src); ++} ++ ++ ++void Assembler::pop(Register dst) { ++ DCHECK(reloc_info_writer.last_pc() != NULL); ++ EnsureSpace ensure_space(this); ++ EMIT(0x58 | dst.code()); ++} ++ ++ ++void Assembler::pop(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x8F); ++ emit_operand(eax, dst); ++} ++ ++ ++void Assembler::enter(const Immediate& size) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC8); ++ emit_w(size); ++ EMIT(0); ++} ++ ++ ++void Assembler::leave() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC9); ++} ++ ++ ++void Assembler::mov_b(Register dst, const Operand& src) { ++ CHECK(dst.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x8A); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::mov_b(const Operand& dst, const Immediate& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC6); ++ emit_operand(eax, dst); ++ EMIT(static_cast(src.x_)); ++} ++ ++ ++void Assembler::mov_b(const Operand& dst, int8_t imm8) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC6); ++ emit_operand(eax, dst); ++ EMIT(imm8); ++} ++ ++ ++void Assembler::mov_b(const Operand& dst, Register src) { ++ CHECK(src.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x88); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::mov_w(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x8B); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::mov_w(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x89); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::mov_w(const Operand& dst, int16_t imm16) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0xC7); ++ emit_operand(eax, dst); ++ EMIT(static_cast(imm16 & 0xff)); ++ EMIT(static_cast(imm16 >> 8)); ++} ++ ++ ++void Assembler::mov_w(const Operand& dst, const Immediate& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0xC7); ++ emit_operand(eax, dst); ++ EMIT(static_cast(src.x_ & 0xff)); ++ EMIT(static_cast(src.x_ >> 8)); ++} ++ ++ ++void Assembler::mov(Register dst, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xB8 | dst.code()); ++ emit(imm32); ++} ++ ++ ++void Assembler::mov(Register dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xB8 | dst.code()); ++ emit(x); ++} ++ ++ ++void Assembler::mov(Register dst, Handle handle) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xB8 | dst.code()); ++ emit(handle); ++} ++ ++ ++void Assembler::mov(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x8B); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::mov(Register dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x89); ++ EMIT(0xC0 | src.code() << 3 | dst.code()); ++} ++ ++ ++void Assembler::mov(const Operand& dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC7); ++ emit_operand(eax, dst); ++ emit(x); ++} ++ ++ ++void Assembler::mov(const Operand& dst, Handle handle) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xC7); ++ emit_operand(eax, dst); ++ emit(handle); ++} ++ ++ ++void Assembler::mov(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x89); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::movsx_b(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xBE); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::movsx_w(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xBF); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::movzx_b(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xB6); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::movzx_w(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xB7); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::cld() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFC); ++} ++ ++ ++void Assembler::rep_movs() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF3); ++ EMIT(0xA5); ++} ++ ++ ++void Assembler::rep_stos() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF3); ++ EMIT(0xAB); ++} ++ ++ ++void Assembler::stos() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xAB); ++} ++ ++ ++void Assembler::xchg(Register dst, Register src) { ++ EnsureSpace ensure_space(this); ++ if (src.is(eax) || dst.is(eax)) { // Single-byte encoding. ++ EMIT(0x90 | (src.is(eax) ? dst.code() : src.code())); ++ } else { ++ EMIT(0x87); ++ EMIT(0xC0 | src.code() << 3 | dst.code()); ++ } ++} ++ ++ ++void Assembler::xchg(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x87); ++ emit_operand(dst, src); ++} ++ ++void Assembler::xchg_b(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x86); ++ emit_operand(reg, op); ++} ++ ++void Assembler::xchg_w(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x87); ++ emit_operand(reg, op); ++} ++ ++void Assembler::lock() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF0); ++} ++ ++void Assembler::cmpxchg(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xB1); ++ emit_operand(src, dst); ++} ++ ++void Assembler::cmpxchg_b(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xB0); ++ emit_operand(src, dst); ++} ++ ++void Assembler::cmpxchg_w(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x0F); ++ EMIT(0xB1); ++ emit_operand(src, dst); ++} ++ ++void Assembler::adc(Register dst, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ emit_arith(2, Operand(dst), Immediate(imm32)); ++} ++ ++ ++void Assembler::adc(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x13); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::add(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x03); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::add(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x01); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::add(const Operand& dst, const Immediate& x) { ++ DCHECK(reloc_info_writer.last_pc() != NULL); ++ EnsureSpace ensure_space(this); ++ emit_arith(0, dst, x); ++} ++ ++ ++void Assembler::and_(Register dst, int32_t imm32) { ++ and_(dst, Immediate(imm32)); ++} ++ ++ ++void Assembler::and_(Register dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ emit_arith(4, Operand(dst), x); ++} ++ ++ ++void Assembler::and_(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x23); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::and_(const Operand& dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ emit_arith(4, dst, x); ++} ++ ++ ++void Assembler::and_(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x21); ++ emit_operand(src, dst); ++} ++ ++void Assembler::cmpb(const Operand& op, Immediate imm8) { ++ DCHECK(imm8.is_int8() || imm8.is_uint8()); ++ EnsureSpace ensure_space(this); ++ if (op.is_reg(eax)) { ++ EMIT(0x3C); ++ } else { ++ EMIT(0x80); ++ emit_operand(edi, op); // edi == 7 ++ } ++ emit_b(imm8); ++} ++ ++ ++void Assembler::cmpb(const Operand& op, Register reg) { ++ CHECK(reg.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x38); ++ emit_operand(reg, op); ++} ++ ++ ++void Assembler::cmpb(Register reg, const Operand& op) { ++ CHECK(reg.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x3A); ++ emit_operand(reg, op); ++} ++ ++ ++void Assembler::cmpw(const Operand& op, Immediate imm16) { ++ DCHECK(imm16.is_int16()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x81); ++ emit_operand(edi, op); ++ emit_w(imm16); ++} ++ ++void Assembler::cmpw(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x3B); ++ emit_operand(reg, op); ++} ++ ++void Assembler::cmpw(const Operand& op, Register reg) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x39); ++ emit_operand(reg, op); ++} ++ ++void Assembler::cmp(Register reg, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ emit_arith(7, Operand(reg), Immediate(imm32)); ++} ++ ++ ++void Assembler::cmp(Register reg, Handle handle) { ++ EnsureSpace ensure_space(this); ++ emit_arith(7, Operand(reg), Immediate(handle)); ++} ++ ++ ++void Assembler::cmp(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x3B); ++ emit_operand(reg, op); ++} ++ ++void Assembler::cmp(const Operand& op, Register reg) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x39); ++ emit_operand(reg, op); ++} ++ ++void Assembler::cmp(const Operand& op, const Immediate& imm) { ++ EnsureSpace ensure_space(this); ++ emit_arith(7, op, imm); ++} ++ ++ ++void Assembler::cmp(const Operand& op, Handle handle) { ++ EnsureSpace ensure_space(this); ++ emit_arith(7, op, Immediate(handle)); ++} ++ ++ ++void Assembler::cmpb_al(const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x38); // CMP r/m8, r8 ++ emit_operand(eax, op); // eax has same code as register al. ++} ++ ++ ++void Assembler::cmpw_ax(const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x39); // CMP r/m16, r16 ++ emit_operand(eax, op); // eax has same code as register ax. ++} ++ ++ ++void Assembler::dec_b(Register dst) { ++ CHECK(dst.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0xFE); ++ EMIT(0xC8 | dst.code()); ++} ++ ++ ++void Assembler::dec_b(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFE); ++ emit_operand(ecx, dst); ++} ++ ++ ++void Assembler::dec(Register dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x48 | dst.code()); ++} ++ ++ ++void Assembler::dec(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFF); ++ emit_operand(ecx, dst); ++} ++ ++ ++void Assembler::cdq() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x99); ++} ++ ++ ++void Assembler::idiv(const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ emit_operand(edi, src); ++} ++ ++ ++void Assembler::div(const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ emit_operand(esi, src); ++} ++ ++ ++void Assembler::imul(Register reg) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ EMIT(0xE8 | reg.code()); ++} ++ ++ ++void Assembler::imul(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xAF); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::imul(Register dst, Register src, int32_t imm32) { ++ imul(dst, Operand(src), imm32); ++} ++ ++ ++void Assembler::imul(Register dst, const Operand& src, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ if (is_int8(imm32)) { ++ EMIT(0x6B); ++ emit_operand(dst, src); ++ EMIT(imm32); ++ } else { ++ EMIT(0x69); ++ emit_operand(dst, src); ++ emit(imm32); ++ } ++} ++ ++ ++void Assembler::inc(Register dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x40 | dst.code()); ++} ++ ++ ++void Assembler::inc(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFF); ++ emit_operand(eax, dst); ++} ++ ++ ++void Assembler::lea(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x8D); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::mul(Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ EMIT(0xE0 | src.code()); ++} ++ ++ ++void Assembler::neg(Register dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ EMIT(0xD8 | dst.code()); ++} ++ ++ ++void Assembler::neg(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ emit_operand(ebx, dst); ++} ++ ++ ++void Assembler::not_(Register dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ EMIT(0xD0 | dst.code()); ++} ++ ++ ++void Assembler::not_(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ emit_operand(edx, dst); ++} ++ ++ ++void Assembler::or_(Register dst, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ emit_arith(1, Operand(dst), Immediate(imm32)); ++} ++ ++ ++void Assembler::or_(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0B); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::or_(const Operand& dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ emit_arith(1, dst, x); ++} ++ ++ ++void Assembler::or_(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x09); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::rcl(Register dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ EMIT(0xD0 | dst.code()); ++ } else { ++ EMIT(0xC1); ++ EMIT(0xD0 | dst.code()); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::rcr(Register dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ EMIT(0xD8 | dst.code()); ++ } else { ++ EMIT(0xC1); ++ EMIT(0xD8 | dst.code()); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::ror(const Operand& dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ emit_operand(ecx, dst); ++ } else { ++ EMIT(0xC1); ++ emit_operand(ecx, dst); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::ror_cl(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD3); ++ emit_operand(ecx, dst); ++} ++ ++ ++void Assembler::sar(const Operand& dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ emit_operand(edi, dst); ++ } else { ++ EMIT(0xC1); ++ emit_operand(edi, dst); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::sar_cl(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD3); ++ emit_operand(edi, dst); ++} ++ ++void Assembler::sbb(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x1B); ++ emit_operand(dst, src); ++} ++ ++void Assembler::shld(Register dst, Register src, uint8_t shift) { ++ DCHECK(is_uint5(shift)); ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xA4); ++ emit_operand(src, Operand(dst)); ++ EMIT(shift); ++} ++ ++void Assembler::shld_cl(Register dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xA5); ++ emit_operand(src, Operand(dst)); ++} ++ ++ ++void Assembler::shl(const Operand& dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ emit_operand(esp, dst); ++ } else { ++ EMIT(0xC1); ++ emit_operand(esp, dst); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::shl_cl(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD3); ++ emit_operand(esp, dst); ++} ++ ++void Assembler::shr(const Operand& dst, uint8_t imm8) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint5(imm8)); // illegal shift count ++ if (imm8 == 1) { ++ EMIT(0xD1); ++ emit_operand(ebp, dst); ++ } else { ++ EMIT(0xC1); ++ emit_operand(ebp, dst); ++ EMIT(imm8); ++ } ++} ++ ++ ++void Assembler::shr_cl(const Operand& dst) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD3); ++ emit_operand(ebp, dst); ++} ++ ++void Assembler::shrd(Register dst, Register src, uint8_t shift) { ++ DCHECK(is_uint5(shift)); ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xAC); ++ emit_operand(dst, Operand(src)); ++ EMIT(shift); ++} ++ ++void Assembler::shrd_cl(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xAD); ++ emit_operand(src, dst); ++} ++ ++void Assembler::sub(const Operand& dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ emit_arith(5, dst, x); ++} ++ ++ ++void Assembler::sub(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x2B); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::sub(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x29); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::test(Register reg, const Immediate& imm) { ++ if (imm.is_uint8()) { ++ test_b(reg, imm); ++ return; ++ } ++ ++ EnsureSpace ensure_space(this); ++ // This is not using emit_arith because test doesn't support ++ // sign-extension of 8-bit operands. ++ if (reg.is(eax)) { ++ EMIT(0xA9); ++ } else { ++ EMIT(0xF7); ++ EMIT(0xC0 | reg.code()); ++ } ++ emit(imm); ++} ++ ++ ++void Assembler::test(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x85); ++ emit_operand(reg, op); ++} ++ ++ ++void Assembler::test_b(Register reg, const Operand& op) { ++ CHECK(reg.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x84); ++ emit_operand(reg, op); ++} ++ ++ ++void Assembler::test(const Operand& op, const Immediate& imm) { ++ if (op.is_reg_only()) { ++ test(op.reg(), imm); ++ return; ++ } ++ if (imm.is_uint8()) { ++ return test_b(op, imm); ++ } ++ EnsureSpace ensure_space(this); ++ EMIT(0xF7); ++ emit_operand(eax, op); ++ emit(imm); ++} ++ ++void Assembler::test_b(Register reg, Immediate imm8) { ++ DCHECK(imm8.is_uint8()); ++ EnsureSpace ensure_space(this); ++ // Only use test against byte for registers that have a byte ++ // variant: eax, ebx, ecx, and edx. ++ if (reg.is(eax)) { ++ EMIT(0xA8); ++ emit_b(imm8); ++ } else if (reg.is_byte_register()) { ++ emit_arith_b(0xF6, 0xC0, reg, static_cast(imm8.x_)); ++ } else { ++ EMIT(0x66); ++ EMIT(0xF7); ++ EMIT(0xC0 | reg.code()); ++ emit_w(imm8); ++ } ++} ++ ++void Assembler::test_b(const Operand& op, Immediate imm8) { ++ if (op.is_reg_only()) { ++ test_b(op.reg(), imm8); ++ return; ++ } ++ EnsureSpace ensure_space(this); ++ EMIT(0xF6); ++ emit_operand(eax, op); ++ emit_b(imm8); ++} ++ ++void Assembler::test_w(Register reg, Immediate imm16) { ++ DCHECK(imm16.is_int16() || imm16.is_uint16()); ++ EnsureSpace ensure_space(this); ++ if (reg.is(eax)) { ++ EMIT(0xA9); ++ emit_w(imm16); ++ } else { ++ EMIT(0x66); ++ EMIT(0xF7); ++ EMIT(0xc0 | reg.code()); ++ emit_w(imm16); ++ } ++} ++ ++void Assembler::test_w(Register reg, const Operand& op) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0x85); ++ emit_operand(reg, op); ++} ++ ++void Assembler::test_w(const Operand& op, Immediate imm16) { ++ DCHECK(imm16.is_int16() || imm16.is_uint16()); ++ if (op.is_reg_only()) { ++ test_w(op.reg(), imm16); ++ return; ++ } ++ EnsureSpace ensure_space(this); ++ EMIT(0x66); ++ EMIT(0xF7); ++ emit_operand(eax, op); ++ emit_w(imm16); ++} ++ ++void Assembler::xor_(Register dst, int32_t imm32) { ++ EnsureSpace ensure_space(this); ++ emit_arith(6, Operand(dst), Immediate(imm32)); ++} ++ ++ ++void Assembler::xor_(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x33); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::xor_(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x31); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::xor_(const Operand& dst, const Immediate& x) { ++ EnsureSpace ensure_space(this); ++ emit_arith(6, dst, x); ++} ++ ++ ++void Assembler::bt(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xA3); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::bts(const Operand& dst, Register src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xAB); ++ emit_operand(src, dst); ++} ++ ++ ++void Assembler::bsr(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xBD); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::bsf(Register dst, const Operand& src) { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0xBC); ++ emit_operand(dst, src); ++} ++ ++ ++void Assembler::hlt() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xF4); ++} ++ ++ ++void Assembler::int3() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xCC); ++} ++ ++ ++void Assembler::nop() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x90); ++} ++ ++ ++void Assembler::ret(int imm16) { ++ EnsureSpace ensure_space(this); ++ DCHECK(is_uint16(imm16)); ++ if (imm16 == 0) { ++ EMIT(0xC3); ++ } else { ++ EMIT(0xC2); ++ EMIT(imm16 & 0xFF); ++ EMIT((imm16 >> 8) & 0xFF); ++ } ++} ++ ++ ++void Assembler::ud2() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0x0B); ++} ++ ++ ++// Labels refer to positions in the (to be) generated code. ++// There are bound, linked, and unused labels. ++// ++// Bound labels refer to known positions in the already ++// generated code. pos() is the position the label refers to. ++// ++// Linked labels refer to unknown positions in the code ++// to be generated; pos() is the position of the 32bit ++// Displacement of the last instruction using the label. ++ ++ ++void Assembler::print(Label* L) { ++ if (L->is_unused()) { ++ PrintF("unused label\n"); ++ } else if (L->is_bound()) { ++ PrintF("bound label to %d\n", L->pos()); ++ } else if (L->is_linked()) { ++ Label l = *L; ++ PrintF("unbound label"); ++ while (l.is_linked()) { ++ Displacement disp = disp_at(&l); ++ PrintF("@ %d ", l.pos()); ++ disp.print(); ++ PrintF("\n"); ++ disp.next(&l); ++ } ++ } else { ++ PrintF("label in inconsistent state (pos = %d)\n", L->pos_); ++ } ++} ++ ++ ++void Assembler::bind_to(Label* L, int pos) { ++ EnsureSpace ensure_space(this); ++ DCHECK(0 <= pos && pos <= pc_offset()); // must have a valid binding position ++ while (L->is_linked()) { ++ Displacement disp = disp_at(L); ++ int fixup_pos = L->pos(); ++ if (disp.type() == Displacement::CODE_ABSOLUTE) { ++ long_at_put(fixup_pos, reinterpret_cast(buffer_ + pos)); ++ internal_reference_positions_.push_back(fixup_pos); ++ } else if (disp.type() == Displacement::CODE_RELATIVE) { ++ // Relative to Code* heap object pointer. ++ long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag); ++ } else { ++ if (disp.type() == Displacement::UNCONDITIONAL_JUMP) { ++ DCHECK(byte_at(fixup_pos - 1) == 0xE9); // jmp expected ++ } ++ // Relative address, relative to point after address. ++ int imm32 = pos - (fixup_pos + sizeof(int32_t)); ++ long_at_put(fixup_pos, imm32); ++ } ++ disp.next(L); ++ } ++ while (L->is_near_linked()) { ++ int fixup_pos = L->near_link_pos(); ++ int offset_to_next = ++ static_cast(*reinterpret_cast(addr_at(fixup_pos))); ++ DCHECK(offset_to_next <= 0); ++ // Relative address, relative to point after address. ++ int disp = pos - fixup_pos - sizeof(int8_t); ++ CHECK(0 <= disp && disp <= 127); ++ set_byte_at(fixup_pos, disp); ++ if (offset_to_next < 0) { ++ L->link_to(fixup_pos + offset_to_next, Label::kNear); ++ } else { ++ L->UnuseNear(); ++ } ++ } ++ L->bind_to(pos); ++} ++ ++ ++void Assembler::bind(Label* L) { ++ EnsureSpace ensure_space(this); ++ DCHECK(!L->is_bound()); // label can only be bound once ++ bind_to(L, pc_offset()); ++} ++ ++ ++void Assembler::call(Label* L) { ++ EnsureSpace ensure_space(this); ++ if (L->is_bound()) { ++ const int long_size = 5; ++ int offs = L->pos() - pc_offset(); ++ DCHECK(offs <= 0); ++ // 1110 1000 #32-bit disp. ++ EMIT(0xE8); ++ emit(offs - long_size); ++ } else { ++ // 1110 1000 #32-bit disp. ++ EMIT(0xE8); ++ emit_disp(L, Displacement::OTHER); ++ } ++} ++ ++ ++void Assembler::call(byte* entry, RelocInfo::Mode rmode) { ++ EnsureSpace ensure_space(this); ++ DCHECK(!RelocInfo::IsCodeTarget(rmode)); ++ EMIT(0xE8); ++ if (RelocInfo::IsRuntimeEntry(rmode)) { ++ emit(reinterpret_cast(entry), rmode); ++ } else { ++ emit(entry - (pc_ + sizeof(int32_t)), rmode); ++ } ++} ++ ++ ++int Assembler::CallSize(const Operand& adr) { ++ // Call size is 1 (opcode) + adr.len_ (operand). ++ return 1 + adr.len_; ++} ++ ++ ++void Assembler::call(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFF); ++ emit_operand(edx, adr); ++} ++ ++ ++int Assembler::CallSize(Handle code, RelocInfo::Mode rmode) { ++ return 1 /* EMIT */ + sizeof(uint32_t) /* emit */; ++} ++ ++ ++void Assembler::call(Handle code, ++ RelocInfo::Mode rmode, ++ TypeFeedbackId ast_id) { ++ EnsureSpace ensure_space(this); ++ DCHECK(RelocInfo::IsCodeTarget(rmode) ++ || rmode == RelocInfo::CODE_AGE_SEQUENCE); ++ EMIT(0xE8); ++ emit(code, rmode, ast_id); ++} ++ ++ ++void Assembler::jmp(Label* L, Label::Distance distance) { ++ EnsureSpace ensure_space(this); ++ if (L->is_bound()) { ++ const int short_size = 2; ++ const int long_size = 5; ++ int offs = L->pos() - pc_offset(); ++ DCHECK(offs <= 0); ++ if (is_int8(offs - short_size)) { ++ // 1110 1011 #8-bit disp. ++ EMIT(0xEB); ++ EMIT((offs - short_size) & 0xFF); ++ } else { ++ // 1110 1001 #32-bit disp. ++ EMIT(0xE9); ++ emit(offs - long_size); ++ } ++ } else if (distance == Label::kNear) { ++ EMIT(0xEB); ++ emit_near_disp(L); ++ } else { ++ // 1110 1001 #32-bit disp. ++ EMIT(0xE9); ++ emit_disp(L, Displacement::UNCONDITIONAL_JUMP); ++ } ++} ++ ++ ++void Assembler::jmp(byte* entry, RelocInfo::Mode rmode) { ++ EnsureSpace ensure_space(this); ++ DCHECK(!RelocInfo::IsCodeTarget(rmode)); ++ EMIT(0xE9); ++ if (RelocInfo::IsRuntimeEntry(rmode)) { ++ emit(reinterpret_cast(entry), rmode); ++ } else { ++ emit(entry - (pc_ + sizeof(int32_t)), rmode); ++ } ++} ++ ++ ++void Assembler::jmp(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xFF); ++ emit_operand(esp, adr); ++} ++ ++ ++void Assembler::jmp(Handle code, RelocInfo::Mode rmode) { ++ EnsureSpace ensure_space(this); ++ DCHECK(RelocInfo::IsCodeTarget(rmode)); ++ EMIT(0xE9); ++ emit(code, rmode); ++} ++ ++ ++void Assembler::j(Condition cc, Label* L, Label::Distance distance) { ++ EnsureSpace ensure_space(this); ++ DCHECK(0 <= cc && static_cast(cc) < 16); ++ if (L->is_bound()) { ++ const int short_size = 2; ++ const int long_size = 6; ++ int offs = L->pos() - pc_offset(); ++ DCHECK(offs <= 0); ++ if (is_int8(offs - short_size)) { ++ // 0111 tttn #8-bit disp ++ EMIT(0x70 | cc); ++ EMIT((offs - short_size) & 0xFF); ++ } else { ++ // 0000 1111 1000 tttn #32-bit disp ++ EMIT(0x0F); ++ EMIT(0x80 | cc); ++ emit(offs - long_size); ++ } ++ } else if (distance == Label::kNear) { ++ EMIT(0x70 | cc); ++ emit_near_disp(L); ++ } else { ++ // 0000 1111 1000 tttn #32-bit disp ++ // Note: could eliminate cond. jumps to this jump if condition ++ // is the same however, seems to be rather unlikely case. ++ EMIT(0x0F); ++ EMIT(0x80 | cc); ++ emit_disp(L, Displacement::OTHER); ++ } ++} ++ ++ ++void Assembler::j(Condition cc, byte* entry, RelocInfo::Mode rmode) { ++ EnsureSpace ensure_space(this); ++ DCHECK((0 <= cc) && (static_cast(cc) < 16)); ++ // 0000 1111 1000 tttn #32-bit disp. ++ EMIT(0x0F); ++ EMIT(0x80 | cc); ++ if (RelocInfo::IsRuntimeEntry(rmode)) { ++ emit(reinterpret_cast(entry), rmode); ++ } else { ++ emit(entry - (pc_ + sizeof(int32_t)), rmode); ++ } ++} ++ ++ ++void Assembler::j(Condition cc, Handle code, RelocInfo::Mode rmode) { ++ EnsureSpace ensure_space(this); ++ // 0000 1111 1000 tttn #32-bit disp ++ EMIT(0x0F); ++ EMIT(0x80 | cc); ++ emit(code, rmode); ++} ++ ++ ++// FPU instructions. ++ ++void Assembler::fld(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD9, 0xC0, i); ++} ++ ++ ++void Assembler::fstp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDD, 0xD8, i); ++} ++ ++ ++void Assembler::fld1() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xE8); ++} ++ ++ ++void Assembler::fldpi() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xEB); ++} ++ ++ ++void Assembler::fldz() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xEE); ++} ++ ++ ++void Assembler::fldln2() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xED); ++} ++ ++ ++void Assembler::fld_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ emit_operand(eax, adr); ++} ++ ++ ++void Assembler::fld_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(eax, adr); ++} ++ ++ ++void Assembler::fstp_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ emit_operand(ebx, adr); ++} ++ ++ ++void Assembler::fst_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ emit_operand(edx, adr); ++} ++ ++ ++void Assembler::fldcw(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ emit_operand(ebp, adr); ++} ++ ++ ++void Assembler::fnstcw(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ emit_operand(edi, adr); ++} ++ ++ ++void Assembler::fstp_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(ebx, adr); ++} ++ ++ ++void Assembler::fst_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(edx, adr); ++} ++ ++ ++void Assembler::fild_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ emit_operand(eax, adr); ++} ++ ++ ++void Assembler::fild_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDF); ++ emit_operand(ebp, adr); ++} ++ ++ ++void Assembler::fistp_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ emit_operand(ebx, adr); ++} ++ ++ ++void Assembler::fisttp_s(const Operand& adr) { ++ DCHECK(IsEnabled(SSE3)); ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ emit_operand(ecx, adr); ++} ++ ++ ++void Assembler::fisttp_d(const Operand& adr) { ++ DCHECK(IsEnabled(SSE3)); ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(ecx, adr); ++} ++ ++ ++void Assembler::fist_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ emit_operand(edx, adr); ++} ++ ++ ++void Assembler::fistp_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDF); ++ emit_operand(edi, adr); ++} ++ ++ ++void Assembler::fabs() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xE1); ++} ++ ++ ++void Assembler::fchs() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xE0); ++} ++ ++ ++void Assembler::fsqrt() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xFA); ++} ++ ++ ++void Assembler::fcos() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xFF); ++} ++ ++ ++void Assembler::fsin() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xFE); ++} ++ ++ ++void Assembler::fptan() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF2); ++} ++ ++ ++void Assembler::fyl2x() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF1); ++} ++ ++ ++void Assembler::f2xm1() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF0); ++} ++ ++ ++void Assembler::fscale() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xFD); ++} ++ ++ ++void Assembler::fninit() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ EMIT(0xE3); ++} ++ ++ ++void Assembler::fadd(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDC, 0xC0, i); ++} ++ ++ ++void Assembler::fadd_i(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD8, 0xC0, i); ++} ++ ++ ++void Assembler::fadd_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(eax, adr); ++} ++ ++ ++void Assembler::fsub(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDC, 0xE8, i); ++} ++ ++ ++void Assembler::fsub_i(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD8, 0xE0, i); ++} ++ ++ ++void Assembler::fsubr_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(ebp, adr); ++} ++ ++ ++void Assembler::fsub_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(esp, adr); ++} ++ ++ ++void Assembler::fisub_s(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDA); ++ emit_operand(esp, adr); ++} ++ ++ ++void Assembler::fmul_i(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD8, 0xC8, i); ++} ++ ++ ++void Assembler::fmul(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDC, 0xC8, i); ++} ++ ++ ++void Assembler::fmul_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(ecx, adr); ++} ++ ++ ++void Assembler::fdiv(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDC, 0xF8, i); ++} ++ ++ ++void Assembler::fdiv_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(esi, adr); ++} ++ ++ ++void Assembler::fdivr_d(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDC); ++ emit_operand(edi, adr); ++} ++ ++ ++void Assembler::fdiv_i(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD8, 0xF0, i); ++} ++ ++ ++void Assembler::faddp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDE, 0xC0, i); ++} ++ ++ ++void Assembler::fsubp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDE, 0xE8, i); ++} ++ ++ ++void Assembler::fsubrp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDE, 0xE0, i); ++} ++ ++ ++void Assembler::fmulp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDE, 0xC8, i); ++} ++ ++ ++void Assembler::fdivp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDE, 0xF8, i); ++} ++ ++ ++void Assembler::fprem() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF8); ++} ++ ++ ++void Assembler::fprem1() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF5); ++} ++ ++ ++void Assembler::fxch(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xD9, 0xC8, i); ++} ++ ++ ++void Assembler::fincstp() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xF7); ++} ++ ++ ++void Assembler::ffree(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDD, 0xC0, i); ++} ++ ++ ++void Assembler::ftst() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xE4); ++} ++ ++ ++void Assembler::fxam() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xE5); ++} ++ ++ ++void Assembler::fucomp(int i) { ++ EnsureSpace ensure_space(this); ++ emit_farith(0xDD, 0xE8, i); ++} ++ ++ ++void Assembler::fucompp() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDA); ++ EMIT(0xE9); ++} ++ ++ ++void Assembler::fucomi(int i) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ EMIT(0xE8 + i); ++} ++ ++ ++void Assembler::fucomip() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDF); ++ EMIT(0xE9); ++} ++ ++ ++void Assembler::fcompp() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDE); ++ EMIT(0xD9); ++} ++ ++ ++void Assembler::fnstsw_ax() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDF); ++ EMIT(0xE0); ++} ++ ++ ++void Assembler::fwait() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x9B); ++} ++ ++ ++void Assembler::frndint() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xD9); ++ EMIT(0xFC); ++} ++ ++ ++void Assembler::fnclex() { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDB); ++ EMIT(0xE2); ++} ++ ++ ++void Assembler::fnsave(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(esi, adr); ++} ++ ++ ++void Assembler::frstor(const Operand& adr) { ++ EnsureSpace ensure_space(this); ++ EMIT(0xDD); ++ emit_operand(esp, adr); ++} ++ ++ ++void Assembler::sahf() { ++ EnsureSpace ensure_space(this); ++ EMIT(0x9E); ++} ++ ++ ++void Assembler::setcc(Condition cc, Register reg) { ++ DCHECK(reg.is_byte_register()); ++ EnsureSpace ensure_space(this); ++ EMIT(0x0F); ++ EMIT(0x90 | cc); ++ EMIT(0xC0 | reg.code()); ++} ++ ++ ++void Assembler::GrowBuffer() { ++ DCHECK(buffer_overflow()); ++ if (!own_buffer_) FATAL("external code buffer is too small"); ++ ++ // Compute new buffer size. ++ CodeDesc desc; // the new buffer ++ desc.buffer_size = 2 * buffer_size_; ++ ++ // Some internal data structures overflow for very large buffers, ++ // they must ensure that kMaximalBufferSize is not too large. ++ if (desc.buffer_size > kMaximalBufferSize || ++ static_cast(desc.buffer_size) > ++ isolate()->heap()->MaxOldGenerationSize()) { ++ V8::FatalProcessOutOfMemory("Assembler::GrowBuffer"); ++ } ++ ++ // Set up new buffer. ++ desc.buffer = NewArray(desc.buffer_size); ++ desc.origin = this; ++ desc.instr_size = pc_offset(); ++ desc.reloc_size = (buffer_ + buffer_size_) - (reloc_info_writer.pos()); ++ ++ // Clear the buffer in debug mode. Use 'int3' instructions to make ++ // sure to get into problems if we ever run uninitialized code. ++#ifdef DEBUG ++ memset(desc.buffer, 0xCC, desc.buffer_size); ++#endif ++ ++ // Copy the data. ++ int pc_delta = desc.buffer - buffer_; ++ int rc_delta = (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); ++ MemMove(desc.buffer, buffer_, desc.instr_size); ++ MemMove(rc_delta + reloc_info_writer.pos(), reloc_info_writer.pos(), ++ desc.reloc_size); ++ ++ DeleteArray(buffer_); ++ buffer_ = desc.buffer; ++ buffer_size_ = desc.buffer_size; ++ pc_ += pc_delta; ++ reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, ++ reloc_info_writer.last_pc() + pc_delta); ++ ++ // Relocate internal references. ++ for (auto pos : internal_reference_positions_) { ++ int32_t* p = reinterpret_cast(buffer_ + pos); ++ *p += pc_delta; ++ } ++ ++ DCHECK(!buffer_overflow()); ++} ++ ++ ++void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { ++ DCHECK(is_uint8(op1) && is_uint8(op2)); // wrong opcode ++ DCHECK(is_uint8(imm8)); ++ DCHECK((op1 & 0x01) == 0); // should be 8bit operation ++ EMIT(op1); ++ EMIT(op2 | dst.code()); ++ EMIT(imm8); ++} ++ ++ ++void Assembler::emit_arith(int sel, Operand dst, const Immediate& x) { ++ DCHECK((0 <= sel) && (sel <= 7)); ++ Register ireg = { sel }; ++ if (x.is_int8()) { ++ EMIT(0x83); // using a sign-extended 8-bit immediate. ++ emit_operand(ireg, dst); ++ EMIT(x.x_ & 0xFF); ++ } else if (dst.is_reg(eax)) { ++ EMIT((sel << 3) | 0x05); // short form if the destination is eax. ++ emit(x); ++ } else { ++ EMIT(0x81); // using a literal 32-bit immediate. ++ emit_operand(ireg, dst); ++ emit(x); ++ } ++} ++ ++ ++void Assembler::emit_operand(Register reg, const Operand& adr) { ++ const unsigned length = adr.len_; ++ DCHECK(length > 0); ++ ++ // Emit updated ModRM byte containing the given register. ++ pc_[0] = (adr.buf_[0] & ~0x38) | (reg.code() << 3); ++ ++ // Emit the rest of the encoded operand. ++ for (unsigned i = 1; i < length; i++) pc_[i] = adr.buf_[i]; ++ pc_ += length; ++ ++ // Emit relocation information if necessary. ++ if (length >= sizeof(int32_t) && !RelocInfo::IsNone(adr.rmode_)) { ++ pc_ -= sizeof(int32_t); // pc_ must be *at* disp32 ++ RecordRelocInfo(adr.rmode_); ++ if (adr.rmode_ == RelocInfo::INTERNAL_REFERENCE) { // Fixup for labels ++ emit_label(*reinterpret_cast(pc_)); ++ } else { ++ pc_ += sizeof(int32_t); ++ } ++ } ++} ++ ++ ++void Assembler::emit_label(Label* label) { ++ if (label->is_bound()) { ++ internal_reference_positions_.push_back(pc_offset()); ++ emit(reinterpret_cast(buffer_ + label->pos())); ++ } else { ++ emit_disp(label, Displacement::CODE_ABSOLUTE); ++ } ++} ++ ++ ++void Assembler::emit_farith(int b1, int b2, int i) { ++ DCHECK(is_uint8(b1) && is_uint8(b2)); // wrong opcode ++ DCHECK(0 <= i && i < 8); // illegal stack offset ++ EMIT(b1); ++ EMIT(b2 + i); ++} ++ ++ ++void Assembler::db(uint8_t data) { ++ EnsureSpace ensure_space(this); ++ EMIT(data); ++} ++ ++ ++void Assembler::dd(uint32_t data) { ++ EnsureSpace ensure_space(this); ++ emit(data); ++} ++ ++ ++void Assembler::dq(uint64_t data) { ++ EnsureSpace ensure_space(this); ++ emit_q(data); ++} ++ ++ ++void Assembler::dd(Label* label) { ++ EnsureSpace ensure_space(this); ++ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); ++ emit_label(label); ++} ++ ++ ++void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { ++ DCHECK(!RelocInfo::IsNone(rmode)); ++ // Don't record external references unless the heap will be serialized. ++ if (rmode == RelocInfo::EXTERNAL_REFERENCE && ++ !serializer_enabled() && !emit_debug_code()) { ++ return; ++ } ++ RelocInfo rinfo(isolate(), pc_, rmode, data, NULL); ++ reloc_info_writer.Write(&rinfo); ++} ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87.h 2017-12-25 17:42:57.220465573 +0100 +@@ -0,0 +1,1107 @@ ++// Copyright (c) 1994-2006 Sun Microsystems Inc. ++// All Rights Reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are ++// met: ++// ++// - Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// ++// - Redistribution in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// - Neither the name of Sun Microsystems or the names of contributors may ++// be used to endorse or promote products derived from this software without ++// specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++// The original source code covered by the above license above has been ++// modified significantly by Google Inc. ++// Copyright 2011 the V8 project authors. All rights reserved. ++ ++// A light-weight IA32 Assembler. ++ ++#ifndef V8_X87_ASSEMBLER_X87_H_ ++#define V8_X87_ASSEMBLER_X87_H_ ++ ++#include ++ ++#include "src/assembler.h" ++#include "src/isolate.h" ++#include "src/utils.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define GENERAL_REGISTERS(V) \ ++ V(eax) \ ++ V(ecx) \ ++ V(edx) \ ++ V(ebx) \ ++ V(esp) \ ++ V(ebp) \ ++ V(esi) \ ++ V(edi) ++ ++#define ALLOCATABLE_GENERAL_REGISTERS(V) \ ++ V(eax) \ ++ V(ecx) \ ++ V(edx) \ ++ V(ebx) \ ++ V(esi) \ ++ V(edi) ++ ++#define DOUBLE_REGISTERS(V) \ ++ V(stX_0) \ ++ V(stX_1) \ ++ V(stX_2) \ ++ V(stX_3) \ ++ V(stX_4) \ ++ V(stX_5) \ ++ V(stX_6) \ ++ V(stX_7) ++ ++#define FLOAT_REGISTERS DOUBLE_REGISTERS ++#define SIMD128_REGISTERS DOUBLE_REGISTERS ++ ++#define ALLOCATABLE_DOUBLE_REGISTERS(V) \ ++ V(stX_0) \ ++ V(stX_1) \ ++ V(stX_2) \ ++ V(stX_3) \ ++ V(stX_4) \ ++ V(stX_5) ++ ++// CPU Registers. ++// ++// 1) We would prefer to use an enum, but enum values are assignment- ++// compatible with int, which has caused code-generation bugs. ++// ++// 2) We would prefer to use a class instead of a struct but we don't like ++// the register initialization to depend on the particular initialization ++// order (which appears to be different on OS X, Linux, and Windows for the ++// installed versions of C++ we tried). Using a struct permits C-style ++// "initialization". Also, the Register objects cannot be const as this ++// forces initialization stubs in MSVC, making us dependent on initialization ++// order. ++// ++// 3) By not using an enum, we are possibly preventing the compiler from ++// doing certain constant folds, which may significantly reduce the ++// code generated for some assembly instructions (because they boil down ++// to a few constants). If this is a problem, we could change the code ++// such that we use an enum in optimized mode, and the struct in debug ++// mode. This way we get the compile-time error checking in debug mode ++// and best performance in optimized code. ++// ++struct Register { ++ enum Code { ++#define REGISTER_CODE(R) kCode_##R, ++ GENERAL_REGISTERS(REGISTER_CODE) ++#undef REGISTER_CODE ++ kAfterLast, ++ kCode_no_reg = -1 ++ }; ++ ++ static const int kNumRegisters = Code::kAfterLast; ++ ++ static Register from_code(int code) { ++ DCHECK(code >= 0); ++ DCHECK(code < kNumRegisters); ++ Register r = {code}; ++ return r; ++ } ++ bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; } ++ bool is(Register reg) const { return reg_code == reg.reg_code; } ++ int code() const { ++ DCHECK(is_valid()); ++ return reg_code; ++ } ++ int bit() const { ++ DCHECK(is_valid()); ++ return 1 << reg_code; ++ } ++ ++ bool is_byte_register() const { return reg_code <= 3; } ++ ++ // Unfortunately we can't make this private in a struct. ++ int reg_code; ++}; ++ ++ ++#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R}; ++GENERAL_REGISTERS(DECLARE_REGISTER) ++#undef DECLARE_REGISTER ++const Register no_reg = {Register::kCode_no_reg}; ++ ++static const bool kSimpleFPAliasing = true; ++static const bool kSimdMaskRegisters = false; ++ ++struct X87Register { ++ enum Code { ++#define REGISTER_CODE(R) kCode_##R, ++ DOUBLE_REGISTERS(REGISTER_CODE) ++#undef REGISTER_CODE ++ kAfterLast, ++ kCode_no_reg = -1 ++ }; ++ ++ static const int kMaxNumRegisters = Code::kAfterLast; ++ static const int kMaxNumAllocatableRegisters = 6; ++ ++ static X87Register from_code(int code) { ++ X87Register result = {code}; ++ return result; ++ } ++ ++ bool is_valid() const { return 0 <= reg_code && reg_code < kMaxNumRegisters; } ++ ++ int code() const { ++ DCHECK(is_valid()); ++ return reg_code; ++ } ++ ++ bool is(X87Register reg) const { return reg_code == reg.reg_code; } ++ ++ int reg_code; ++}; ++ ++typedef X87Register FloatRegister; ++ ++typedef X87Register DoubleRegister; ++ ++// TODO(x87) Define SIMD registers. ++typedef X87Register Simd128Register; ++ ++#define DECLARE_REGISTER(R) \ ++ const DoubleRegister R = {DoubleRegister::kCode_##R}; ++DOUBLE_REGISTERS(DECLARE_REGISTER) ++#undef DECLARE_REGISTER ++const DoubleRegister no_double_reg = {DoubleRegister::kCode_no_reg}; ++ ++enum Condition { ++ // any value < 0 is considered no_condition ++ no_condition = -1, ++ ++ overflow = 0, ++ no_overflow = 1, ++ below = 2, ++ above_equal = 3, ++ equal = 4, ++ not_equal = 5, ++ below_equal = 6, ++ above = 7, ++ negative = 8, ++ positive = 9, ++ parity_even = 10, ++ parity_odd = 11, ++ less = 12, ++ greater_equal = 13, ++ less_equal = 14, ++ greater = 15, ++ ++ // aliases ++ carry = below, ++ not_carry = above_equal, ++ zero = equal, ++ not_zero = not_equal, ++ sign = negative, ++ not_sign = positive ++}; ++ ++ ++// Returns the equivalent of !cc. ++// Negation of the default no_condition (-1) results in a non-default ++// no_condition value (-2). As long as tests for no_condition check ++// for condition < 0, this will work as expected. ++inline Condition NegateCondition(Condition cc) { ++ return static_cast(cc ^ 1); ++} ++ ++ ++// Commute a condition such that {a cond b == b cond' a}. ++inline Condition CommuteCondition(Condition cc) { ++ switch (cc) { ++ case below: ++ return above; ++ case above: ++ return below; ++ case above_equal: ++ return below_equal; ++ case below_equal: ++ return above_equal; ++ case less: ++ return greater; ++ case greater: ++ return less; ++ case greater_equal: ++ return less_equal; ++ case less_equal: ++ return greater_equal; ++ default: ++ return cc; ++ } ++} ++ ++ ++enum RoundingMode { ++ kRoundToNearest = 0x0, ++ kRoundDown = 0x1, ++ kRoundUp = 0x2, ++ kRoundToZero = 0x3 ++}; ++ ++ ++// ----------------------------------------------------------------------------- ++// Machine instruction Immediates ++ ++class Immediate BASE_EMBEDDED { ++ public: ++ inline explicit Immediate(int x); ++ inline explicit Immediate(const ExternalReference& ext); ++ inline explicit Immediate(Handle handle); ++ inline explicit Immediate(Smi* value); ++ inline explicit Immediate(Address addr); ++ inline explicit Immediate(Address x, RelocInfo::Mode rmode); ++ ++ static Immediate CodeRelativeOffset(Label* label) { ++ return Immediate(label); ++ } ++ ++ bool is_zero() const { return x_ == 0 && RelocInfo::IsNone(rmode_); } ++ bool is_int8() const { ++ return -128 <= x_ && x_ < 128 && RelocInfo::IsNone(rmode_); ++ } ++ bool is_uint8() const { ++ return v8::internal::is_uint8(x_) && RelocInfo::IsNone(rmode_); ++ } ++ bool is_int16() const { ++ return -32768 <= x_ && x_ < 32768 && RelocInfo::IsNone(rmode_); ++ } ++ bool is_uint16() const { ++ return v8::internal::is_uint16(x_) && RelocInfo::IsNone(rmode_); ++ } ++ ++ private: ++ inline explicit Immediate(Label* value); ++ ++ int x_; ++ RelocInfo::Mode rmode_; ++ ++ friend class Operand; ++ friend class Assembler; ++ friend class MacroAssembler; ++}; ++ ++ ++// ----------------------------------------------------------------------------- ++// Machine instruction Operands ++ ++enum ScaleFactor { ++ times_1 = 0, ++ times_2 = 1, ++ times_4 = 2, ++ times_8 = 3, ++ times_int_size = times_4, ++ times_half_pointer_size = times_2, ++ times_pointer_size = times_4, ++ times_twice_pointer_size = times_8 ++}; ++ ++ ++class Operand BASE_EMBEDDED { ++ public: ++ // reg ++ INLINE(explicit Operand(Register reg)); ++ ++ // [disp/r] ++ INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode)); ++ ++ // [disp/r] ++ INLINE(explicit Operand(Immediate imm)); ++ ++ // [base + disp/r] ++ explicit Operand(Register base, int32_t disp, ++ RelocInfo::Mode rmode = RelocInfo::NONE32); ++ ++ // [base + index*scale + disp/r] ++ explicit Operand(Register base, ++ Register index, ++ ScaleFactor scale, ++ int32_t disp, ++ RelocInfo::Mode rmode = RelocInfo::NONE32); ++ ++ // [index*scale + disp/r] ++ explicit Operand(Register index, ++ ScaleFactor scale, ++ int32_t disp, ++ RelocInfo::Mode rmode = RelocInfo::NONE32); ++ ++ static Operand JumpTable(Register index, ScaleFactor scale, Label* table) { ++ return Operand(index, scale, reinterpret_cast(table), ++ RelocInfo::INTERNAL_REFERENCE); ++ } ++ ++ static Operand StaticVariable(const ExternalReference& ext) { ++ return Operand(reinterpret_cast(ext.address()), ++ RelocInfo::EXTERNAL_REFERENCE); ++ } ++ ++ static Operand StaticArray(Register index, ++ ScaleFactor scale, ++ const ExternalReference& arr) { ++ return Operand(index, scale, reinterpret_cast(arr.address()), ++ RelocInfo::EXTERNAL_REFERENCE); ++ } ++ ++ static Operand ForCell(Handle cell) { ++ AllowDeferredHandleDereference embedding_raw_address; ++ return Operand(reinterpret_cast(cell.location()), ++ RelocInfo::CELL); ++ } ++ ++ static Operand ForRegisterPlusImmediate(Register base, Immediate imm) { ++ return Operand(base, imm.x_, imm.rmode_); ++ } ++ ++ // Returns true if this Operand is a wrapper for the specified register. ++ bool is_reg(Register reg) const; ++ ++ // Returns true if this Operand is a wrapper for one register. ++ bool is_reg_only() const; ++ ++ // Asserts that this Operand is a wrapper for one register and returns the ++ // register. ++ Register reg() const; ++ ++ private: ++ // Set the ModRM byte without an encoded 'reg' register. The ++ // register is encoded later as part of the emit_operand operation. ++ inline void set_modrm(int mod, Register rm); ++ ++ inline void set_sib(ScaleFactor scale, Register index, Register base); ++ inline void set_disp8(int8_t disp); ++ inline void set_dispr(int32_t disp, RelocInfo::Mode rmode); ++ ++ byte buf_[6]; ++ // The number of bytes in buf_. ++ unsigned int len_; ++ // Only valid if len_ > 4. ++ RelocInfo::Mode rmode_; ++ ++ friend class Assembler; ++ friend class MacroAssembler; ++}; ++ ++ ++// ----------------------------------------------------------------------------- ++// A Displacement describes the 32bit immediate field of an instruction which ++// may be used together with a Label in order to refer to a yet unknown code ++// position. Displacements stored in the instruction stream are used to describe ++// the instruction and to chain a list of instructions using the same Label. ++// A Displacement contains 2 different fields: ++// ++// next field: position of next displacement in the chain (0 = end of list) ++// type field: instruction type ++// ++// A next value of null (0) indicates the end of a chain (note that there can ++// be no displacement at position zero, because there is always at least one ++// instruction byte before the displacement). ++// ++// Displacement _data field layout ++// ++// |31.....2|1......0| ++// [ next | type | ++ ++class Displacement BASE_EMBEDDED { ++ public: ++ enum Type { UNCONDITIONAL_JUMP, CODE_RELATIVE, OTHER, CODE_ABSOLUTE }; ++ ++ int data() const { return data_; } ++ Type type() const { return TypeField::decode(data_); } ++ void next(Label* L) const { ++ int n = NextField::decode(data_); ++ n > 0 ? L->link_to(n) : L->Unuse(); ++ } ++ void link_to(Label* L) { init(L, type()); } ++ ++ explicit Displacement(int data) { data_ = data; } ++ ++ Displacement(Label* L, Type type) { init(L, type); } ++ ++ void print() { ++ PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"), ++ NextField::decode(data_)); ++ } ++ ++ private: ++ int data_; ++ ++ class TypeField: public BitField {}; ++ class NextField: public BitField {}; ++ ++ void init(Label* L, Type type); ++}; ++ ++ ++class Assembler : public AssemblerBase { ++ private: ++ // We check before assembling an instruction that there is sufficient ++ // space to write an instruction and its relocation information. ++ // The relocation writer's position must be kGap bytes above the end of ++ // the generated instructions. This leaves enough space for the ++ // longest possible ia32 instruction, 15 bytes, and the longest possible ++ // relocation information encoding, RelocInfoWriter::kMaxLength == 16. ++ // (There is a 15 byte limit on ia32 instruction length that rules out some ++ // otherwise valid instructions.) ++ // This allows for a single, fast space check per instruction. ++ static const int kGap = 32; ++ ++ public: ++ // Create an assembler. Instructions and relocation information are emitted ++ // into a buffer, with the instructions starting from the beginning and the ++ // relocation information starting from the end of the buffer. See CodeDesc ++ // for a detailed comment on the layout (globals.h). ++ // ++ // If the provided buffer is NULL, the assembler allocates and grows its own ++ // buffer, and buffer_size determines the initial buffer size. The buffer is ++ // owned by the assembler and deallocated upon destruction of the assembler. ++ // ++ // If the provided buffer is not NULL, the assembler uses the provided buffer ++ // for code generation and assumes its size to be buffer_size. If the buffer ++ // is too small, a fatal error occurs. No deallocation of the buffer is done ++ // upon destruction of the assembler. ++ Assembler(Isolate* isolate, void* buffer, int buffer_size) ++ : Assembler(IsolateData(isolate), buffer, buffer_size) {} ++ Assembler(IsolateData isolate_data, void* buffer, int buffer_size); ++ virtual ~Assembler() { } ++ ++ // GetCode emits any pending (non-emitted) code and fills the descriptor ++ // desc. GetCode() is idempotent; it returns the same result if no other ++ // Assembler functions are invoked in between GetCode() calls. ++ void GetCode(CodeDesc* desc); ++ ++ // Read/Modify the code target in the branch/call instruction at pc. ++ // The isolate argument is unused (and may be nullptr) when skipping flushing. ++ inline static Address target_address_at(Address pc, Address constant_pool); ++ inline static void set_target_address_at( ++ Isolate* isolate, Address pc, Address constant_pool, Address target, ++ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); ++ static inline Address target_address_at(Address pc, Code* code); ++ static inline void set_target_address_at( ++ Isolate* isolate, Address pc, Code* code, Address target, ++ ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); ++ ++ // Return the code target address at a call site from the return address ++ // of that call in the instruction stream. ++ inline static Address target_address_from_return_address(Address pc); ++ ++ // This sets the branch destination (which is in the instruction on x86). ++ // This is for calls and branches within generated code. ++ inline static void deserialization_set_special_target_at( ++ Isolate* isolate, Address instruction_payload, Code* code, ++ Address target) { ++ set_target_address_at(isolate, instruction_payload, code, target); ++ } ++ ++ // This sets the internal reference at the pc. ++ inline static void deserialization_set_target_internal_reference_at( ++ Isolate* isolate, Address pc, Address target, ++ RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE); ++ ++ static const int kSpecialTargetSize = kPointerSize; ++ ++ // Distance between the address of the code target in the call instruction ++ // and the return address ++ static const int kCallTargetAddressOffset = kPointerSize; ++ ++ static const int kCallInstructionLength = 5; ++ ++ // The debug break slot must be able to contain a call instruction. ++ static const int kDebugBreakSlotLength = kCallInstructionLength; ++ ++ // Distance between start of patched debug break slot and the emitted address ++ // to jump to. ++ static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32. ++ ++ // One byte opcode for test al, 0xXX. ++ static const byte kTestAlByte = 0xA8; ++ // One byte opcode for nop. ++ static const byte kNopByte = 0x90; ++ ++ // One byte opcode for a short unconditional jump. ++ static const byte kJmpShortOpcode = 0xEB; ++ // One byte prefix for a short conditional jump. ++ static const byte kJccShortPrefix = 0x70; ++ static const byte kJncShortOpcode = kJccShortPrefix | not_carry; ++ static const byte kJcShortOpcode = kJccShortPrefix | carry; ++ static const byte kJnzShortOpcode = kJccShortPrefix | not_zero; ++ static const byte kJzShortOpcode = kJccShortPrefix | zero; ++ ++ ++ // --------------------------------------------------------------------------- ++ // Code generation ++ // ++ // - function names correspond one-to-one to ia32 instruction mnemonics ++ // - unless specified otherwise, instructions operate on 32bit operands ++ // - instructions on 8bit (byte) operands/registers have a trailing '_b' ++ // - instructions on 16bit (word) operands/registers have a trailing '_w' ++ // - naming conflicts with C++ keywords are resolved via a trailing '_' ++ ++ // NOTE ON INTERFACE: Currently, the interface is not very consistent ++ // in the sense that some operations (e.g. mov()) can be called in more ++ // the one way to generate the same instruction: The Register argument ++ // can in some cases be replaced with an Operand(Register) argument. ++ // This should be cleaned up and made more orthogonal. The questions ++ // is: should we always use Operands instead of Registers where an ++ // Operand is possible, or should we have a Register (overloaded) form ++ // instead? We must be careful to make sure that the selected instruction ++ // is obvious from the parameters to avoid hard-to-find code generation ++ // bugs. ++ ++ // Insert the smallest number of nop instructions ++ // possible to align the pc offset to a multiple ++ // of m. m must be a power of 2. ++ void Align(int m); ++ // Insert the smallest number of zero bytes possible to align the pc offset ++ // to a mulitple of m. m must be a power of 2 (>= 2). ++ void DataAlign(int m); ++ void Nop(int bytes = 1); ++ // Aligns code to something that's optimal for a jump target for the platform. ++ void CodeTargetAlign(); ++ ++ // Stack ++ void pushad(); ++ void popad(); ++ ++ void pushfd(); ++ void popfd(); ++ ++ void push(const Immediate& x); ++ void push_imm32(int32_t imm32); ++ void push(Register src); ++ void push(const Operand& src); ++ ++ void pop(Register dst); ++ void pop(const Operand& dst); ++ ++ void enter(const Immediate& size); ++ void leave(); ++ ++ // Moves ++ void mov_b(Register dst, Register src) { mov_b(dst, Operand(src)); } ++ void mov_b(Register dst, const Operand& src); ++ void mov_b(Register dst, int8_t imm8) { mov_b(Operand(dst), imm8); } ++ void mov_b(const Operand& dst, int8_t imm8); ++ void mov_b(const Operand& dst, const Immediate& src); ++ void mov_b(const Operand& dst, Register src); ++ ++ void mov_w(Register dst, const Operand& src); ++ void mov_w(const Operand& dst, Register src); ++ void mov_w(const Operand& dst, int16_t imm16); ++ void mov_w(const Operand& dst, const Immediate& src); ++ ++ ++ void mov(Register dst, int32_t imm32); ++ void mov(Register dst, const Immediate& x); ++ void mov(Register dst, Handle handle); ++ void mov(Register dst, const Operand& src); ++ void mov(Register dst, Register src); ++ void mov(const Operand& dst, const Immediate& x); ++ void mov(const Operand& dst, Handle handle); ++ void mov(const Operand& dst, Register src); ++ ++ void movsx_b(Register dst, Register src) { movsx_b(dst, Operand(src)); } ++ void movsx_b(Register dst, const Operand& src); ++ ++ void movsx_w(Register dst, Register src) { movsx_w(dst, Operand(src)); } ++ void movsx_w(Register dst, const Operand& src); ++ ++ void movzx_b(Register dst, Register src) { movzx_b(dst, Operand(src)); } ++ void movzx_b(Register dst, const Operand& src); ++ ++ void movzx_w(Register dst, Register src) { movzx_w(dst, Operand(src)); } ++ void movzx_w(Register dst, const Operand& src); ++ ++ // Flag management. ++ void cld(); ++ ++ // Repetitive string instructions. ++ void rep_movs(); ++ void rep_stos(); ++ void stos(); ++ ++ // Exchange ++ void xchg(Register dst, Register src); ++ void xchg(Register dst, const Operand& src); ++ void xchg_b(Register reg, const Operand& op); ++ void xchg_w(Register reg, const Operand& op); ++ ++ // Lock prefix ++ void lock(); ++ ++ // CompareExchange ++ void cmpxchg(const Operand& dst, Register src); ++ void cmpxchg_b(const Operand& dst, Register src); ++ void cmpxchg_w(const Operand& dst, Register src); ++ ++ // Arithmetics ++ void adc(Register dst, int32_t imm32); ++ void adc(Register dst, const Operand& src); ++ ++ void add(Register dst, Register src) { add(dst, Operand(src)); } ++ void add(Register dst, const Operand& src); ++ void add(const Operand& dst, Register src); ++ void add(Register dst, const Immediate& imm) { add(Operand(dst), imm); } ++ void add(const Operand& dst, const Immediate& x); ++ ++ void and_(Register dst, int32_t imm32); ++ void and_(Register dst, const Immediate& x); ++ void and_(Register dst, Register src) { and_(dst, Operand(src)); } ++ void and_(Register dst, const Operand& src); ++ void and_(const Operand& dst, Register src); ++ void and_(const Operand& dst, const Immediate& x); ++ ++ void cmpb(Register reg, Immediate imm8) { cmpb(Operand(reg), imm8); } ++ void cmpb(const Operand& op, Immediate imm8); ++ void cmpb(Register reg, const Operand& op); ++ void cmpb(const Operand& op, Register reg); ++ void cmpb(Register dst, Register src) { cmpb(Operand(dst), src); } ++ void cmpb_al(const Operand& op); ++ void cmpw_ax(const Operand& op); ++ void cmpw(const Operand& dst, Immediate src); ++ void cmpw(Register dst, Immediate src) { cmpw(Operand(dst), src); } ++ void cmpw(Register dst, const Operand& src); ++ void cmpw(Register dst, Register src) { cmpw(Operand(dst), src); } ++ void cmpw(const Operand& dst, Register src); ++ void cmp(Register reg, int32_t imm32); ++ void cmp(Register reg, Handle handle); ++ void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); } ++ void cmp(Register reg, const Operand& op); ++ void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); } ++ void cmp(const Operand& op, Register reg); ++ void cmp(const Operand& op, const Immediate& imm); ++ void cmp(const Operand& op, Handle handle); ++ ++ void dec_b(Register dst); ++ void dec_b(const Operand& dst); ++ ++ void dec(Register dst); ++ void dec(const Operand& dst); ++ ++ void cdq(); ++ ++ void idiv(Register src) { idiv(Operand(src)); } ++ void idiv(const Operand& src); ++ void div(Register src) { div(Operand(src)); } ++ void div(const Operand& src); ++ ++ // Signed multiply instructions. ++ void imul(Register src); // edx:eax = eax * src. ++ void imul(Register dst, Register src) { imul(dst, Operand(src)); } ++ void imul(Register dst, const Operand& src); // dst = dst * src. ++ void imul(Register dst, Register src, int32_t imm32); // dst = src * imm32. ++ void imul(Register dst, const Operand& src, int32_t imm32); ++ ++ void inc(Register dst); ++ void inc(const Operand& dst); ++ ++ void lea(Register dst, const Operand& src); ++ ++ // Unsigned multiply instruction. ++ void mul(Register src); // edx:eax = eax * reg. ++ ++ void neg(Register dst); ++ void neg(const Operand& dst); ++ ++ void not_(Register dst); ++ void not_(const Operand& dst); ++ ++ void or_(Register dst, int32_t imm32); ++ void or_(Register dst, Register src) { or_(dst, Operand(src)); } ++ void or_(Register dst, const Operand& src); ++ void or_(const Operand& dst, Register src); ++ void or_(Register dst, const Immediate& imm) { or_(Operand(dst), imm); } ++ void or_(const Operand& dst, const Immediate& x); ++ ++ void rcl(Register dst, uint8_t imm8); ++ void rcr(Register dst, uint8_t imm8); ++ ++ void ror(Register dst, uint8_t imm8) { ror(Operand(dst), imm8); } ++ void ror(const Operand& dst, uint8_t imm8); ++ void ror_cl(Register dst) { ror_cl(Operand(dst)); } ++ void ror_cl(const Operand& dst); ++ ++ void sar(Register dst, uint8_t imm8) { sar(Operand(dst), imm8); } ++ void sar(const Operand& dst, uint8_t imm8); ++ void sar_cl(Register dst) { sar_cl(Operand(dst)); } ++ void sar_cl(const Operand& dst); ++ ++ void sbb(Register dst, const Operand& src); ++ ++ void shl(Register dst, uint8_t imm8) { shl(Operand(dst), imm8); } ++ void shl(const Operand& dst, uint8_t imm8); ++ void shl_cl(Register dst) { shl_cl(Operand(dst)); } ++ void shl_cl(const Operand& dst); ++ void shld(Register dst, Register src, uint8_t shift); ++ void shld_cl(Register dst, Register src); ++ ++ void shr(Register dst, uint8_t imm8) { shr(Operand(dst), imm8); } ++ void shr(const Operand& dst, uint8_t imm8); ++ void shr_cl(Register dst) { shr_cl(Operand(dst)); } ++ void shr_cl(const Operand& dst); ++ void shrd(Register dst, Register src, uint8_t shift); ++ void shrd_cl(Register dst, Register src) { shrd_cl(Operand(dst), src); } ++ void shrd_cl(const Operand& dst, Register src); ++ ++ void sub(Register dst, const Immediate& imm) { sub(Operand(dst), imm); } ++ void sub(const Operand& dst, const Immediate& x); ++ void sub(Register dst, Register src) { sub(dst, Operand(src)); } ++ void sub(Register dst, const Operand& src); ++ void sub(const Operand& dst, Register src); ++ ++ void test(Register reg, const Immediate& imm); ++ void test(Register reg0, Register reg1) { test(reg0, Operand(reg1)); } ++ void test(Register reg, const Operand& op); ++ void test(const Operand& op, const Immediate& imm); ++ void test(const Operand& op, Register reg) { test(reg, op); } ++ void test_b(Register reg, const Operand& op); ++ void test_b(Register reg, Immediate imm8); ++ void test_b(const Operand& op, Immediate imm8); ++ void test_b(const Operand& op, Register reg) { test_b(reg, op); } ++ void test_b(Register dst, Register src) { test_b(dst, Operand(src)); } ++ void test_w(Register reg, const Operand& op); ++ void test_w(Register reg, Immediate imm16); ++ void test_w(const Operand& op, Immediate imm16); ++ void test_w(const Operand& op, Register reg) { test_w(reg, op); } ++ void test_w(Register dst, Register src) { test_w(dst, Operand(src)); } ++ ++ void xor_(Register dst, int32_t imm32); ++ void xor_(Register dst, Register src) { xor_(dst, Operand(src)); } ++ void xor_(Register dst, const Operand& src); ++ void xor_(const Operand& dst, Register src); ++ void xor_(Register dst, const Immediate& imm) { xor_(Operand(dst), imm); } ++ void xor_(const Operand& dst, const Immediate& x); ++ ++ // Bit operations. ++ void bt(const Operand& dst, Register src); ++ void bts(Register dst, Register src) { bts(Operand(dst), src); } ++ void bts(const Operand& dst, Register src); ++ void bsr(Register dst, Register src) { bsr(dst, Operand(src)); } ++ void bsr(Register dst, const Operand& src); ++ void bsf(Register dst, Register src) { bsf(dst, Operand(src)); } ++ void bsf(Register dst, const Operand& src); ++ ++ // Miscellaneous ++ void hlt(); ++ void int3(); ++ void nop(); ++ void ret(int imm16); ++ void ud2(); ++ ++ // Label operations & relative jumps (PPUM Appendix D) ++ // ++ // Takes a branch opcode (cc) and a label (L) and generates ++ // either a backward branch or a forward branch and links it ++ // to the label fixup chain. Usage: ++ // ++ // Label L; // unbound label ++ // j(cc, &L); // forward branch to unbound label ++ // bind(&L); // bind label to the current pc ++ // j(cc, &L); // backward branch to bound label ++ // bind(&L); // illegal: a label may be bound only once ++ // ++ // Note: The same Label can be used for forward and backward branches ++ // but it may be bound only once. ++ ++ void bind(Label* L); // binds an unbound label L to the current code position ++ ++ // Calls ++ void call(Label* L); ++ void call(byte* entry, RelocInfo::Mode rmode); ++ int CallSize(const Operand& adr); ++ void call(Register reg) { call(Operand(reg)); } ++ void call(const Operand& adr); ++ int CallSize(Handle code, RelocInfo::Mode mode); ++ void call(Handle code, ++ RelocInfo::Mode rmode, ++ TypeFeedbackId id = TypeFeedbackId::None()); ++ ++ // Jumps ++ // unconditional jump to L ++ void jmp(Label* L, Label::Distance distance = Label::kFar); ++ void jmp(byte* entry, RelocInfo::Mode rmode); ++ void jmp(Register reg) { jmp(Operand(reg)); } ++ void jmp(const Operand& adr); ++ void jmp(Handle code, RelocInfo::Mode rmode); ++ ++ // Conditional jumps ++ void j(Condition cc, ++ Label* L, ++ Label::Distance distance = Label::kFar); ++ void j(Condition cc, byte* entry, RelocInfo::Mode rmode); ++ void j(Condition cc, Handle code, ++ RelocInfo::Mode rmode = RelocInfo::CODE_TARGET); ++ ++ // Floating-point operations ++ void fld(int i); ++ void fstp(int i); ++ ++ void fld1(); ++ void fldz(); ++ void fldpi(); ++ void fldln2(); ++ ++ void fld_s(const Operand& adr); ++ void fld_d(const Operand& adr); ++ ++ void fstp_s(const Operand& adr); ++ void fst_s(const Operand& adr); ++ void fstp_d(const Operand& adr); ++ void fst_d(const Operand& adr); ++ ++ void fild_s(const Operand& adr); ++ void fild_d(const Operand& adr); ++ ++ void fist_s(const Operand& adr); ++ ++ void fistp_s(const Operand& adr); ++ void fistp_d(const Operand& adr); ++ ++ // The fisttp instructions require SSE3. ++ void fisttp_s(const Operand& adr); ++ void fisttp_d(const Operand& adr); ++ ++ void fabs(); ++ void fchs(); ++ void fsqrt(); ++ void fcos(); ++ void fsin(); ++ void fptan(); ++ void fyl2x(); ++ void f2xm1(); ++ void fscale(); ++ void fninit(); ++ ++ void fadd(int i); ++ void fadd_i(int i); ++ void fadd_d(const Operand& adr); ++ void fsub(int i); ++ void fsub_i(int i); ++ void fsub_d(const Operand& adr); ++ void fsubr_d(const Operand& adr); ++ void fmul(int i); ++ void fmul_d(const Operand& adr); ++ void fmul_i(int i); ++ void fdiv(int i); ++ void fdiv_d(const Operand& adr); ++ void fdivr_d(const Operand& adr); ++ void fdiv_i(int i); ++ ++ void fisub_s(const Operand& adr); ++ ++ void faddp(int i = 1); ++ void fsubp(int i = 1); ++ void fsubr(int i = 1); ++ void fsubrp(int i = 1); ++ void fmulp(int i = 1); ++ void fdivp(int i = 1); ++ void fprem(); ++ void fprem1(); ++ ++ void fxch(int i = 1); ++ void fincstp(); ++ void ffree(int i = 0); ++ ++ void ftst(); ++ void fxam(); ++ void fucomp(int i); ++ void fucompp(); ++ void fucomi(int i); ++ void fucomip(); ++ void fcompp(); ++ void fnstsw_ax(); ++ void fldcw(const Operand& adr); ++ void fnstcw(const Operand& adr); ++ void fwait(); ++ void fnclex(); ++ void fnsave(const Operand& adr); ++ void frstor(const Operand& adr); ++ ++ void frndint(); ++ ++ void sahf(); ++ void setcc(Condition cc, Register reg); ++ ++ void cpuid(); ++ ++ // TODO(lrn): Need SFENCE for movnt? ++ ++ // Check the code size generated from label to here. ++ int SizeOfCodeGeneratedSince(Label* label) { ++ return pc_offset() - label->pos(); ++ } ++ ++ // Mark address of a debug break slot. ++ void RecordDebugBreakSlot(RelocInfo::Mode mode); ++ ++ // Record a comment relocation entry that can be used by a disassembler. ++ // Use --code-comments to enable. ++ void RecordComment(const char* msg); ++ ++ // Record a deoptimization reason that can be used by a log or cpu profiler. ++ // Use --trace-deopt to enable. ++ void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position, ++ int id); ++ ++ // Writes a single byte or word of data in the code stream. Used for ++ // inline tables, e.g., jump-tables. ++ void db(uint8_t data); ++ void dd(uint32_t data); ++ void dq(uint64_t data); ++ void dp(uintptr_t data) { dd(data); } ++ void dd(Label* label); ++ ++ // Check if there is less than kGap bytes available in the buffer. ++ // If this is the case, we need to grow the buffer before emitting ++ // an instruction or relocation information. ++ inline bool buffer_overflow() const { ++ return pc_ >= reloc_info_writer.pos() - kGap; ++ } ++ ++ // Get the number of bytes available in the buffer. ++ inline int available_space() const { return reloc_info_writer.pos() - pc_; } ++ ++ static bool IsNop(Address addr); ++ ++ int relocation_writer_size() { ++ return (buffer_ + buffer_size_) - reloc_info_writer.pos(); ++ } ++ ++ // Avoid overflows for displacements etc. ++ static const int kMaximalBufferSize = 512*MB; ++ ++ byte byte_at(int pos) { return buffer_[pos]; } ++ void set_byte_at(int pos, byte value) { buffer_[pos] = value; } ++ ++ void PatchConstantPoolAccessInstruction(int pc_offset, int offset, ++ ConstantPoolEntry::Access access, ++ ConstantPoolEntry::Type type) { ++ // No embedded constant pool support. ++ UNREACHABLE(); ++ } ++ ++ protected: ++ byte* addr_at(int pos) { return buffer_ + pos; } ++ ++ ++ private: ++ uint32_t long_at(int pos) { ++ return *reinterpret_cast(addr_at(pos)); ++ } ++ void long_at_put(int pos, uint32_t x) { ++ *reinterpret_cast(addr_at(pos)) = x; ++ } ++ ++ // code emission ++ void GrowBuffer(); ++ inline void emit(uint32_t x); ++ inline void emit(Handle handle); ++ inline void emit(uint32_t x, ++ RelocInfo::Mode rmode, ++ TypeFeedbackId id = TypeFeedbackId::None()); ++ inline void emit(Handle code, ++ RelocInfo::Mode rmode, ++ TypeFeedbackId id = TypeFeedbackId::None()); ++ inline void emit(const Immediate& x); ++ inline void emit_b(Immediate x); ++ inline void emit_w(const Immediate& x); ++ inline void emit_q(uint64_t x); ++ ++ // Emit the code-object-relative offset of the label's position ++ inline void emit_code_relative_offset(Label* label); ++ ++ // instruction generation ++ void emit_arith_b(int op1, int op2, Register dst, int imm8); ++ ++ // Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81) ++ // with a given destination expression and an immediate operand. It attempts ++ // to use the shortest encoding possible. ++ // sel specifies the /n in the modrm byte (see the Intel PRM). ++ void emit_arith(int sel, Operand dst, const Immediate& x); ++ ++ void emit_operand(Register reg, const Operand& adr); ++ ++ void emit_label(Label* label); ++ ++ void emit_farith(int b1, int b2, int i); ++ ++ // labels ++ void print(Label* L); ++ void bind_to(Label* L, int pos); ++ ++ // displacements ++ inline Displacement disp_at(Label* L); ++ inline void disp_at_put(Label* L, Displacement disp); ++ inline void emit_disp(Label* L, Displacement::Type type); ++ inline void emit_near_disp(Label* L); ++ ++ // record reloc info for current pc_ ++ void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); ++ ++ friend class CodePatcher; ++ friend class EnsureSpace; ++ ++ // Internal reference positions, required for (potential) patching in ++ // GrowBuffer(); contains only those internal references whose labels ++ // are already bound. ++ std::deque internal_reference_positions_; ++ ++ // code generation ++ RelocInfoWriter reloc_info_writer; ++}; ++ ++ ++// Helper class that ensures that there is enough space for generating ++// instructions and relocation information. The constructor makes ++// sure that there is enough space and (in debug mode) the destructor ++// checks that we did not generate too much. ++class EnsureSpace BASE_EMBEDDED { ++ public: ++ explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) { ++ if (assembler_->buffer_overflow()) assembler_->GrowBuffer(); ++#ifdef DEBUG ++ space_before_ = assembler_->available_space(); ++#endif ++ } ++ ++#ifdef DEBUG ++ ~EnsureSpace() { ++ int bytes_generated = space_before_ - assembler_->available_space(); ++ DCHECK(bytes_generated < assembler_->kGap); ++ } ++#endif ++ ++ private: ++ Assembler* assembler_; ++#ifdef DEBUG ++ int space_before_; ++#endif ++}; ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_ASSEMBLER_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87-inl.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87-inl.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/assembler-x87-inl.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/assembler-x87-inl.h 2017-12-25 17:42:57.219465588 +0100 +@@ -0,0 +1,546 @@ ++// Copyright (c) 1994-2006 Sun Microsystems Inc. ++// All Rights Reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are ++// met: ++// ++// - Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// ++// - Redistribution in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in the ++// documentation and/or other materials provided with the distribution. ++// ++// - Neither the name of Sun Microsystems or the names of contributors may ++// be used to endorse or promote products derived from this software without ++// specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++// The original source code covered by the above license above has been ++// modified significantly by Google Inc. ++// Copyright 2012 the V8 project authors. All rights reserved. ++ ++// A light-weight IA32 Assembler. ++ ++#ifndef V8_X87_ASSEMBLER_X87_INL_H_ ++#define V8_X87_ASSEMBLER_X87_INL_H_ ++ ++#include "src/x87/assembler-x87.h" ++ ++#include "src/assembler.h" ++#include "src/debug/debug.h" ++#include "src/objects-inl.h" ++ ++namespace v8 { ++namespace internal { ++ ++bool CpuFeatures::SupportsCrankshaft() { return true; } ++ ++bool CpuFeatures::SupportsWasmSimd128() { return false; } ++ ++static const byte kCallOpcode = 0xE8; ++static const int kNoCodeAgeSequenceLength = 5; ++ ++ ++// The modes possibly affected by apply must be in kApplyMask. ++void RelocInfo::apply(intptr_t delta) { ++ if (IsRuntimeEntry(rmode_) || IsCodeTarget(rmode_)) { ++ int32_t* p = reinterpret_cast(pc_); ++ *p -= delta; // Relocate entry. ++ } else if (IsCodeAgeSequence(rmode_)) { ++ if (*pc_ == kCallOpcode) { ++ int32_t* p = reinterpret_cast(pc_ + 1); ++ *p -= delta; // Relocate entry. ++ } ++ } else if (IsDebugBreakSlot(rmode_) && IsPatchedDebugBreakSlotSequence()) { ++ // Special handling of a debug break slot when a break point is set (call ++ // instruction has been inserted). ++ int32_t* p = reinterpret_cast( ++ pc_ + Assembler::kPatchDebugBreakSlotAddressOffset); ++ *p -= delta; // Relocate entry. ++ } else if (IsInternalReference(rmode_)) { ++ // absolute code pointer inside code object moves with the code object. ++ int32_t* p = reinterpret_cast(pc_); ++ *p += delta; // Relocate entry. ++ } ++} ++ ++ ++Address RelocInfo::target_address() { ++ DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); ++ return Assembler::target_address_at(pc_, host_); ++} ++ ++Address RelocInfo::target_address_address() { ++ DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) ++ || rmode_ == EMBEDDED_OBJECT ++ || rmode_ == EXTERNAL_REFERENCE); ++ return reinterpret_cast
(pc_); ++} ++ ++ ++Address RelocInfo::constant_pool_entry_address() { ++ UNREACHABLE(); ++} ++ ++ ++int RelocInfo::target_address_size() { ++ return Assembler::kSpecialTargetSize; ++} ++ ++HeapObject* RelocInfo::target_object() { ++ DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); ++ return HeapObject::cast(Memory::Object_at(pc_)); ++} ++ ++Handle RelocInfo::target_object_handle(Assembler* origin) { ++ DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); ++ return Handle::cast(Memory::Object_Handle_at(pc_)); ++} ++ ++void RelocInfo::set_target_object(HeapObject* target, ++ WriteBarrierMode write_barrier_mode, ++ ICacheFlushMode icache_flush_mode) { ++ DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); ++ Memory::Object_at(pc_) = target; ++ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { ++ Assembler::FlushICache(target->GetIsolate(), pc_, sizeof(Address)); ++ } ++ if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) { ++ host()->GetHeap()->RecordWriteIntoCode(host(), this, target); ++ host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, ++ target); ++ } ++} ++ ++ ++Address RelocInfo::target_external_reference() { ++ DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); ++ return Memory::Address_at(pc_); ++} ++ ++ ++Address RelocInfo::target_internal_reference() { ++ DCHECK(rmode_ == INTERNAL_REFERENCE); ++ return Memory::Address_at(pc_); ++} ++ ++ ++Address RelocInfo::target_internal_reference_address() { ++ DCHECK(rmode_ == INTERNAL_REFERENCE); ++ return reinterpret_cast
(pc_); ++} ++ ++ ++Address RelocInfo::target_runtime_entry(Assembler* origin) { ++ DCHECK(IsRuntimeEntry(rmode_)); ++ return reinterpret_cast
(*reinterpret_cast(pc_)); ++} ++ ++void RelocInfo::set_target_runtime_entry(Isolate* isolate, Address target, ++ WriteBarrierMode write_barrier_mode, ++ ICacheFlushMode icache_flush_mode) { ++ DCHECK(IsRuntimeEntry(rmode_)); ++ if (target_address() != target) { ++ set_target_address(isolate, target, write_barrier_mode, icache_flush_mode); ++ } ++} ++ ++ ++Handle RelocInfo::target_cell_handle() { ++ DCHECK(rmode_ == RelocInfo::CELL); ++ Address address = Memory::Address_at(pc_); ++ return Handle(reinterpret_cast(address)); ++} ++ ++ ++Cell* RelocInfo::target_cell() { ++ DCHECK(rmode_ == RelocInfo::CELL); ++ return Cell::FromValueAddress(Memory::Address_at(pc_)); ++} ++ ++ ++void RelocInfo::set_target_cell(Cell* cell, ++ WriteBarrierMode write_barrier_mode, ++ ICacheFlushMode icache_flush_mode) { ++ DCHECK(cell->IsCell()); ++ DCHECK(rmode_ == RelocInfo::CELL); ++ Address address = cell->address() + Cell::kValueOffset; ++ Memory::Address_at(pc_) = address; ++ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { ++ Assembler::FlushICache(cell->GetIsolate(), pc_, sizeof(Address)); ++ } ++ if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) { ++ host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, ++ cell); ++ } ++} ++ ++Handle RelocInfo::code_age_stub_handle(Assembler* origin) { ++ DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); ++ DCHECK(*pc_ == kCallOpcode); ++ return Handle::cast(Memory::Object_Handle_at(pc_ + 1)); ++} ++ ++ ++Code* RelocInfo::code_age_stub() { ++ DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); ++ DCHECK(*pc_ == kCallOpcode); ++ return Code::GetCodeFromTargetAddress( ++ Assembler::target_address_at(pc_ + 1, host_)); ++} ++ ++ ++void RelocInfo::set_code_age_stub(Code* stub, ++ ICacheFlushMode icache_flush_mode) { ++ DCHECK(*pc_ == kCallOpcode); ++ DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); ++ Assembler::set_target_address_at(stub->GetIsolate(), pc_ + 1, host_, ++ stub->instruction_start(), ++ icache_flush_mode); ++} ++ ++ ++Address RelocInfo::debug_call_address() { ++ DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); ++ Address location = pc_ + Assembler::kPatchDebugBreakSlotAddressOffset; ++ return Assembler::target_address_at(location, host_); ++} ++ ++void RelocInfo::set_debug_call_address(Isolate* isolate, Address target) { ++ DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); ++ Address location = pc_ + Assembler::kPatchDebugBreakSlotAddressOffset; ++ Assembler::set_target_address_at(isolate, location, host_, target); ++ if (host() != NULL) { ++ Code* target_code = Code::GetCodeFromTargetAddress(target); ++ host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, ++ target_code); ++ } ++} ++ ++void RelocInfo::WipeOut(Isolate* isolate) { ++ if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) || ++ IsInternalReference(rmode_)) { ++ Memory::Address_at(pc_) = NULL; ++ } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) { ++ // Effectively write zero into the relocation. ++ Assembler::set_target_address_at(isolate, pc_, host_, ++ pc_ + sizeof(int32_t)); ++ } else { ++ UNREACHABLE(); ++ } ++} ++ ++template ++void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { ++ RelocInfo::Mode mode = rmode(); ++ if (mode == RelocInfo::EMBEDDED_OBJECT) { ++ visitor->VisitEmbeddedPointer(host(), this); ++ Assembler::FlushICache(isolate, pc_, sizeof(Address)); ++ } else if (RelocInfo::IsCodeTarget(mode)) { ++ visitor->VisitCodeTarget(host(), this); ++ } else if (mode == RelocInfo::CELL) { ++ visitor->VisitCellPointer(host(), this); ++ } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { ++ visitor->VisitExternalReference(host(), this); ++ } else if (mode == RelocInfo::INTERNAL_REFERENCE) { ++ visitor->VisitInternalReference(host(), this); ++ } else if (RelocInfo::IsCodeAgeSequence(mode)) { ++ visitor->VisitCodeAgeSequence(host(), this); ++ } else if (RelocInfo::IsDebugBreakSlot(mode) && ++ IsPatchedDebugBreakSlotSequence()) { ++ visitor->VisitDebugTarget(host(), this); ++ } else if (IsRuntimeEntry(mode)) { ++ visitor->VisitRuntimeEntry(host(), this); ++ } ++} ++ ++ ++template ++void RelocInfo::Visit(Heap* heap) { ++ RelocInfo::Mode mode = rmode(); ++ if (mode == RelocInfo::EMBEDDED_OBJECT) { ++ StaticVisitor::VisitEmbeddedPointer(heap, this); ++ Assembler::FlushICache(heap->isolate(), pc_, sizeof(Address)); ++ } else if (RelocInfo::IsCodeTarget(mode)) { ++ StaticVisitor::VisitCodeTarget(heap, this); ++ } else if (mode == RelocInfo::CELL) { ++ StaticVisitor::VisitCell(heap, this); ++ } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { ++ StaticVisitor::VisitExternalReference(this); ++ } else if (mode == RelocInfo::INTERNAL_REFERENCE) { ++ StaticVisitor::VisitInternalReference(this); ++ } else if (RelocInfo::IsCodeAgeSequence(mode)) { ++ StaticVisitor::VisitCodeAgeSequence(heap, this); ++ } else if (RelocInfo::IsDebugBreakSlot(mode) && ++ IsPatchedDebugBreakSlotSequence()) { ++ StaticVisitor::VisitDebugTarget(heap, this); ++ } else if (IsRuntimeEntry(mode)) { ++ StaticVisitor::VisitRuntimeEntry(this); ++ } ++} ++ ++ ++ ++Immediate::Immediate(int x) { ++ x_ = x; ++ rmode_ = RelocInfo::NONE32; ++} ++ ++Immediate::Immediate(Address x, RelocInfo::Mode rmode) { ++ x_ = reinterpret_cast(x); ++ rmode_ = rmode; ++} ++ ++Immediate::Immediate(const ExternalReference& ext) { ++ x_ = reinterpret_cast(ext.address()); ++ rmode_ = RelocInfo::EXTERNAL_REFERENCE; ++} ++ ++ ++Immediate::Immediate(Label* internal_offset) { ++ x_ = reinterpret_cast(internal_offset); ++ rmode_ = RelocInfo::INTERNAL_REFERENCE; ++} ++ ++ ++Immediate::Immediate(Handle handle) { ++ AllowDeferredHandleDereference using_raw_address; ++ // Verify all Objects referred by code are NOT in new space. ++ Object* obj = *handle; ++ if (obj->IsHeapObject()) { ++ x_ = reinterpret_cast(handle.location()); ++ rmode_ = RelocInfo::EMBEDDED_OBJECT; ++ } else { ++ // no relocation needed ++ x_ = reinterpret_cast(obj); ++ rmode_ = RelocInfo::NONE32; ++ } ++} ++ ++ ++Immediate::Immediate(Smi* value) { ++ x_ = reinterpret_cast(value); ++ rmode_ = RelocInfo::NONE32; ++} ++ ++ ++Immediate::Immediate(Address addr) { ++ x_ = reinterpret_cast(addr); ++ rmode_ = RelocInfo::NONE32; ++} ++ ++ ++void Assembler::emit(uint32_t x) { ++ *reinterpret_cast(pc_) = x; ++ pc_ += sizeof(uint32_t); ++} ++ ++ ++void Assembler::emit_q(uint64_t x) { ++ *reinterpret_cast(pc_) = x; ++ pc_ += sizeof(uint64_t); ++} ++ ++ ++void Assembler::emit(Handle handle) { ++ AllowDeferredHandleDereference heap_object_check; ++ // Verify all Objects referred by code are NOT in new space. ++ Object* obj = *handle; ++ if (obj->IsHeapObject()) { ++ emit(reinterpret_cast(handle.location()), ++ RelocInfo::EMBEDDED_OBJECT); ++ } else { ++ // no relocation needed ++ emit(reinterpret_cast(obj)); ++ } ++} ++ ++ ++void Assembler::emit(uint32_t x, RelocInfo::Mode rmode, TypeFeedbackId id) { ++ if (rmode == RelocInfo::CODE_TARGET && !id.IsNone()) { ++ RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, id.ToInt()); ++ } else if (!RelocInfo::IsNone(rmode) ++ && rmode != RelocInfo::CODE_AGE_SEQUENCE) { ++ RecordRelocInfo(rmode); ++ } ++ emit(x); ++} ++ ++ ++void Assembler::emit(Handle code, ++ RelocInfo::Mode rmode, ++ TypeFeedbackId id) { ++ AllowDeferredHandleDereference embedding_raw_address; ++ emit(reinterpret_cast(code.location()), rmode, id); ++} ++ ++ ++void Assembler::emit(const Immediate& x) { ++ if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) { ++ Label* label = reinterpret_cast(x.x_); ++ emit_code_relative_offset(label); ++ return; ++ } ++ if (!RelocInfo::IsNone(x.rmode_)) RecordRelocInfo(x.rmode_); ++ emit(x.x_); ++} ++ ++ ++void Assembler::emit_code_relative_offset(Label* label) { ++ if (label->is_bound()) { ++ int32_t pos; ++ pos = label->pos() + Code::kHeaderSize - kHeapObjectTag; ++ emit(pos); ++ } else { ++ emit_disp(label, Displacement::CODE_RELATIVE); ++ } ++} ++ ++void Assembler::emit_b(Immediate x) { ++ DCHECK(x.is_int8() || x.is_uint8()); ++ uint8_t value = static_cast(x.x_); ++ *pc_++ = value; ++} ++ ++void Assembler::emit_w(const Immediate& x) { ++ DCHECK(RelocInfo::IsNone(x.rmode_)); ++ uint16_t value = static_cast(x.x_); ++ reinterpret_cast(pc_)[0] = value; ++ pc_ += sizeof(uint16_t); ++} ++ ++ ++Address Assembler::target_address_at(Address pc, Address constant_pool) { ++ return pc + sizeof(int32_t) + *reinterpret_cast(pc); ++} ++ ++ ++void Assembler::set_target_address_at(Isolate* isolate, Address pc, ++ Address constant_pool, Address target, ++ ICacheFlushMode icache_flush_mode) { ++ DCHECK_IMPLIES(isolate == nullptr, icache_flush_mode == SKIP_ICACHE_FLUSH); ++ int32_t* p = reinterpret_cast(pc); ++ *p = target - (pc + sizeof(int32_t)); ++ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { ++ Assembler::FlushICache(isolate, p, sizeof(int32_t)); ++ } ++} ++ ++Address Assembler::target_address_at(Address pc, Code* code) { ++ Address constant_pool = code ? code->constant_pool() : NULL; ++ return target_address_at(pc, constant_pool); ++} ++ ++void Assembler::set_target_address_at(Isolate* isolate, Address pc, Code* code, ++ Address target, ++ ICacheFlushMode icache_flush_mode) { ++ Address constant_pool = code ? code->constant_pool() : NULL; ++ set_target_address_at(isolate, pc, constant_pool, target, icache_flush_mode); ++} ++ ++Address Assembler::target_address_from_return_address(Address pc) { ++ return pc - kCallTargetAddressOffset; ++} ++ ++ ++Displacement Assembler::disp_at(Label* L) { ++ return Displacement(long_at(L->pos())); ++} ++ ++ ++void Assembler::disp_at_put(Label* L, Displacement disp) { ++ long_at_put(L->pos(), disp.data()); ++} ++ ++ ++void Assembler::emit_disp(Label* L, Displacement::Type type) { ++ Displacement disp(L, type); ++ L->link_to(pc_offset()); ++ emit(static_cast(disp.data())); ++} ++ ++ ++void Assembler::emit_near_disp(Label* L) { ++ byte disp = 0x00; ++ if (L->is_near_linked()) { ++ int offset = L->near_link_pos() - pc_offset(); ++ DCHECK(is_int8(offset)); ++ disp = static_cast(offset & 0xFF); ++ } ++ L->link_to(pc_offset(), Label::kNear); ++ *pc_++ = disp; ++} ++ ++ ++void Assembler::deserialization_set_target_internal_reference_at( ++ Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) { ++ Memory::Address_at(pc) = target; ++} ++ ++ ++void Operand::set_modrm(int mod, Register rm) { ++ DCHECK((mod & -4) == 0); ++ buf_[0] = mod << 6 | rm.code(); ++ len_ = 1; ++} ++ ++ ++void Operand::set_sib(ScaleFactor scale, Register index, Register base) { ++ DCHECK(len_ == 1); ++ DCHECK((scale & -4) == 0); ++ // Use SIB with no index register only for base esp. ++ DCHECK(!index.is(esp) || base.is(esp)); ++ buf_[1] = scale << 6 | index.code() << 3 | base.code(); ++ len_ = 2; ++} ++ ++ ++void Operand::set_disp8(int8_t disp) { ++ DCHECK(len_ == 1 || len_ == 2); ++ *reinterpret_cast(&buf_[len_++]) = disp; ++} ++ ++ ++void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) { ++ DCHECK(len_ == 1 || len_ == 2); ++ int32_t* p = reinterpret_cast(&buf_[len_]); ++ *p = disp; ++ len_ += sizeof(int32_t); ++ rmode_ = rmode; ++} ++ ++Operand::Operand(Register reg) { ++ // reg ++ set_modrm(3, reg); ++} ++ ++ ++Operand::Operand(int32_t disp, RelocInfo::Mode rmode) { ++ // [disp/r] ++ set_modrm(0, ebp); ++ set_dispr(disp, rmode); ++} ++ ++ ++Operand::Operand(Immediate imm) { ++ // [disp/r] ++ set_modrm(0, ebp); ++ set_dispr(imm.x_, imm.rmode_); ++} ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_ASSEMBLER_X87_INL_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/codegen-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/codegen-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/codegen-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/codegen-x87.cc 2017-12-25 17:42:57.221465559 +0100 +@@ -0,0 +1,381 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "src/x87/codegen-x87.h" ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/codegen.h" ++#include "src/heap/heap.h" ++#include "src/macro-assembler.h" ++ ++namespace v8 { ++namespace internal { ++ ++ ++// ------------------------------------------------------------------------- ++// Platform-specific RuntimeCallHelper functions. ++ ++void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { ++ masm->EnterFrame(StackFrame::INTERNAL); ++ DCHECK(!masm->has_frame()); ++ masm->set_has_frame(true); ++} ++ ++ ++void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { ++ masm->LeaveFrame(StackFrame::INTERNAL); ++ DCHECK(masm->has_frame()); ++ masm->set_has_frame(false); ++} ++ ++ ++#define __ masm. ++ ++ ++UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { ++ size_t actual_size; ++ // Allocate buffer in executable space. ++ byte* buffer = ++ static_cast(base::OS::Allocate(1 * KB, &actual_size, true)); ++ if (buffer == nullptr) return nullptr; ++ ++ MacroAssembler masm(isolate, buffer, static_cast(actual_size), ++ CodeObjectRequired::kNo); ++ // Load double input into registers. ++ __ fld_d(MemOperand(esp, 4)); ++ __ X87SetFPUCW(0x027F); ++ __ fsqrt(); ++ __ X87SetFPUCW(0x037F); ++ __ Ret(); ++ ++ CodeDesc desc; ++ masm.GetCode(&desc); ++ DCHECK(!RelocInfo::RequiresRelocation(isolate, desc)); ++ ++ Assembler::FlushICache(isolate, buffer, actual_size); ++ base::OS::ProtectCode(buffer, actual_size); ++ return FUNCTION_CAST(buffer); ++} ++ ++ ++// Helper functions for CreateMemMoveFunction. ++#undef __ ++#define __ ACCESS_MASM(masm) ++ ++enum Direction { FORWARD, BACKWARD }; ++enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED }; ++ ++ ++void MemMoveEmitPopAndReturn(MacroAssembler* masm) { ++ __ pop(esi); ++ __ pop(edi); ++ __ ret(0); ++} ++ ++ ++#undef __ ++#define __ masm. ++ ++ ++class LabelConverter { ++ public: ++ explicit LabelConverter(byte* buffer) : buffer_(buffer) {} ++ int32_t address(Label* l) const { ++ return reinterpret_cast(buffer_) + l->pos(); ++ } ++ private: ++ byte* buffer_; ++}; ++ ++ ++MemMoveFunction CreateMemMoveFunction(Isolate* isolate) { ++ size_t actual_size; ++ // Allocate buffer in executable space. ++ byte* buffer = ++ static_cast(base::OS::Allocate(1 * KB, &actual_size, true)); ++ if (buffer == nullptr) return nullptr; ++ MacroAssembler masm(isolate, buffer, static_cast(actual_size), ++ CodeObjectRequired::kNo); ++ LabelConverter conv(buffer); ++ ++ // Generated code is put into a fixed, unmovable buffer, and not into ++ // the V8 heap. We can't, and don't, refer to any relocatable addresses ++ // (e.g. the JavaScript nan-object). ++ ++ // 32-bit C declaration function calls pass arguments on stack. ++ ++ // Stack layout: ++ // esp[12]: Third argument, size. ++ // esp[8]: Second argument, source pointer. ++ // esp[4]: First argument, destination pointer. ++ // esp[0]: return address ++ ++ const int kDestinationOffset = 1 * kPointerSize; ++ const int kSourceOffset = 2 * kPointerSize; ++ const int kSizeOffset = 3 * kPointerSize; ++ ++ int stack_offset = 0; // Update if we change the stack height. ++ ++ Label backward, backward_much_overlap; ++ Label forward_much_overlap, small_size, medium_size, pop_and_return; ++ __ push(edi); ++ __ push(esi); ++ stack_offset += 2 * kPointerSize; ++ Register dst = edi; ++ Register src = esi; ++ Register count = ecx; ++ __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); ++ __ mov(src, Operand(esp, stack_offset + kSourceOffset)); ++ __ mov(count, Operand(esp, stack_offset + kSizeOffset)); ++ ++ __ cmp(dst, src); ++ __ j(equal, &pop_and_return); ++ ++ // No SSE2. ++ Label forward; ++ __ cmp(count, 0); ++ __ j(equal, &pop_and_return); ++ __ cmp(dst, src); ++ __ j(above, &backward); ++ __ jmp(&forward); ++ { ++ // Simple forward copier. ++ Label forward_loop_1byte, forward_loop_4byte; ++ __ bind(&forward_loop_4byte); ++ __ mov(eax, Operand(src, 0)); ++ __ sub(count, Immediate(4)); ++ __ add(src, Immediate(4)); ++ __ mov(Operand(dst, 0), eax); ++ __ add(dst, Immediate(4)); ++ __ bind(&forward); // Entry point. ++ __ cmp(count, 3); ++ __ j(above, &forward_loop_4byte); ++ __ bind(&forward_loop_1byte); ++ __ cmp(count, 0); ++ __ j(below_equal, &pop_and_return); ++ __ mov_b(eax, Operand(src, 0)); ++ __ dec(count); ++ __ inc(src); ++ __ mov_b(Operand(dst, 0), eax); ++ __ inc(dst); ++ __ jmp(&forward_loop_1byte); ++ } ++ { ++ // Simple backward copier. ++ Label backward_loop_1byte, backward_loop_4byte, entry_shortcut; ++ __ bind(&backward); ++ __ add(src, count); ++ __ add(dst, count); ++ __ cmp(count, 3); ++ __ j(below_equal, &entry_shortcut); ++ ++ __ bind(&backward_loop_4byte); ++ __ sub(src, Immediate(4)); ++ __ sub(count, Immediate(4)); ++ __ mov(eax, Operand(src, 0)); ++ __ sub(dst, Immediate(4)); ++ __ mov(Operand(dst, 0), eax); ++ __ cmp(count, 3); ++ __ j(above, &backward_loop_4byte); ++ __ bind(&backward_loop_1byte); ++ __ cmp(count, 0); ++ __ j(below_equal, &pop_and_return); ++ __ bind(&entry_shortcut); ++ __ dec(src); ++ __ dec(count); ++ __ mov_b(eax, Operand(src, 0)); ++ __ dec(dst); ++ __ mov_b(Operand(dst, 0), eax); ++ __ jmp(&backward_loop_1byte); ++ } ++ ++ __ bind(&pop_and_return); ++ MemMoveEmitPopAndReturn(&masm); ++ ++ CodeDesc desc; ++ masm.GetCode(&desc); ++ DCHECK(!RelocInfo::RequiresRelocation(isolate, desc)); ++ Assembler::FlushICache(isolate, buffer, actual_size); ++ base::OS::ProtectCode(buffer, actual_size); ++ // TODO(jkummerow): It would be nice to register this code creation event ++ // with the PROFILE / GDBJIT system. ++ return FUNCTION_CAST(buffer); ++} ++ ++ ++#undef __ ++ ++// ------------------------------------------------------------------------- ++// Code generators ++ ++#define __ ACCESS_MASM(masm) ++ ++void StringCharLoadGenerator::Generate(MacroAssembler* masm, ++ Factory* factory, ++ Register string, ++ Register index, ++ Register result, ++ Label* call_runtime) { ++ Label indirect_string_loaded; ++ __ bind(&indirect_string_loaded); ++ ++ // Fetch the instance type of the receiver into result register. ++ __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); ++ __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); ++ ++ // We need special handling for indirect strings. ++ Label check_sequential; ++ __ test(result, Immediate(kIsIndirectStringMask)); ++ __ j(zero, &check_sequential, Label::kNear); ++ ++ // Dispatch on the indirect string shape: slice or cons. ++ Label cons_string, thin_string; ++ __ and_(result, Immediate(kStringRepresentationMask)); ++ __ cmp(result, Immediate(kConsStringTag)); ++ __ j(equal, &cons_string, Label::kNear); ++ __ cmp(result, Immediate(kThinStringTag)); ++ __ j(equal, &thin_string, Label::kNear); ++ ++ // Handle slices. ++ __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset)); ++ __ SmiUntag(result); ++ __ add(index, result); ++ __ mov(string, FieldOperand(string, SlicedString::kParentOffset)); ++ __ jmp(&indirect_string_loaded); ++ ++ // Handle thin strings. ++ __ bind(&thin_string); ++ __ mov(string, FieldOperand(string, ThinString::kActualOffset)); ++ __ jmp(&indirect_string_loaded); ++ ++ // Handle cons strings. ++ // Check whether the right hand side is the empty string (i.e. if ++ // this is really a flat string in a cons string). If that is not ++ // the case we would rather go to the runtime system now to flatten ++ // the string. ++ __ bind(&cons_string); ++ __ cmp(FieldOperand(string, ConsString::kSecondOffset), ++ Immediate(factory->empty_string())); ++ __ j(not_equal, call_runtime); ++ __ mov(string, FieldOperand(string, ConsString::kFirstOffset)); ++ __ jmp(&indirect_string_loaded); ++ ++ // Distinguish sequential and external strings. Only these two string ++ // representations can reach here (slices and flat cons strings have been ++ // reduced to the underlying sequential or external string). ++ Label seq_string; ++ __ bind(&check_sequential); ++ STATIC_ASSERT(kSeqStringTag == 0); ++ __ test(result, Immediate(kStringRepresentationMask)); ++ __ j(zero, &seq_string, Label::kNear); ++ ++ // Handle external strings. ++ Label one_byte_external, done; ++ if (FLAG_debug_code) { ++ // Assert that we do not have a cons or slice (indirect strings) here. ++ // Sequential strings have already been ruled out. ++ __ test(result, Immediate(kIsIndirectStringMask)); ++ __ Assert(zero, kExternalStringExpectedButNotFound); ++ } ++ // Rule out short external strings. ++ STATIC_ASSERT(kShortExternalStringTag != 0); ++ __ test_b(result, Immediate(kShortExternalStringMask)); ++ __ j(not_zero, call_runtime); ++ // Check encoding. ++ STATIC_ASSERT(kTwoByteStringTag == 0); ++ __ test_b(result, Immediate(kStringEncodingMask)); ++ __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset)); ++ __ j(not_equal, &one_byte_external, Label::kNear); ++ // Two-byte string. ++ __ movzx_w(result, Operand(result, index, times_2, 0)); ++ __ jmp(&done, Label::kNear); ++ __ bind(&one_byte_external); ++ // One-byte string. ++ __ movzx_b(result, Operand(result, index, times_1, 0)); ++ __ jmp(&done, Label::kNear); ++ ++ // Dispatch on the encoding: one-byte or two-byte. ++ Label one_byte; ++ __ bind(&seq_string); ++ STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); ++ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); ++ __ test(result, Immediate(kStringEncodingMask)); ++ __ j(not_zero, &one_byte, Label::kNear); ++ ++ // Two-byte string. ++ // Load the two-byte character code into the result register. ++ __ movzx_w(result, FieldOperand(string, ++ index, ++ times_2, ++ SeqTwoByteString::kHeaderSize)); ++ __ jmp(&done, Label::kNear); ++ ++ // One-byte string. ++ // Load the byte into the result register. ++ __ bind(&one_byte); ++ __ movzx_b(result, FieldOperand(string, ++ index, ++ times_1, ++ SeqOneByteString::kHeaderSize)); ++ __ bind(&done); ++} ++ ++ ++#undef __ ++ ++ ++CodeAgingHelper::CodeAgingHelper(Isolate* isolate) { ++ USE(isolate); ++ DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); ++ CodePatcher patcher(isolate, young_sequence_.start(), ++ young_sequence_.length()); ++ patcher.masm()->push(ebp); ++ patcher.masm()->mov(ebp, esp); ++ patcher.masm()->push(esi); ++ patcher.masm()->push(edi); ++} ++ ++ ++#ifdef DEBUG ++bool CodeAgingHelper::IsOld(byte* candidate) const { ++ return *candidate == kCallOpcode; ++} ++#endif ++ ++ ++bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { ++ bool result = isolate->code_aging_helper()->IsYoung(sequence); ++ DCHECK(result || isolate->code_aging_helper()->IsOld(sequence)); ++ return result; ++} ++ ++Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) { ++ if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge; ++ ++ sequence++; // Skip the kCallOpcode byte ++ Address target_address = sequence + *reinterpret_cast(sequence) + ++ Assembler::kCallTargetAddressOffset; ++ Code* stub = GetCodeFromTargetAddress(target_address); ++ return GetAgeOfCodeAgeStub(stub); ++} ++ ++void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, ++ Code::Age age) { ++ uint32_t young_length = isolate->code_aging_helper()->young_sequence_length(); ++ if (age == kNoAgeCodeAge) { ++ isolate->code_aging_helper()->CopyYoungSequenceTo(sequence); ++ Assembler::FlushICache(isolate, sequence, young_length); ++ } else { ++ Code* stub = GetCodeAgeStub(isolate, age); ++ CodePatcher patcher(isolate, sequence, young_length); ++ patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32); ++ } ++} ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/codegen-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/codegen-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/codegen-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/codegen-x87.h 2017-12-25 17:42:57.221465559 +0100 +@@ -0,0 +1,33 @@ ++// Copyright 2011 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_X87_CODEGEN_X87_H_ ++#define V8_X87_CODEGEN_X87_H_ ++ ++#include "src/macro-assembler.h" ++ ++namespace v8 { ++namespace internal { ++ ++ ++class StringCharLoadGenerator : public AllStatic { ++ public: ++ // Generates the code for handling different string types and loading the ++ // indexed character into |result|. We expect |index| as untagged input and ++ // |result| as untagged output. ++ static void Generate(MacroAssembler* masm, ++ Factory* factory, ++ Register string, ++ Register index, ++ Register result, ++ Label* call_runtime); ++ ++ private: ++ DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); ++}; ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_CODEGEN_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.cc 2017-12-25 17:42:57.221465559 +0100 +@@ -0,0 +1,3428 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/code-stubs.h" ++#include "src/api-arguments.h" ++#include "src/base/bits.h" ++#include "src/bootstrapper.h" ++#include "src/codegen.h" ++#include "src/ic/handler-compiler.h" ++#include "src/ic/ic.h" ++#include "src/ic/stub-cache.h" ++#include "src/isolate.h" ++#include "src/regexp/jsregexp.h" ++#include "src/regexp/regexp-macro-assembler.h" ++#include "src/runtime/runtime.h" ++#include "src/x87/code-stubs-x87.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++#define __ ACCESS_MASM(masm) ++ ++void ArrayNArgumentsConstructorStub::Generate(MacroAssembler* masm) { ++ __ pop(ecx); ++ __ mov(MemOperand(esp, eax, times_4, 0), edi); ++ __ push(edi); ++ __ push(ebx); ++ __ push(ecx); ++ __ add(eax, Immediate(3)); ++ __ TailCallRuntime(Runtime::kNewArray); ++} ++ ++ ++void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { ++ // We don't allow a GC during a store buffer overflow so there is no need to ++ // store the registers in any particular way, but we do have to store and ++ // restore them. ++ __ pushad(); ++ if (save_doubles()) { ++ // Save FPU stat in m108byte. ++ __ sub(esp, Immediate(108)); ++ __ fnsave(Operand(esp, 0)); ++ } ++ const int argument_count = 1; ++ ++ AllowExternalCallThatCantCauseGC scope(masm); ++ __ PrepareCallCFunction(argument_count, ecx); ++ __ mov(Operand(esp, 0 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ __ CallCFunction( ++ ExternalReference::store_buffer_overflow_function(isolate()), ++ argument_count); ++ if (save_doubles()) { ++ // Restore FPU stat in m108byte. ++ __ frstor(Operand(esp, 0)); ++ __ add(esp, Immediate(108)); ++ } ++ __ popad(); ++ __ ret(0); ++} ++ ++ ++class FloatingPointHelper : public AllStatic { ++ public: ++ enum ArgLocation { ++ ARGS_ON_STACK, ++ ARGS_IN_REGISTERS ++ }; ++ ++ // Code pattern for loading a floating point value. Input value must ++ // be either a smi or a heap number object (fp value). Requirements: ++ // operand in register number. Returns operand as floating point number ++ // on FPU stack. ++ static void LoadFloatOperand(MacroAssembler* masm, Register number); ++ ++ // Test if operands are smi or number objects (fp). Requirements: ++ // operand_1 in eax, operand_2 in edx; falls through on float ++ // operands, jumps to the non_float label otherwise. ++ static void CheckFloatOperands(MacroAssembler* masm, ++ Label* non_float, ++ Register scratch); ++}; ++ ++ ++void DoubleToIStub::Generate(MacroAssembler* masm) { ++ Register input_reg = this->source(); ++ Register final_result_reg = this->destination(); ++ DCHECK(is_truncating()); ++ ++ Label check_negative, process_64_bits, done, done_no_stash; ++ ++ int double_offset = offset(); ++ ++ // Account for return address and saved regs if input is esp. ++ if (input_reg.is(esp)) double_offset += 3 * kPointerSize; ++ ++ MemOperand mantissa_operand(MemOperand(input_reg, double_offset)); ++ MemOperand exponent_operand(MemOperand(input_reg, ++ double_offset + kDoubleSize / 2)); ++ ++ Register scratch1; ++ { ++ Register scratch_candidates[3] = { ebx, edx, edi }; ++ for (int i = 0; i < 3; i++) { ++ scratch1 = scratch_candidates[i]; ++ if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break; ++ } ++ } ++ // Since we must use ecx for shifts below, use some other register (eax) ++ // to calculate the result if ecx is the requested return register. ++ Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg; ++ // Save ecx if it isn't the return register and therefore volatile, or if it ++ // is the return register, then save the temp register we use in its stead for ++ // the result. ++ Register save_reg = final_result_reg.is(ecx) ? eax : ecx; ++ __ push(scratch1); ++ __ push(save_reg); ++ ++ bool stash_exponent_copy = !input_reg.is(esp); ++ __ mov(scratch1, mantissa_operand); ++ __ mov(ecx, exponent_operand); ++ if (stash_exponent_copy) __ push(ecx); ++ ++ __ and_(ecx, HeapNumber::kExponentMask); ++ __ shr(ecx, HeapNumber::kExponentShift); ++ __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias)); ++ __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits)); ++ __ j(below, &process_64_bits); ++ ++ // Result is entirely in lower 32-bits of mantissa ++ int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; ++ __ sub(ecx, Immediate(delta)); ++ __ xor_(result_reg, result_reg); ++ __ cmp(ecx, Immediate(31)); ++ __ j(above, &done); ++ __ shl_cl(scratch1); ++ __ jmp(&check_negative); ++ ++ __ bind(&process_64_bits); ++ // Result must be extracted from shifted 32-bit mantissa ++ __ sub(ecx, Immediate(delta)); ++ __ neg(ecx); ++ if (stash_exponent_copy) { ++ __ mov(result_reg, MemOperand(esp, 0)); ++ } else { ++ __ mov(result_reg, exponent_operand); ++ } ++ __ and_(result_reg, ++ Immediate(static_cast(Double::kSignificandMask >> 32))); ++ __ add(result_reg, ++ Immediate(static_cast(Double::kHiddenBit >> 32))); ++ __ shrd_cl(scratch1, result_reg); ++ __ shr_cl(result_reg); ++ __ test(ecx, Immediate(32)); ++ { ++ Label skip_mov; ++ __ j(equal, &skip_mov, Label::kNear); ++ __ mov(scratch1, result_reg); ++ __ bind(&skip_mov); ++ } ++ ++ // If the double was negative, negate the integer result. ++ __ bind(&check_negative); ++ __ mov(result_reg, scratch1); ++ __ neg(result_reg); ++ if (stash_exponent_copy) { ++ __ cmp(MemOperand(esp, 0), Immediate(0)); ++ } else { ++ __ cmp(exponent_operand, Immediate(0)); ++ } ++ { ++ Label skip_mov; ++ __ j(less_equal, &skip_mov, Label::kNear); ++ __ mov(result_reg, scratch1); ++ __ bind(&skip_mov); ++ } ++ ++ // Restore registers ++ __ bind(&done); ++ if (stash_exponent_copy) { ++ __ add(esp, Immediate(kDoubleSize / 2)); ++ } ++ __ bind(&done_no_stash); ++ if (!final_result_reg.is(result_reg)) { ++ DCHECK(final_result_reg.is(ecx)); ++ __ mov(final_result_reg, result_reg); ++ } ++ __ pop(save_reg); ++ __ pop(scratch1); ++ __ ret(0); ++} ++ ++ ++void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, ++ Register number) { ++ Label load_smi, done; ++ ++ __ JumpIfSmi(number, &load_smi, Label::kNear); ++ __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); ++ __ jmp(&done, Label::kNear); ++ ++ __ bind(&load_smi); ++ __ SmiUntag(number); ++ __ push(number); ++ __ fild_s(Operand(esp, 0)); ++ __ pop(number); ++ ++ __ bind(&done); ++} ++ ++ ++void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, ++ Label* non_float, ++ Register scratch) { ++ Label test_other, done; ++ // Test if both operands are floats or smi -> scratch=k_is_float; ++ // Otherwise scratch = k_not_float. ++ __ JumpIfSmi(edx, &test_other, Label::kNear); ++ __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); ++ Factory* factory = masm->isolate()->factory(); ++ __ cmp(scratch, factory->heap_number_map()); ++ __ j(not_equal, non_float); // argument in edx is not a number -> NaN ++ ++ __ bind(&test_other); ++ __ JumpIfSmi(eax, &done, Label::kNear); ++ __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ cmp(scratch, factory->heap_number_map()); ++ __ j(not_equal, non_float); // argument in eax is not a number -> NaN ++ ++ // Fall-through: Both operands are numbers. ++ __ bind(&done); ++} ++ ++ ++void MathPowStub::Generate(MacroAssembler* masm) { ++ const Register scratch = ecx; ++ ++ // Load the double_exponent into x87 FPU ++ __ fld_d(Operand(esp, 0 * kDoubleSize + 4)); ++ // Load the double_base into x87 FPU ++ __ fld_d(Operand(esp, 1 * kDoubleSize + 4)); ++ ++ // Call ieee754 runtime directly. ++ { ++ AllowExternalCallThatCantCauseGC scope(masm); ++ __ PrepareCallCFunction(4, scratch); ++ // Put the double_base parameter in call stack ++ __ fstp_d(Operand(esp, 0 * kDoubleSize)); ++ // Put the double_exponent parameter in call stack ++ __ fstp_d(Operand(esp, 1 * kDoubleSize)); ++ __ CallCFunction(ExternalReference::power_double_double_function(isolate()), ++ 4); ++ } ++ // Return value is in st(0) on ia32. ++ __ ret(0); ++} ++ ++ ++static int NegativeComparisonResult(Condition cc) { ++ DCHECK(cc != equal); ++ DCHECK((cc == less) || (cc == less_equal) ++ || (cc == greater) || (cc == greater_equal)); ++ return (cc == greater || cc == greater_equal) ? LESS : GREATER; ++} ++ ++ ++static void CheckInputType(MacroAssembler* masm, Register input, ++ CompareICState::State expected, Label* fail) { ++ Label ok; ++ if (expected == CompareICState::SMI) { ++ __ JumpIfNotSmi(input, fail); ++ } else if (expected == CompareICState::NUMBER) { ++ __ JumpIfSmi(input, &ok); ++ __ cmp(FieldOperand(input, HeapObject::kMapOffset), ++ Immediate(masm->isolate()->factory()->heap_number_map())); ++ __ j(not_equal, fail); ++ } ++ // We could be strict about internalized/non-internalized here, but as long as ++ // hydrogen doesn't care, the stub doesn't have to care either. ++ __ bind(&ok); ++} ++ ++ ++static void BranchIfNotInternalizedString(MacroAssembler* masm, ++ Label* label, ++ Register object, ++ Register scratch) { ++ __ JumpIfSmi(object, label); ++ __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); ++ __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); ++ STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); ++ __ test(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); ++ __ j(not_zero, label); ++} ++ ++ ++void CompareICStub::GenerateGeneric(MacroAssembler* masm) { ++ Label runtime_call, check_unequal_objects; ++ Condition cc = GetCondition(); ++ ++ Label miss; ++ CheckInputType(masm, edx, left(), &miss); ++ CheckInputType(masm, eax, right(), &miss); ++ ++ // Compare two smis. ++ Label non_smi, smi_done; ++ __ mov(ecx, edx); ++ __ or_(ecx, eax); ++ __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); ++ __ sub(edx, eax); // Return on the result of the subtraction. ++ __ j(no_overflow, &smi_done, Label::kNear); ++ __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. ++ __ bind(&smi_done); ++ __ mov(eax, edx); ++ __ ret(0); ++ __ bind(&non_smi); ++ ++ // NOTICE! This code is only reached after a smi-fast-case check, so ++ // it is certain that at least one operand isn't a smi. ++ ++ // Identical objects can be compared fast, but there are some tricky cases ++ // for NaN and undefined. ++ Label generic_heap_number_comparison; ++ { ++ Label not_identical; ++ __ cmp(eax, edx); ++ __ j(not_equal, ¬_identical); ++ ++ if (cc != equal) { ++ // Check for undefined. undefined OP undefined is false even though ++ // undefined == undefined. ++ __ cmp(edx, isolate()->factory()->undefined_value()); ++ Label check_for_nan; ++ __ j(not_equal, &check_for_nan, Label::kNear); ++ __ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); ++ __ ret(0); ++ __ bind(&check_for_nan); ++ } ++ ++ // Test for NaN. Compare heap numbers in a general way, ++ // to handle NaNs correctly. ++ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), ++ Immediate(isolate()->factory()->heap_number_map())); ++ __ j(equal, &generic_heap_number_comparison, Label::kNear); ++ if (cc != equal) { ++ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); ++ // Call runtime on identical JSObjects. Otherwise return equal. ++ __ cmpb(ecx, Immediate(FIRST_JS_RECEIVER_TYPE)); ++ __ j(above_equal, &runtime_call, Label::kFar); ++ // Call runtime on identical symbols since we need to throw a TypeError. ++ __ cmpb(ecx, Immediate(SYMBOL_TYPE)); ++ __ j(equal, &runtime_call, Label::kFar); ++ } ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ ret(0); ++ ++ ++ __ bind(¬_identical); ++ } ++ ++ // Strict equality can quickly decide whether objects are equal. ++ // Non-strict object equality is slower, so it is handled later in the stub. ++ if (cc == equal && strict()) { ++ Label slow; // Fallthrough label. ++ Label not_smis; ++ // If we're doing a strict equality comparison, we don't have to do ++ // type conversion, so we generate code to do fast comparison for objects ++ // and oddballs. Non-smi numbers and strings still go through the usual ++ // slow-case code. ++ // If either is a Smi (we know that not both are), then they can only ++ // be equal if the other is a HeapNumber. If so, use the slow case. ++ STATIC_ASSERT(kSmiTag == 0); ++ DCHECK_EQ(static_cast(0), Smi::kZero); ++ __ mov(ecx, Immediate(kSmiTagMask)); ++ __ and_(ecx, eax); ++ __ test(ecx, edx); ++ __ j(not_zero, ¬_smis, Label::kNear); ++ // One operand is a smi. ++ ++ // Check whether the non-smi is a heap number. ++ STATIC_ASSERT(kSmiTagMask == 1); ++ // ecx still holds eax & kSmiTag, which is either zero or one. ++ __ sub(ecx, Immediate(0x01)); ++ __ mov(ebx, edx); ++ __ xor_(ebx, eax); ++ __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx. ++ __ xor_(ebx, eax); ++ // if eax was smi, ebx is now edx, else eax. ++ ++ // Check if the non-smi operand is a heap number. ++ __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), ++ Immediate(isolate()->factory()->heap_number_map())); ++ // If heap number, handle it in the slow case. ++ __ j(equal, &slow, Label::kNear); ++ // Return non-equal (ebx is not zero) ++ __ mov(eax, ebx); ++ __ ret(0); ++ ++ __ bind(¬_smis); ++ // If either operand is a JSObject or an oddball value, then they are not ++ // equal since their pointers are different ++ // There is no test for undetectability in strict equality. ++ ++ // Get the type of the first operand. ++ // If the first object is a JS object, we have done pointer comparison. ++ Label first_non_object; ++ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(below, &first_non_object, Label::kNear); ++ ++ // Return non-zero (eax is not zero) ++ Label return_not_equal; ++ STATIC_ASSERT(kHeapObjectTag != 0); ++ __ bind(&return_not_equal); ++ __ ret(0); ++ ++ __ bind(&first_non_object); ++ // Check for oddballs: true, false, null, undefined. ++ __ CmpInstanceType(ecx, ODDBALL_TYPE); ++ __ j(equal, &return_not_equal); ++ ++ __ CmpObjectType(edx, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(above_equal, &return_not_equal); ++ ++ // Check for oddballs: true, false, null, undefined. ++ __ CmpInstanceType(ecx, ODDBALL_TYPE); ++ __ j(equal, &return_not_equal); ++ ++ // Fall through to the general case. ++ __ bind(&slow); ++ } ++ ++ // Generate the number comparison code. ++ Label non_number_comparison; ++ Label unordered; ++ __ bind(&generic_heap_number_comparison); ++ FloatingPointHelper::CheckFloatOperands( ++ masm, &non_number_comparison, ebx); ++ FloatingPointHelper::LoadFloatOperand(masm, eax); ++ FloatingPointHelper::LoadFloatOperand(masm, edx); ++ __ FCmp(); ++ ++ // Don't base result on EFLAGS when a NaN is involved. ++ __ j(parity_even, &unordered, Label::kNear); ++ ++ Label below_label, above_label; ++ // Return a result of -1, 0, or 1, based on EFLAGS. ++ __ j(below, &below_label, Label::kNear); ++ __ j(above, &above_label, Label::kNear); ++ ++ __ Move(eax, Immediate(0)); ++ __ ret(0); ++ ++ __ bind(&below_label); ++ __ mov(eax, Immediate(Smi::FromInt(-1))); ++ __ ret(0); ++ ++ __ bind(&above_label); ++ __ mov(eax, Immediate(Smi::FromInt(1))); ++ __ ret(0); ++ ++ // If one of the numbers was NaN, then the result is always false. ++ // The cc is never not-equal. ++ __ bind(&unordered); ++ DCHECK(cc != not_equal); ++ if (cc == less || cc == less_equal) { ++ __ mov(eax, Immediate(Smi::FromInt(1))); ++ } else { ++ __ mov(eax, Immediate(Smi::FromInt(-1))); ++ } ++ __ ret(0); ++ ++ // The number comparison code did not provide a valid result. ++ __ bind(&non_number_comparison); ++ ++ // Fast negative check for internalized-to-internalized equality. ++ Label check_for_strings; ++ if (cc == equal) { ++ BranchIfNotInternalizedString(masm, &check_for_strings, eax, ecx); ++ BranchIfNotInternalizedString(masm, &check_for_strings, edx, ecx); ++ ++ // We've already checked for object identity, so if both operands ++ // are internalized they aren't equal. Register eax already holds a ++ // non-zero value, which indicates not equal, so just return. ++ __ ret(0); ++ } ++ ++ __ bind(&check_for_strings); ++ ++ __ JumpIfNotBothSequentialOneByteStrings(edx, eax, ecx, ebx, ++ &check_unequal_objects); ++ ++ // Inline comparison of one-byte strings. ++ if (cc == equal) { ++ StringHelper::GenerateFlatOneByteStringEquals(masm, edx, eax, ecx, ebx); ++ } else { ++ StringHelper::GenerateCompareFlatOneByteStrings(masm, edx, eax, ecx, ebx, ++ edi); ++ } ++#ifdef DEBUG ++ __ Abort(kUnexpectedFallThroughFromStringComparison); ++#endif ++ ++ __ bind(&check_unequal_objects); ++ if (cc == equal && !strict()) { ++ // Non-strict equality. Objects are unequal if ++ // they are both JSObjects and not undetectable, ++ // and their pointers are different. ++ Label return_equal, return_unequal, undetectable; ++ // At most one is a smi, so we can test for smi by adding the two. ++ // A smi plus a heap object has the low bit set, a heap object plus ++ // a heap object has the low bit clear. ++ STATIC_ASSERT(kSmiTag == 0); ++ STATIC_ASSERT(kSmiTagMask == 1); ++ __ lea(ecx, Operand(eax, edx, times_1, 0)); ++ __ test(ecx, Immediate(kSmiTagMask)); ++ __ j(not_zero, &runtime_call); ++ ++ __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); ++ ++ __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsUndetectable)); ++ __ j(not_zero, &undetectable, Label::kNear); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsUndetectable)); ++ __ j(not_zero, &return_unequal, Label::kNear); ++ ++ __ CmpInstanceType(ebx, FIRST_JS_RECEIVER_TYPE); ++ __ j(below, &runtime_call, Label::kNear); ++ __ CmpInstanceType(ecx, FIRST_JS_RECEIVER_TYPE); ++ __ j(below, &runtime_call, Label::kNear); ++ ++ __ bind(&return_unequal); ++ // Return non-equal by returning the non-zero object pointer in eax. ++ __ ret(0); // eax, edx were pushed ++ ++ __ bind(&undetectable); ++ __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), ++ Immediate(1 << Map::kIsUndetectable)); ++ __ j(zero, &return_unequal, Label::kNear); ++ ++ // If both sides are JSReceivers, then the result is false according to ++ // the HTML specification, which says that only comparisons with null or ++ // undefined are affected by special casing for document.all. ++ __ CmpInstanceType(ebx, ODDBALL_TYPE); ++ __ j(zero, &return_equal, Label::kNear); ++ __ CmpInstanceType(ecx, ODDBALL_TYPE); ++ __ j(not_zero, &return_unequal, Label::kNear); ++ ++ __ bind(&return_equal); ++ __ Move(eax, Immediate(EQUAL)); ++ __ ret(0); // eax, edx were pushed ++ } ++ __ bind(&runtime_call); ++ ++ if (cc == equal) { ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(esi); ++ __ Call(strict() ? isolate()->builtins()->StrictEqual() ++ : isolate()->builtins()->Equal(), ++ RelocInfo::CODE_TARGET); ++ __ Pop(esi); ++ } ++ // Turn true into 0 and false into some non-zero value. ++ STATIC_ASSERT(EQUAL == 0); ++ __ sub(eax, Immediate(isolate()->factory()->true_value())); ++ __ Ret(); ++ } else { ++ // Push arguments below the return address. ++ __ pop(ecx); ++ __ push(edx); ++ __ push(eax); ++ __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); ++ ++ // Restore return address on the stack. ++ __ push(ecx); ++ // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) ++ // tagged as a small integer. ++ __ TailCallRuntime(Runtime::kCompare); ++ } ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { ++ // eax : number of arguments to the construct function ++ // ebx : feedback vector ++ // edx : slot in feedback vector (Smi) ++ // edi : the function to call ++ ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Number-of-arguments register must be smi-tagged to call out. ++ __ SmiTag(eax); ++ __ push(eax); ++ __ push(edi); ++ __ push(edx); ++ __ push(ebx); ++ __ push(esi); ++ ++ __ CallStub(stub); ++ ++ __ pop(esi); ++ __ pop(ebx); ++ __ pop(edx); ++ __ pop(edi); ++ __ pop(eax); ++ __ SmiUntag(eax); ++ } ++} ++ ++ ++static void GenerateRecordCallTarget(MacroAssembler* masm) { ++ // Cache the called function in a feedback vector slot. Cache states ++ // are uninitialized, monomorphic (indicated by a JSFunction), and ++ // megamorphic. ++ // eax : number of arguments to the construct function ++ // ebx : feedback vector ++ // edx : slot in feedback vector (Smi) ++ // edi : the function to call ++ Isolate* isolate = masm->isolate(); ++ Label initialize, done, miss, megamorphic, not_array_function; ++ ++ // Load the cache state into ecx. ++ __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, ++ FixedArray::kHeaderSize)); ++ ++ // A monomorphic cache hit or an already megamorphic state: invoke the ++ // function without changing the state. ++ // We don't know if ecx is a WeakCell or a Symbol, but it's harmless to read ++ // at this position in a symbol (see static asserts in feedback-vector.h). ++ Label check_allocation_site; ++ __ cmp(edi, FieldOperand(ecx, WeakCell::kValueOffset)); ++ __ j(equal, &done, Label::kFar); ++ __ CompareRoot(ecx, Heap::kmegamorphic_symbolRootIndex); ++ __ j(equal, &done, Label::kFar); ++ __ CompareRoot(FieldOperand(ecx, HeapObject::kMapOffset), ++ Heap::kWeakCellMapRootIndex); ++ __ j(not_equal, &check_allocation_site); ++ ++ // If the weak cell is cleared, we have a new chance to become monomorphic. ++ __ JumpIfSmi(FieldOperand(ecx, WeakCell::kValueOffset), &initialize); ++ __ jmp(&megamorphic); ++ ++ __ bind(&check_allocation_site); ++ // If we came here, we need to see if we are the array function. ++ // If we didn't have a matching function, and we didn't find the megamorph ++ // sentinel, then we have in the slot either some other function or an ++ // AllocationSite. ++ __ CompareRoot(FieldOperand(ecx, 0), Heap::kAllocationSiteMapRootIndex); ++ __ j(not_equal, &miss); ++ ++ // Make sure the function is the Array() function ++ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx); ++ __ cmp(edi, ecx); ++ __ j(not_equal, &megamorphic); ++ __ jmp(&done, Label::kFar); ++ ++ __ bind(&miss); ++ ++ // A monomorphic miss (i.e, here the cache is not uninitialized) goes ++ // megamorphic. ++ __ CompareRoot(ecx, Heap::kuninitialized_symbolRootIndex); ++ __ j(equal, &initialize); ++ // MegamorphicSentinel is an immortal immovable object (undefined) so no ++ // write-barrier is needed. ++ __ bind(&megamorphic); ++ __ mov( ++ FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), ++ Immediate(FeedbackVector::MegamorphicSentinel(isolate))); ++ __ jmp(&done, Label::kFar); ++ ++ // An uninitialized cache is patched with the function or sentinel to ++ // indicate the ElementsKind if function is the Array constructor. ++ __ bind(&initialize); ++ // Make sure the function is the Array() function ++ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx); ++ __ cmp(edi, ecx); ++ __ j(not_equal, ¬_array_function); ++ ++ // The target function is the Array constructor, ++ // Create an AllocationSite if we don't already have it, store it in the ++ // slot. ++ CreateAllocationSiteStub create_stub(isolate); ++ CallStubInRecordCallTarget(masm, &create_stub); ++ __ jmp(&done); ++ ++ __ bind(¬_array_function); ++ CreateWeakCellStub weak_cell_stub(isolate); ++ CallStubInRecordCallTarget(masm, &weak_cell_stub); ++ ++ __ bind(&done); ++ // Increment the call count for all function calls. ++ __ add(FieldOperand(ebx, edx, times_half_pointer_size, ++ FixedArray::kHeaderSize + kPointerSize), ++ Immediate(Smi::FromInt(1))); ++} ++ ++ ++void CallConstructStub::Generate(MacroAssembler* masm) { ++ // eax : number of arguments ++ // ebx : feedback vector ++ // edx : slot in feedback vector (Smi, for RecordCallTarget) ++ // edi : constructor function ++ ++ Label non_function; ++ // Check that function is not a smi. ++ __ JumpIfSmi(edi, &non_function); ++ // Check that function is a JSFunction. ++ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); ++ __ j(not_equal, &non_function); ++ ++ GenerateRecordCallTarget(masm); ++ ++ Label feedback_register_initialized; ++ // Put the AllocationSite from the feedback vector into ebx, or undefined. ++ __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size, ++ FixedArray::kHeaderSize)); ++ Handle allocation_site_map = isolate()->factory()->allocation_site_map(); ++ __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map)); ++ __ j(equal, &feedback_register_initialized); ++ __ mov(ebx, isolate()->factory()->undefined_value()); ++ __ bind(&feedback_register_initialized); ++ ++ __ AssertUndefinedOrAllocationSite(ebx); ++ ++ // Pass new target to construct stub. ++ __ mov(edx, edi); ++ ++ // Tail call to the function-specific construct stub (still in the caller ++ // context at this point). ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); ++ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); ++ __ jmp(ecx); ++ ++ __ bind(&non_function); ++ __ mov(edx, edi); ++ __ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); ++} ++ ++static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector, ++ Register slot) { ++ __ add(FieldOperand(feedback_vector, slot, times_half_pointer_size, ++ FixedArray::kHeaderSize + kPointerSize), ++ Immediate(Smi::FromInt(1))); ++} ++ ++void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) { ++ // eax - number of arguments ++ // edi - function ++ // edx - slot id ++ // ebx - vector ++ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx); ++ __ cmp(edi, ecx); ++ __ j(not_equal, miss); ++ ++ // Reload ecx. ++ __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, ++ FixedArray::kHeaderSize)); ++ ++ // Increment the call count for monomorphic function calls. ++ IncrementCallCount(masm, ebx, edx); ++ ++ __ mov(ebx, ecx); ++ __ mov(edx, edi); ++ ArrayConstructorStub stub(masm->isolate()); ++ __ TailCallStub(&stub); ++ ++ // Unreachable. ++} ++ ++ ++void CallICStub::Generate(MacroAssembler* masm) { ++ // edi - number of arguments ++ // edi - function ++ // edx - slot id ++ // ebx - vector ++ Isolate* isolate = masm->isolate(); ++ Label extra_checks_or_miss, call, call_function, call_count_incremented; ++ ++ // The checks. First, does edi match the recorded monomorphic target? ++ __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, ++ FixedArray::kHeaderSize)); ++ ++ // We don't know that we have a weak cell. We might have a private symbol ++ // or an AllocationSite, but the memory is safe to examine. ++ // AllocationSite::kTransitionInfoOrBoilerplateOffset - contains a Smi or ++ // pointer to FixedArray. WeakCell::kValueOffset - contains a JSFunction or ++ // Smi(0) Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not ++ // computed, meaning that it can't appear to be a pointer. If the low bit is ++ // 0, then hash is computed, but the 0 bit prevents the field from appearing ++ // to be a pointer. ++ STATIC_ASSERT(WeakCell::kSize >= kPointerSize); ++ STATIC_ASSERT(AllocationSite::kTransitionInfoOrBoilerplateOffset == ++ WeakCell::kValueOffset && ++ WeakCell::kValueOffset == Symbol::kHashFieldSlot); ++ ++ __ cmp(edi, FieldOperand(ecx, WeakCell::kValueOffset)); ++ __ j(not_equal, &extra_checks_or_miss); ++ ++ // The compare above could have been a SMI/SMI comparison. Guard against this ++ // convincing us that we have a monomorphic JSFunction. ++ __ JumpIfSmi(edi, &extra_checks_or_miss); ++ ++ __ bind(&call_function); ++ ++ // Increment the call count for monomorphic function calls. ++ IncrementCallCount(masm, ebx, edx); ++ ++ __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(), ++ tail_call_mode()), ++ RelocInfo::CODE_TARGET); ++ ++ __ bind(&extra_checks_or_miss); ++ Label uninitialized, miss, not_allocation_site; ++ ++ __ cmp(ecx, Immediate(FeedbackVector::MegamorphicSentinel(isolate))); ++ __ j(equal, &call); ++ ++ // Check if we have an allocation site. ++ __ CompareRoot(FieldOperand(ecx, HeapObject::kMapOffset), ++ Heap::kAllocationSiteMapRootIndex); ++ __ j(not_equal, ¬_allocation_site); ++ ++ // We have an allocation site. ++ HandleArrayCase(masm, &miss); ++ ++ __ bind(¬_allocation_site); ++ ++ // The following cases attempt to handle MISS cases without going to the ++ // runtime. ++ if (FLAG_trace_ic) { ++ __ jmp(&miss); ++ } ++ ++ __ cmp(ecx, Immediate(FeedbackVector::UninitializedSentinel(isolate))); ++ __ j(equal, &uninitialized); ++ ++ // We are going megamorphic. If the feedback is a JSFunction, it is fine ++ // to handle it here. More complex cases are dealt with in the runtime. ++ __ AssertNotSmi(ecx); ++ __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); ++ __ j(not_equal, &miss); ++ __ mov( ++ FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), ++ Immediate(FeedbackVector::MegamorphicSentinel(isolate))); ++ ++ __ bind(&call); ++ ++ // Increment the call count for megamorphic function calls. ++ IncrementCallCount(masm, ebx, edx); ++ ++ __ bind(&call_count_incremented); ++ ++ __ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()), ++ RelocInfo::CODE_TARGET); ++ ++ __ bind(&uninitialized); ++ ++ // We are going monomorphic, provided we actually have a JSFunction. ++ __ JumpIfSmi(edi, &miss); ++ ++ // Goto miss case if we do not have a function. ++ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); ++ __ j(not_equal, &miss); ++ ++ // Make sure the function is not the Array() function, which requires special ++ // behavior on MISS. ++ __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx); ++ __ cmp(edi, ecx); ++ __ j(equal, &miss); ++ ++ // Make sure the function belongs to the same native context. ++ __ mov(ecx, FieldOperand(edi, JSFunction::kContextOffset)); ++ __ mov(ecx, ContextOperand(ecx, Context::NATIVE_CONTEXT_INDEX)); ++ __ cmp(ecx, NativeContextOperand()); ++ __ j(not_equal, &miss); ++ ++ // Store the function. Use a stub since we need a frame for allocation. ++ // eax - number of arguments ++ // ebx - vector ++ // edx - slot ++ // edi - function ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ CreateWeakCellStub create_stub(isolate); ++ __ SmiTag(eax); ++ __ push(eax); ++ __ push(ebx); ++ __ push(edx); ++ __ push(edi); ++ __ push(esi); ++ __ CallStub(&create_stub); ++ __ pop(esi); ++ __ pop(edi); ++ __ pop(edx); ++ __ pop(ebx); ++ __ pop(eax); ++ __ SmiUntag(eax); ++ } ++ ++ __ jmp(&call_function); ++ ++ // We are here because tracing is on or we encountered a MISS case we can't ++ // handle here. ++ __ bind(&miss); ++ GenerateMiss(masm); ++ ++ __ jmp(&call_count_incremented); ++ ++ // Unreachable ++ __ int3(); ++} ++ ++ ++void CallICStub::GenerateMiss(MacroAssembler* masm) { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ ++ // Preserve the number of arguments. ++ __ SmiTag(eax); ++ __ push(eax); ++ ++ // Push the function and feedback info. ++ __ push(edi); ++ __ push(ebx); ++ __ push(edx); ++ ++ // Call the entry. ++ __ CallRuntime(Runtime::kCallIC_Miss); ++ ++ // Move result to edi and exit the internal frame. ++ __ mov(edi, eax); ++ ++ // Restore number of arguments. ++ __ pop(eax); ++ __ SmiUntag(eax); ++} ++ ++ ++bool CEntryStub::NeedsImmovableCode() { ++ return false; ++} ++ ++ ++void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { ++ CEntryStub::GenerateAheadOfTime(isolate); ++ StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); ++ // It is important that the store buffer overflow stubs are generated first. ++ CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate); ++ CreateAllocationSiteStub::GenerateAheadOfTime(isolate); ++ CreateWeakCellStub::GenerateAheadOfTime(isolate); ++ StoreFastElementStub::GenerateAheadOfTime(isolate); ++} ++ ++ ++void CodeStub::GenerateFPStubs(Isolate* isolate) { ++ CEntryStub save_doubles(isolate, 1, kSaveFPRegs); ++ // Stubs might already be in the snapshot, detect that and don't regenerate, ++ // which would lead to code stub initialization state being messed up. ++ Code* save_doubles_code; ++ if (!save_doubles.FindCodeInCache(&save_doubles_code)) { ++ save_doubles_code = *(save_doubles.GetCode()); ++ } ++} ++ ++ ++void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { ++ CEntryStub stub(isolate, 1, kDontSaveFPRegs); ++ stub.GetCode(); ++} ++ ++ ++void CEntryStub::Generate(MacroAssembler* masm) { ++ // eax: number of arguments including receiver ++ // ebx: pointer to C function (C callee-saved) ++ // ebp: frame pointer (restored after C call) ++ // esp: stack pointer (restored after C call) ++ // esi: current context (C callee-saved) ++ // edi: JS function of the caller (C callee-saved) ++ // ++ // If argv_in_register(): ++ // ecx: pointer to the first argument ++ ++ ProfileEntryHookStub::MaybeCallEntryHook(masm); ++ ++ // Reserve space on the stack for the three arguments passed to the call. If ++ // result size is greater than can be returned in registers, also reserve ++ // space for the hidden argument for the result location, and space for the ++ // result itself. ++ int arg_stack_space = result_size() < 3 ? 3 : 4 + result_size(); ++ ++ // Enter the exit frame that transitions from JavaScript to C++. ++ if (argv_in_register()) { ++ DCHECK(!save_doubles()); ++ DCHECK(!is_builtin_exit()); ++ __ EnterApiExitFrame(arg_stack_space); ++ ++ // Move argc and argv into the correct registers. ++ __ mov(esi, ecx); ++ __ mov(edi, eax); ++ } else { ++ __ EnterExitFrame( ++ arg_stack_space, save_doubles(), ++ is_builtin_exit() ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT); ++ } ++ ++ // ebx: pointer to C function (C callee-saved) ++ // ebp: frame pointer (restored after C call) ++ // esp: stack pointer (restored after C call) ++ // edi: number of arguments including receiver (C callee-saved) ++ // esi: pointer to the first argument (C callee-saved) ++ ++ // Result returned in eax, or eax+edx if result size is 2. ++ ++ // Check stack alignment. ++ if (FLAG_debug_code) { ++ __ CheckStackAlignment(); ++ } ++ // Call C function. ++ if (result_size() <= 2) { ++ __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. ++ __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. ++ __ mov(Operand(esp, 2 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ } else { ++ DCHECK_EQ(3, result_size()); ++ // Pass a pointer to the result location as the first argument. ++ __ lea(eax, Operand(esp, 4 * kPointerSize)); ++ __ mov(Operand(esp, 0 * kPointerSize), eax); ++ __ mov(Operand(esp, 1 * kPointerSize), edi); // argc. ++ __ mov(Operand(esp, 2 * kPointerSize), esi); // argv. ++ __ mov(Operand(esp, 3 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ } ++ __ call(ebx); ++ ++ if (result_size() > 2) { ++ DCHECK_EQ(3, result_size()); ++#ifndef _WIN32 ++ // Restore the "hidden" argument on the stack which was popped by caller. ++ __ sub(esp, Immediate(kPointerSize)); ++#endif ++ // Read result values stored on stack. Result is stored above the arguments. ++ __ mov(kReturnRegister0, Operand(esp, 4 * kPointerSize)); ++ __ mov(kReturnRegister1, Operand(esp, 5 * kPointerSize)); ++ __ mov(kReturnRegister2, Operand(esp, 6 * kPointerSize)); ++ } ++ // Result is in eax, edx:eax or edi:edx:eax - do not destroy these registers! ++ ++ // Check result for exception sentinel. ++ Label exception_returned; ++ __ cmp(eax, isolate()->factory()->exception()); ++ __ j(equal, &exception_returned); ++ ++ // Check that there is no pending exception, otherwise we ++ // should have returned the exception sentinel. ++ if (FLAG_debug_code) { ++ __ push(edx); ++ __ mov(edx, Immediate(isolate()->factory()->the_hole_value())); ++ Label okay; ++ ExternalReference pending_exception_address( ++ IsolateAddressId::kPendingExceptionAddress, isolate()); ++ __ cmp(edx, Operand::StaticVariable(pending_exception_address)); ++ // Cannot use check here as it attempts to generate call into runtime. ++ __ j(equal, &okay, Label::kNear); ++ __ int3(); ++ __ bind(&okay); ++ __ pop(edx); ++ } ++ ++ // Exit the JavaScript to C++ exit frame. ++ __ LeaveExitFrame(save_doubles(), !argv_in_register()); ++ __ ret(0); ++ ++ // Handling of exception. ++ __ bind(&exception_returned); ++ ++ ExternalReference pending_handler_context_address( ++ IsolateAddressId::kPendingHandlerContextAddress, isolate()); ++ ExternalReference pending_handler_code_address( ++ IsolateAddressId::kPendingHandlerCodeAddress, isolate()); ++ ExternalReference pending_handler_offset_address( ++ IsolateAddressId::kPendingHandlerOffsetAddress, isolate()); ++ ExternalReference pending_handler_fp_address( ++ IsolateAddressId::kPendingHandlerFPAddress, isolate()); ++ ExternalReference pending_handler_sp_address( ++ IsolateAddressId::kPendingHandlerSPAddress, isolate()); ++ ++ // Ask the runtime for help to determine the handler. This will set eax to ++ // contain the current pending exception, don't clobber it. ++ ExternalReference find_handler(Runtime::kUnwindAndFindExceptionHandler, ++ isolate()); ++ { ++ FrameScope scope(masm, StackFrame::MANUAL); ++ __ PrepareCallCFunction(3, eax); ++ __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); // argc. ++ __ mov(Operand(esp, 1 * kPointerSize), Immediate(0)); // argv. ++ __ mov(Operand(esp, 2 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ __ CallCFunction(find_handler, 3); ++ } ++ ++ // Retrieve the handler context, SP and FP. ++ __ mov(esi, Operand::StaticVariable(pending_handler_context_address)); ++ __ mov(esp, Operand::StaticVariable(pending_handler_sp_address)); ++ __ mov(ebp, Operand::StaticVariable(pending_handler_fp_address)); ++ ++ // If the handler is a JS frame, restore the context to the frame. Note that ++ // the context will be set to (esi == 0) for non-JS frames. ++ Label skip; ++ __ test(esi, esi); ++ __ j(zero, &skip, Label::kNear); ++ __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); ++ __ bind(&skip); ++ ++ // Compute the handler entry address and jump to it. ++ __ mov(edi, Operand::StaticVariable(pending_handler_code_address)); ++ __ mov(edx, Operand::StaticVariable(pending_handler_offset_address)); ++ // Check whether it's a turbofanned exception handler code before jump to it. ++ Label not_turbo; ++ __ push(eax); ++ __ mov(eax, Operand(edi, Code::kKindSpecificFlags1Offset - kHeapObjectTag)); ++ __ and_(eax, Immediate(1 << Code::kIsTurbofannedBit)); ++ __ j(zero, ¬_turbo); ++ __ fninit(); ++ __ fld1(); ++ __ bind(¬_turbo); ++ __ pop(eax); ++ __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize)); ++ __ jmp(edi); ++} ++ ++ ++void JSEntryStub::Generate(MacroAssembler* masm) { ++ Label invoke, handler_entry, exit; ++ Label not_outermost_js, not_outermost_js_2; ++ ++ ProfileEntryHookStub::MaybeCallEntryHook(masm); ++ ++ // Set up frame. ++ __ push(ebp); ++ __ mov(ebp, esp); ++ ++ // Push marker in two places. ++ int marker = type(); ++ __ push(Immediate(Smi::FromInt(marker))); // marker ++ ExternalReference context_address(IsolateAddressId::kContextAddress, ++ isolate()); ++ __ push(Operand::StaticVariable(context_address)); // context ++ // Save callee-saved registers (C calling conventions). ++ __ push(edi); ++ __ push(esi); ++ __ push(ebx); ++ ++ // Save copies of the top frame descriptor on the stack. ++ ExternalReference c_entry_fp(IsolateAddressId::kCEntryFPAddress, isolate()); ++ __ push(Operand::StaticVariable(c_entry_fp)); ++ ++ // If this is the outermost JS call, set js_entry_sp value. ++ ExternalReference js_entry_sp(IsolateAddressId::kJSEntrySPAddress, isolate()); ++ __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); ++ __ j(not_equal, ¬_outermost_js, Label::kNear); ++ __ mov(Operand::StaticVariable(js_entry_sp), ebp); ++ __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); ++ __ jmp(&invoke, Label::kNear); ++ __ bind(¬_outermost_js); ++ __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); ++ ++ // Jump to a faked try block that does the invoke, with a faked catch ++ // block that sets the pending exception. ++ __ jmp(&invoke); ++ __ bind(&handler_entry); ++ handler_offset_ = handler_entry.pos(); ++ // Caught exception: Store result (exception) in the pending exception ++ // field in the JSEnv and return a failure sentinel. ++ ExternalReference pending_exception( ++ IsolateAddressId::kPendingExceptionAddress, isolate()); ++ __ mov(Operand::StaticVariable(pending_exception), eax); ++ __ mov(eax, Immediate(isolate()->factory()->exception())); ++ __ jmp(&exit); ++ ++ // Invoke: Link this frame into the handler chain. ++ __ bind(&invoke); ++ __ PushStackHandler(); ++ ++ // Fake a receiver (NULL). ++ __ push(Immediate(0)); // receiver ++ ++ // Invoke the function by calling through JS entry trampoline builtin and ++ // pop the faked function when we return. Notice that we cannot store a ++ // reference to the trampoline code directly in this stub, because the ++ // builtin stubs may not have been generated yet. ++ if (type() == StackFrame::ENTRY_CONSTRUCT) { ++ ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, ++ isolate()); ++ __ mov(edx, Immediate(construct_entry)); ++ } else { ++ ExternalReference entry(Builtins::kJSEntryTrampoline, isolate()); ++ __ mov(edx, Immediate(entry)); ++ } ++ __ mov(edx, Operand(edx, 0)); // deref address ++ __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); ++ __ call(edx); ++ ++ // Unlink this frame from the handler chain. ++ __ PopStackHandler(); ++ ++ __ bind(&exit); ++ // Check if the current stack frame is marked as the outermost JS frame. ++ __ pop(ebx); ++ __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); ++ __ j(not_equal, ¬_outermost_js_2); ++ __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); ++ __ bind(¬_outermost_js_2); ++ ++ // Restore the top frame descriptor from the stack. ++ __ pop(Operand::StaticVariable( ++ ExternalReference(IsolateAddressId::kCEntryFPAddress, isolate()))); ++ ++ // Restore callee-saved registers (C calling conventions). ++ __ pop(ebx); ++ __ pop(esi); ++ __ pop(edi); ++ __ add(esp, Immediate(2 * kPointerSize)); // remove markers ++ ++ // Restore frame pointer and return. ++ __ pop(ebp); ++ __ ret(0); ++} ++ ++ ++// ------------------------------------------------------------------------- ++// StringCharCodeAtGenerator ++ ++void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { ++ // If the receiver is a smi trigger the non-string case. ++ if (check_mode_ == RECEIVER_IS_UNKNOWN) { ++ __ JumpIfSmi(object_, receiver_not_string_); ++ ++ // Fetch the instance type of the receiver into result register. ++ __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); ++ __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); ++ // If the receiver is not a string trigger the non-string case. ++ __ test(result_, Immediate(kIsNotStringMask)); ++ __ j(not_zero, receiver_not_string_); ++ } ++ ++ // If the index is non-smi trigger the non-smi case. ++ __ JumpIfNotSmi(index_, &index_not_smi_); ++ __ bind(&got_smi_index_); ++ ++ // Check for index out of range. ++ __ cmp(index_, FieldOperand(object_, String::kLengthOffset)); ++ __ j(above_equal, index_out_of_range_); ++ ++ __ SmiUntag(index_); ++ ++ Factory* factory = masm->isolate()->factory(); ++ StringCharLoadGenerator::Generate( ++ masm, factory, object_, index_, result_, &call_runtime_); ++ ++ __ SmiTag(result_); ++ __ bind(&exit_); ++} ++ ++ ++void StringCharCodeAtGenerator::GenerateSlow( ++ MacroAssembler* masm, EmbedMode embed_mode, ++ const RuntimeCallHelper& call_helper) { ++ __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase); ++ ++ // Index is not a smi. ++ __ bind(&index_not_smi_); ++ // If index is a heap number, try converting it to an integer. ++ __ CheckMap(index_, ++ masm->isolate()->factory()->heap_number_map(), ++ index_not_number_, ++ DONT_DO_SMI_CHECK); ++ call_helper.BeforeCall(masm); ++ if (embed_mode == PART_OF_IC_HANDLER) { ++ __ push(LoadWithVectorDescriptor::VectorRegister()); ++ __ push(LoadDescriptor::SlotRegister()); ++ } ++ __ push(object_); ++ __ push(index_); // Consumed by runtime conversion function. ++ __ CallRuntime(Runtime::kNumberToSmi); ++ if (!index_.is(eax)) { ++ // Save the conversion result before the pop instructions below ++ // have a chance to overwrite it. ++ __ mov(index_, eax); ++ } ++ __ pop(object_); ++ if (embed_mode == PART_OF_IC_HANDLER) { ++ __ pop(LoadDescriptor::SlotRegister()); ++ __ pop(LoadWithVectorDescriptor::VectorRegister()); ++ } ++ // Reload the instance type. ++ __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); ++ __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); ++ call_helper.AfterCall(masm); ++ // If index is still not a smi, it must be out of range. ++ STATIC_ASSERT(kSmiTag == 0); ++ __ JumpIfNotSmi(index_, index_out_of_range_); ++ // Otherwise, return to the fast path. ++ __ jmp(&got_smi_index_); ++ ++ // Call runtime. We get here when the receiver is a string and the ++ // index is a number, but the code of getting the actual character ++ // is too complex (e.g., when the string needs to be flattened). ++ __ bind(&call_runtime_); ++ call_helper.BeforeCall(masm); ++ __ push(object_); ++ __ SmiTag(index_); ++ __ push(index_); ++ __ CallRuntime(Runtime::kStringCharCodeAtRT); ++ if (!result_.is(eax)) { ++ __ mov(result_, eax); ++ } ++ call_helper.AfterCall(masm); ++ __ jmp(&exit_); ++ ++ __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase); ++} ++ ++void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm, ++ Register left, ++ Register right, ++ Register scratch1, ++ Register scratch2) { ++ Register length = scratch1; ++ ++ // Compare lengths. ++ Label strings_not_equal, check_zero_length; ++ __ mov(length, FieldOperand(left, String::kLengthOffset)); ++ __ cmp(length, FieldOperand(right, String::kLengthOffset)); ++ __ j(equal, &check_zero_length, Label::kNear); ++ __ bind(&strings_not_equal); ++ __ Move(eax, Immediate(Smi::FromInt(NOT_EQUAL))); ++ __ ret(0); ++ ++ // Check if the length is zero. ++ Label compare_chars; ++ __ bind(&check_zero_length); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ test(length, length); ++ __ j(not_zero, &compare_chars, Label::kNear); ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ ret(0); ++ ++ // Compare characters. ++ __ bind(&compare_chars); ++ GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2, ++ &strings_not_equal, Label::kNear); ++ ++ // Characters are equal. ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ ret(0); ++} ++ ++ ++void StringHelper::GenerateCompareFlatOneByteStrings( ++ MacroAssembler* masm, Register left, Register right, Register scratch1, ++ Register scratch2, Register scratch3) { ++ Counters* counters = masm->isolate()->counters(); ++ __ IncrementCounter(counters->string_compare_native(), 1); ++ ++ // Find minimum length. ++ Label left_shorter; ++ __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); ++ __ mov(scratch3, scratch1); ++ __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); ++ ++ Register length_delta = scratch3; ++ ++ __ j(less_equal, &left_shorter, Label::kNear); ++ // Right string is shorter. Change scratch1 to be length of right string. ++ __ sub(scratch1, length_delta); ++ __ bind(&left_shorter); ++ ++ Register min_length = scratch1; ++ ++ // If either length is zero, just compare lengths. ++ Label compare_lengths; ++ __ test(min_length, min_length); ++ __ j(zero, &compare_lengths, Label::kNear); ++ ++ // Compare characters. ++ Label result_not_equal; ++ GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2, ++ &result_not_equal, Label::kNear); ++ ++ // Compare lengths - strings up to min-length are equal. ++ __ bind(&compare_lengths); ++ __ test(length_delta, length_delta); ++ Label length_not_equal; ++ __ j(not_zero, &length_not_equal, Label::kNear); ++ ++ // Result is EQUAL. ++ STATIC_ASSERT(EQUAL == 0); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ ret(0); ++ ++ Label result_greater; ++ Label result_less; ++ __ bind(&length_not_equal); ++ __ j(greater, &result_greater, Label::kNear); ++ __ jmp(&result_less, Label::kNear); ++ __ bind(&result_not_equal); ++ __ j(above, &result_greater, Label::kNear); ++ __ bind(&result_less); ++ ++ // Result is LESS. ++ __ Move(eax, Immediate(Smi::FromInt(LESS))); ++ __ ret(0); ++ ++ // Result is GREATER. ++ __ bind(&result_greater); ++ __ Move(eax, Immediate(Smi::FromInt(GREATER))); ++ __ ret(0); ++} ++ ++ ++void StringHelper::GenerateOneByteCharsCompareLoop( ++ MacroAssembler* masm, Register left, Register right, Register length, ++ Register scratch, Label* chars_not_equal, ++ Label::Distance chars_not_equal_near) { ++ // Change index to run from -length to -1 by adding length to string ++ // start. This means that loop ends when index reaches zero, which ++ // doesn't need an additional compare. ++ __ SmiUntag(length); ++ __ lea(left, ++ FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize)); ++ __ lea(right, ++ FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize)); ++ __ neg(length); ++ Register index = length; // index = -length; ++ ++ // Compare loop. ++ Label loop; ++ __ bind(&loop); ++ __ mov_b(scratch, Operand(left, index, times_1, 0)); ++ __ cmpb(scratch, Operand(right, index, times_1, 0)); ++ __ j(not_equal, chars_not_equal, chars_not_equal_near); ++ __ inc(index); ++ __ j(not_zero, &loop); ++} ++ ++ ++void CompareICStub::GenerateBooleans(MacroAssembler* masm) { ++ DCHECK_EQ(CompareICState::BOOLEAN, state()); ++ Label miss; ++ Label::Distance const miss_distance = ++ masm->emit_debug_code() ? Label::kFar : Label::kNear; ++ ++ __ JumpIfSmi(edx, &miss, miss_distance); ++ __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); ++ __ JumpIfSmi(eax, &miss, miss_distance); ++ __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ JumpIfNotRoot(ecx, Heap::kBooleanMapRootIndex, &miss, miss_distance); ++ __ JumpIfNotRoot(ebx, Heap::kBooleanMapRootIndex, &miss, miss_distance); ++ if (!Token::IsEqualityOp(op())) { ++ __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset)); ++ __ AssertSmi(eax); ++ __ mov(edx, FieldOperand(edx, Oddball::kToNumberOffset)); ++ __ AssertSmi(edx); ++ __ xchg(eax, edx); ++ } ++ __ sub(eax, edx); ++ __ Ret(); ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateSmis(MacroAssembler* masm) { ++ DCHECK(state() == CompareICState::SMI); ++ Label miss; ++ __ mov(ecx, edx); ++ __ or_(ecx, eax); ++ __ JumpIfNotSmi(ecx, &miss, Label::kNear); ++ ++ if (GetCondition() == equal) { ++ // For equality we do not care about the sign of the result. ++ __ sub(eax, edx); ++ } else { ++ Label done; ++ __ sub(edx, eax); ++ __ j(no_overflow, &done, Label::kNear); ++ // Correct sign of result in case of overflow. ++ __ not_(edx); ++ __ bind(&done); ++ __ mov(eax, edx); ++ } ++ __ ret(0); ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateNumbers(MacroAssembler* masm) { ++ DCHECK(state() == CompareICState::NUMBER); ++ ++ Label generic_stub, check_left; ++ Label unordered, maybe_undefined1, maybe_undefined2; ++ Label miss; ++ ++ if (left() == CompareICState::SMI) { ++ __ JumpIfNotSmi(edx, &miss); ++ } ++ if (right() == CompareICState::SMI) { ++ __ JumpIfNotSmi(eax, &miss); ++ } ++ ++ // Inlining the double comparison and falling back to the general compare ++ // stub if NaN is involved or SSE2 or CMOV is unsupported. ++ __ JumpIfSmi(eax, &check_left, Label::kNear); ++ __ cmp(FieldOperand(eax, HeapObject::kMapOffset), ++ isolate()->factory()->heap_number_map()); ++ __ j(not_equal, &maybe_undefined1, Label::kNear); ++ ++ __ bind(&check_left); ++ __ JumpIfSmi(edx, &generic_stub, Label::kNear); ++ __ cmp(FieldOperand(edx, HeapObject::kMapOffset), ++ isolate()->factory()->heap_number_map()); ++ __ j(not_equal, &maybe_undefined2, Label::kNear); ++ ++ __ bind(&unordered); ++ __ bind(&generic_stub); ++ CompareICStub stub(isolate(), op(), CompareICState::GENERIC, ++ CompareICState::GENERIC, CompareICState::GENERIC); ++ __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); ++ ++ __ bind(&maybe_undefined1); ++ if (Token::IsOrderedRelationalCompareOp(op())) { ++ __ cmp(eax, Immediate(isolate()->factory()->undefined_value())); ++ __ j(not_equal, &miss); ++ __ JumpIfSmi(edx, &unordered); ++ __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); ++ __ j(not_equal, &maybe_undefined2, Label::kNear); ++ __ jmp(&unordered); ++ } ++ ++ __ bind(&maybe_undefined2); ++ if (Token::IsOrderedRelationalCompareOp(op())) { ++ __ cmp(edx, Immediate(isolate()->factory()->undefined_value())); ++ __ j(equal, &unordered); ++ } ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) { ++ DCHECK(state() == CompareICState::INTERNALIZED_STRING); ++ DCHECK(GetCondition() == equal); ++ ++ // Registers containing left and right operands respectively. ++ Register left = edx; ++ Register right = eax; ++ Register tmp1 = ecx; ++ Register tmp2 = ebx; ++ ++ // Check that both operands are heap objects. ++ Label miss; ++ __ mov(tmp1, left); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ and_(tmp1, right); ++ __ JumpIfSmi(tmp1, &miss, Label::kNear); ++ ++ // Check that both operands are internalized strings. ++ __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); ++ __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); ++ __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); ++ __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); ++ STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); ++ __ or_(tmp1, tmp2); ++ __ test(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); ++ __ j(not_zero, &miss, Label::kNear); ++ ++ // Internalized strings are compared by identity. ++ Label done; ++ __ cmp(left, right); ++ // Make sure eax is non-zero. At this point input operands are ++ // guaranteed to be non-zero. ++ DCHECK(right.is(eax)); ++ __ j(not_equal, &done, Label::kNear); ++ STATIC_ASSERT(EQUAL == 0); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ bind(&done); ++ __ ret(0); ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) { ++ DCHECK(state() == CompareICState::UNIQUE_NAME); ++ DCHECK(GetCondition() == equal); ++ ++ // Registers containing left and right operands respectively. ++ Register left = edx; ++ Register right = eax; ++ Register tmp1 = ecx; ++ Register tmp2 = ebx; ++ ++ // Check that both operands are heap objects. ++ Label miss; ++ __ mov(tmp1, left); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ and_(tmp1, right); ++ __ JumpIfSmi(tmp1, &miss, Label::kNear); ++ ++ // Check that both operands are unique names. This leaves the instance ++ // types loaded in tmp1 and tmp2. ++ __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); ++ __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); ++ __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); ++ __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); ++ ++ __ JumpIfNotUniqueNameInstanceType(tmp1, &miss, Label::kNear); ++ __ JumpIfNotUniqueNameInstanceType(tmp2, &miss, Label::kNear); ++ ++ // Unique names are compared by identity. ++ Label done; ++ __ cmp(left, right); ++ // Make sure eax is non-zero. At this point input operands are ++ // guaranteed to be non-zero. ++ DCHECK(right.is(eax)); ++ __ j(not_equal, &done, Label::kNear); ++ STATIC_ASSERT(EQUAL == 0); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ bind(&done); ++ __ ret(0); ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateStrings(MacroAssembler* masm) { ++ DCHECK(state() == CompareICState::STRING); ++ Label miss; ++ ++ bool equality = Token::IsEqualityOp(op()); ++ ++ // Registers containing left and right operands respectively. ++ Register left = edx; ++ Register right = eax; ++ Register tmp1 = ecx; ++ Register tmp2 = ebx; ++ Register tmp3 = edi; ++ ++ // Check that both operands are heap objects. ++ __ mov(tmp1, left); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ and_(tmp1, right); ++ __ JumpIfSmi(tmp1, &miss); ++ ++ // Check that both operands are strings. This leaves the instance ++ // types loaded in tmp1 and tmp2. ++ __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); ++ __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); ++ __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); ++ __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); ++ __ mov(tmp3, tmp1); ++ STATIC_ASSERT(kNotStringTag != 0); ++ __ or_(tmp3, tmp2); ++ __ test(tmp3, Immediate(kIsNotStringMask)); ++ __ j(not_zero, &miss); ++ ++ // Fast check for identical strings. ++ Label not_same; ++ __ cmp(left, right); ++ __ j(not_equal, ¬_same, Label::kNear); ++ STATIC_ASSERT(EQUAL == 0); ++ STATIC_ASSERT(kSmiTag == 0); ++ __ Move(eax, Immediate(Smi::FromInt(EQUAL))); ++ __ ret(0); ++ ++ // Handle not identical strings. ++ __ bind(¬_same); ++ ++ // Check that both strings are internalized. If they are, we're done ++ // because we already know they are not identical. But in the case of ++ // non-equality compare, we still need to determine the order. We ++ // also know they are both strings. ++ if (equality) { ++ Label do_compare; ++ STATIC_ASSERT(kInternalizedTag == 0); ++ __ or_(tmp1, tmp2); ++ __ test(tmp1, Immediate(kIsNotInternalizedMask)); ++ __ j(not_zero, &do_compare, Label::kNear); ++ // Make sure eax is non-zero. At this point input operands are ++ // guaranteed to be non-zero. ++ DCHECK(right.is(eax)); ++ __ ret(0); ++ __ bind(&do_compare); ++ } ++ ++ // Check that both strings are sequential one-byte. ++ Label runtime; ++ __ JumpIfNotBothSequentialOneByteStrings(left, right, tmp1, tmp2, &runtime); ++ ++ // Compare flat one byte strings. Returns when done. ++ if (equality) { ++ StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1, ++ tmp2); ++ } else { ++ StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1, ++ tmp2, tmp3); ++ } ++ ++ // Handle more complex cases in runtime. ++ __ bind(&runtime); ++ if (equality) { ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(left); ++ __ Push(right); ++ __ CallRuntime(Runtime::kStringEqual); ++ } ++ __ sub(eax, Immediate(masm->isolate()->factory()->true_value())); ++ __ Ret(); ++ } else { ++ __ pop(tmp1); // Return address. ++ __ push(left); ++ __ push(right); ++ __ push(tmp1); ++ __ TailCallRuntime(Runtime::kStringCompare); ++ } ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateReceivers(MacroAssembler* masm) { ++ DCHECK_EQ(CompareICState::RECEIVER, state()); ++ Label miss; ++ __ mov(ecx, edx); ++ __ and_(ecx, eax); ++ __ JumpIfSmi(ecx, &miss, Label::kNear); ++ ++ STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); ++ __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(below, &miss, Label::kNear); ++ __ CmpObjectType(edx, FIRST_JS_RECEIVER_TYPE, ecx); ++ __ j(below, &miss, Label::kNear); ++ ++ DCHECK_EQ(equal, GetCondition()); ++ __ sub(eax, edx); ++ __ ret(0); ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) { ++ Label miss; ++ Handle cell = Map::WeakCellForMap(known_map_); ++ __ mov(ecx, edx); ++ __ and_(ecx, eax); ++ __ JumpIfSmi(ecx, &miss, Label::kNear); ++ ++ __ GetWeakValue(edi, cell); ++ __ cmp(edi, FieldOperand(eax, HeapObject::kMapOffset)); ++ __ j(not_equal, &miss, Label::kNear); ++ __ cmp(edi, FieldOperand(edx, HeapObject::kMapOffset)); ++ __ j(not_equal, &miss, Label::kNear); ++ ++ if (Token::IsEqualityOp(op())) { ++ __ sub(eax, edx); ++ __ ret(0); ++ } else { ++ __ PopReturnAddressTo(ecx); ++ __ Push(edx); ++ __ Push(eax); ++ __ Push(Immediate(Smi::FromInt(NegativeComparisonResult(GetCondition())))); ++ __ PushReturnAddressFrom(ecx); ++ __ TailCallRuntime(Runtime::kCompare); ++ } ++ ++ __ bind(&miss); ++ GenerateMiss(masm); ++} ++ ++ ++void CompareICStub::GenerateMiss(MacroAssembler* masm) { ++ { ++ // Call the runtime system in a fresh internal frame. ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ push(edx); // Preserve edx and eax. ++ __ push(eax); ++ __ push(edx); // And also use them as the arguments. ++ __ push(eax); ++ __ push(Immediate(Smi::FromInt(op()))); ++ __ CallRuntime(Runtime::kCompareIC_Miss); ++ // Compute the entry point of the rewritten stub. ++ __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); ++ __ pop(eax); ++ __ pop(edx); ++ } ++ ++ // Do a tail call to the rewritten stub. ++ __ jmp(edi); ++} ++ ++ ++// Helper function used to check that the dictionary doesn't contain ++// the property. This function may return false negatives, so miss_label ++// must always call a backup property check that is complete. ++// This function is safe to call if the receiver has fast properties. ++// Name must be a unique name and receiver must be a heap object. ++void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, ++ Label* miss, ++ Label* done, ++ Register properties, ++ Handle name, ++ Register r0) { ++ DCHECK(name->IsUniqueName()); ++ ++ // If names of slots in range from 1 to kProbes - 1 for the hash value are ++ // not equal to the name and kProbes-th slot is not used (its name is the ++ // undefined value), it guarantees the hash table doesn't contain the ++ // property. It's true even if some slots represent deleted properties ++ // (their names are the hole value). ++ for (int i = 0; i < kInlinedProbes; i++) { ++ // Compute the masked index: (hash + i + i * i) & mask. ++ Register index = r0; ++ // Capacity is smi 2^n. ++ __ mov(index, FieldOperand(properties, kCapacityOffset)); ++ __ dec(index); ++ __ and_(index, ++ Immediate(Smi::FromInt(name->Hash() + ++ NameDictionary::GetProbeOffset(i)))); ++ ++ // Scale the index by multiplying by the entry size. ++ STATIC_ASSERT(NameDictionary::kEntrySize == 3); ++ __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. ++ Register entity_name = r0; ++ // Having undefined at this place means the name is not contained. ++ STATIC_ASSERT(kSmiTagSize == 1); ++ __ mov(entity_name, Operand(properties, index, times_half_pointer_size, ++ kElementsStartOffset - kHeapObjectTag)); ++ __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); ++ __ j(equal, done); ++ ++ // Stop if found the property. ++ __ cmp(entity_name, Handle(name)); ++ __ j(equal, miss); ++ ++ Label good; ++ // Check for the hole and skip. ++ __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); ++ __ j(equal, &good, Label::kNear); ++ ++ // Check if the entry name is not a unique name. ++ __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); ++ __ JumpIfNotUniqueNameInstanceType( ++ FieldOperand(entity_name, Map::kInstanceTypeOffset), miss); ++ __ bind(&good); ++ } ++ ++ NameDictionaryLookupStub stub(masm->isolate(), properties, r0, r0, ++ NEGATIVE_LOOKUP); ++ __ push(Immediate(Handle(name))); ++ __ push(Immediate(name->Hash())); ++ __ CallStub(&stub); ++ __ test(r0, r0); ++ __ j(not_zero, miss); ++ __ jmp(done); ++} ++ ++void NameDictionaryLookupStub::Generate(MacroAssembler* masm) { ++ // This stub overrides SometimesSetsUpAFrame() to return false. That means ++ // we cannot call anything that could cause a GC from this stub. ++ // Stack frame on entry: ++ // esp[0 * kPointerSize]: return address. ++ // esp[1 * kPointerSize]: key's hash. ++ // esp[2 * kPointerSize]: key. ++ // Registers: ++ // dictionary_: NameDictionary to probe. ++ // result_: used as scratch. ++ // index_: will hold an index of entry if lookup is successful. ++ // might alias with result_. ++ // Returns: ++ // result_ is zero if lookup failed, non zero otherwise. ++ ++ Label in_dictionary, maybe_in_dictionary, not_in_dictionary; ++ ++ Register scratch = result(); ++ ++ __ mov(scratch, FieldOperand(dictionary(), kCapacityOffset)); ++ __ dec(scratch); ++ __ SmiUntag(scratch); ++ __ push(scratch); ++ ++ // If names of slots in range from 1 to kProbes - 1 for the hash value are ++ // not equal to the name and kProbes-th slot is not used (its name is the ++ // undefined value), it guarantees the hash table doesn't contain the ++ // property. It's true even if some slots represent deleted properties ++ // (their names are the null value). ++ for (int i = kInlinedProbes; i < kTotalProbes; i++) { ++ // Compute the masked index: (hash + i + i * i) & mask. ++ __ mov(scratch, Operand(esp, 2 * kPointerSize)); ++ if (i > 0) { ++ __ add(scratch, Immediate(NameDictionary::GetProbeOffset(i))); ++ } ++ __ and_(scratch, Operand(esp, 0)); ++ ++ // Scale the index by multiplying by the entry size. ++ STATIC_ASSERT(NameDictionary::kEntrySize == 3); ++ __ lea(index(), Operand(scratch, scratch, times_2, 0)); // index *= 3. ++ ++ // Having undefined at this place means the name is not contained. ++ STATIC_ASSERT(kSmiTagSize == 1); ++ __ mov(scratch, Operand(dictionary(), index(), times_pointer_size, ++ kElementsStartOffset - kHeapObjectTag)); ++ __ cmp(scratch, isolate()->factory()->undefined_value()); ++ __ j(equal, ¬_in_dictionary); ++ ++ // Stop if found the property. ++ __ cmp(scratch, Operand(esp, 3 * kPointerSize)); ++ __ j(equal, &in_dictionary); ++ ++ if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) { ++ // If we hit a key that is not a unique name during negative ++ // lookup we have to bailout as this key might be equal to the ++ // key we are looking for. ++ ++ // Check if the entry name is not a unique name. ++ __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); ++ __ JumpIfNotUniqueNameInstanceType( ++ FieldOperand(scratch, Map::kInstanceTypeOffset), ++ &maybe_in_dictionary); ++ } ++ } ++ ++ __ bind(&maybe_in_dictionary); ++ // If we are doing negative lookup then probing failure should be ++ // treated as a lookup success. For positive lookup probing failure ++ // should be treated as lookup failure. ++ if (mode() == POSITIVE_LOOKUP) { ++ __ mov(result(), Immediate(0)); ++ __ Drop(1); ++ __ ret(2 * kPointerSize); ++ } ++ ++ __ bind(&in_dictionary); ++ __ mov(result(), Immediate(1)); ++ __ Drop(1); ++ __ ret(2 * kPointerSize); ++ ++ __ bind(¬_in_dictionary); ++ __ mov(result(), Immediate(0)); ++ __ Drop(1); ++ __ ret(2 * kPointerSize); ++} ++ ++ ++void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( ++ Isolate* isolate) { ++ StoreBufferOverflowStub stub(isolate, kDontSaveFPRegs); ++ stub.GetCode(); ++ StoreBufferOverflowStub stub2(isolate, kSaveFPRegs); ++ stub2.GetCode(); ++} ++ ++ ++// Takes the input in 3 registers: address_ value_ and object_. A pointer to ++// the value has just been written into the object, now this stub makes sure ++// we keep the GC informed. The word in the object where the value has been ++// written is in the address register. ++void RecordWriteStub::Generate(MacroAssembler* masm) { ++ Label skip_to_incremental_noncompacting; ++ Label skip_to_incremental_compacting; ++ ++ // The first two instructions are generated with labels so as to get the ++ // offset fixed up correctly by the bind(Label*) call. We patch it back and ++ // forth between a compare instructions (a nop in this position) and the ++ // real branch when we start and stop incremental heap marking. ++ __ jmp(&skip_to_incremental_noncompacting, Label::kNear); ++ __ jmp(&skip_to_incremental_compacting, Label::kFar); ++ ++ if (remembered_set_action() == EMIT_REMEMBERED_SET) { ++ __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), ++ MacroAssembler::kReturnAtEnd); ++ } else { ++ __ ret(0); ++ } ++ ++ __ bind(&skip_to_incremental_noncompacting); ++ GenerateIncremental(masm, INCREMENTAL); ++ ++ __ bind(&skip_to_incremental_compacting); ++ GenerateIncremental(masm, INCREMENTAL_COMPACTION); ++ ++ // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. ++ // Will be checked in IncrementalMarking::ActivateGeneratedStub. ++ masm->set_byte_at(0, kTwoByteNopInstruction); ++ masm->set_byte_at(2, kFiveByteNopInstruction); ++} ++ ++ ++void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { ++ regs_.Save(masm); ++ ++ if (remembered_set_action() == EMIT_REMEMBERED_SET) { ++ Label dont_need_remembered_set; ++ ++ __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); ++ __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. ++ regs_.scratch0(), ++ &dont_need_remembered_set); ++ ++ __ JumpIfInNewSpace(regs_.object(), regs_.scratch0(), ++ &dont_need_remembered_set); ++ ++ // First notify the incremental marker if necessary, then update the ++ // remembered set. ++ CheckNeedsToInformIncrementalMarker( ++ masm, ++ kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, ++ mode); ++ InformIncrementalMarker(masm); ++ regs_.Restore(masm); ++ __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), ++ MacroAssembler::kReturnAtEnd); ++ ++ __ bind(&dont_need_remembered_set); ++ } ++ ++ CheckNeedsToInformIncrementalMarker( ++ masm, ++ kReturnOnNoNeedToInformIncrementalMarker, ++ mode); ++ InformIncrementalMarker(masm); ++ regs_.Restore(masm); ++ __ ret(0); ++} ++ ++ ++void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) { ++ regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode()); ++ int argument_count = 3; ++ __ PrepareCallCFunction(argument_count, regs_.scratch0()); ++ __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); ++ __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. ++ __ mov(Operand(esp, 2 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ ++ AllowExternalCallThatCantCauseGC scope(masm); ++ __ CallCFunction( ++ ExternalReference::incremental_marking_record_write_function(isolate()), ++ argument_count); ++ ++ regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode()); ++} ++ ++ ++void RecordWriteStub::CheckNeedsToInformIncrementalMarker( ++ MacroAssembler* masm, ++ OnNoNeedToInformIncrementalMarker on_no_need, ++ Mode mode) { ++ Label need_incremental, need_incremental_pop_object; ++ ++#ifndef V8_CONCURRENT_MARKING ++ Label object_is_black; ++ // Let's look at the color of the object: If it is not black we don't have ++ // to inform the incremental marker. ++ __ JumpIfBlack(regs_.object(), ++ regs_.scratch0(), ++ regs_.scratch1(), ++ &object_is_black, ++ Label::kNear); ++ ++ regs_.Restore(masm); ++ if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { ++ __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), ++ MacroAssembler::kReturnAtEnd); ++ } else { ++ __ ret(0); ++ } ++ ++ __ bind(&object_is_black); ++#endif ++ ++ // Get the value from the slot. ++ __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); ++ ++ if (mode == INCREMENTAL_COMPACTION) { ++ Label ensure_not_white; ++ ++ __ CheckPageFlag(regs_.scratch0(), // Contains value. ++ regs_.scratch1(), // Scratch. ++ MemoryChunk::kEvacuationCandidateMask, ++ zero, ++ &ensure_not_white, ++ Label::kNear); ++ ++ __ CheckPageFlag(regs_.object(), ++ regs_.scratch1(), // Scratch. ++ MemoryChunk::kSkipEvacuationSlotsRecordingMask, ++ not_zero, ++ &ensure_not_white, ++ Label::kNear); ++ ++ __ jmp(&need_incremental); ++ ++ __ bind(&ensure_not_white); ++ } ++ ++ // We need an extra register for this, so we push the object register ++ // temporarily. ++ __ push(regs_.object()); ++ __ JumpIfWhite(regs_.scratch0(), // The value. ++ regs_.scratch1(), // Scratch. ++ regs_.object(), // Scratch. ++ &need_incremental_pop_object, Label::kNear); ++ __ pop(regs_.object()); ++ ++ regs_.Restore(masm); ++ if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { ++ __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(), ++ MacroAssembler::kReturnAtEnd); ++ } else { ++ __ ret(0); ++ } ++ ++ __ bind(&need_incremental_pop_object); ++ __ pop(regs_.object()); ++ ++ __ bind(&need_incremental); ++ ++ // Fall through when we need to inform the incremental marker. ++} ++ ++ ++void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { ++ if (masm->isolate()->function_entry_hook() != NULL) { ++ ProfileEntryHookStub stub(masm->isolate()); ++ masm->CallStub(&stub); ++ } ++} ++ ++void ProfileEntryHookStub::Generate(MacroAssembler* masm) { ++ // Save volatile registers. ++ const int kNumSavedRegisters = 3; ++ __ push(eax); ++ __ push(ecx); ++ __ push(edx); ++ ++ // Calculate and push the original stack pointer. ++ __ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize)); ++ __ push(eax); ++ ++ // Retrieve our return address and use it to calculate the calling ++ // function's address. ++ __ mov(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize)); ++ __ sub(eax, Immediate(Assembler::kCallInstructionLength)); ++ __ push(eax); ++ ++ // Call the entry hook. ++ DCHECK(isolate()->function_entry_hook() != NULL); ++ __ call(FUNCTION_ADDR(isolate()->function_entry_hook()), ++ RelocInfo::RUNTIME_ENTRY); ++ __ add(esp, Immediate(2 * kPointerSize)); ++ ++ // Restore ecx. ++ __ pop(edx); ++ __ pop(ecx); ++ __ pop(eax); ++ ++ __ ret(0); ++} ++ ++template ++static void CreateArrayDispatch(MacroAssembler* masm, ++ AllocationSiteOverrideMode mode) { ++ if (mode == DISABLE_ALLOCATION_SITES) { ++ T stub(masm->isolate(), GetInitialFastElementsKind(), mode); ++ __ TailCallStub(&stub); ++ } else if (mode == DONT_OVERRIDE) { ++ int last_index = ++ GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); ++ for (int i = 0; i <= last_index; ++i) { ++ Label next; ++ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); ++ __ cmp(edx, kind); ++ __ j(not_equal, &next); ++ T stub(masm->isolate(), kind); ++ __ TailCallStub(&stub); ++ __ bind(&next); ++ } ++ ++ // If we reached this point there is a problem. ++ __ Abort(kUnexpectedElementsKindInArrayConstructor); ++ } else { ++ UNREACHABLE(); ++ } ++} ++ ++static void CreateArrayDispatchOneArgument(MacroAssembler* masm, ++ AllocationSiteOverrideMode mode) { ++ // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES) ++ // edx - kind (if mode != DISABLE_ALLOCATION_SITES) ++ // eax - number of arguments ++ // edi - constructor? ++ // esp[0] - return address ++ // esp[4] - last argument ++ Label normal_sequence; ++ if (mode == DONT_OVERRIDE) { ++ STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); ++ STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1); ++ STATIC_ASSERT(PACKED_ELEMENTS == 2); ++ STATIC_ASSERT(HOLEY_ELEMENTS == 3); ++ STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4); ++ STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5); ++ ++ // is the low bit set? If so, we are holey and that is good. ++ __ test_b(edx, Immediate(1)); ++ __ j(not_zero, &normal_sequence); ++ } ++ ++ // look at the first argument ++ __ mov(ecx, Operand(esp, kPointerSize)); ++ __ test(ecx, ecx); ++ __ j(zero, &normal_sequence); ++ ++ if (mode == DISABLE_ALLOCATION_SITES) { ++ ElementsKind initial = GetInitialFastElementsKind(); ++ ElementsKind holey_initial = GetHoleyElementsKind(initial); ++ ++ ArraySingleArgumentConstructorStub stub_holey( ++ masm->isolate(), holey_initial, DISABLE_ALLOCATION_SITES); ++ __ TailCallStub(&stub_holey); ++ ++ __ bind(&normal_sequence); ++ ArraySingleArgumentConstructorStub stub(masm->isolate(), initial, ++ DISABLE_ALLOCATION_SITES); ++ __ TailCallStub(&stub); ++ } else if (mode == DONT_OVERRIDE) { ++ // We are going to create a holey array, but our kind is non-holey. ++ // Fix kind and retry. ++ __ inc(edx); ++ ++ if (FLAG_debug_code) { ++ Handle allocation_site_map = ++ masm->isolate()->factory()->allocation_site_map(); ++ __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map)); ++ __ Assert(equal, kExpectedAllocationSite); ++ } ++ ++ // Save the resulting elements kind in type info. We can't just store r3 ++ // in the AllocationSite::transition_info field because elements kind is ++ // restricted to a portion of the field...upper bits need to be left alone. ++ STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); ++ __ add( ++ FieldOperand(ebx, AllocationSite::kTransitionInfoOrBoilerplateOffset), ++ Immediate(Smi::FromInt(kFastElementsKindPackedToHoley))); ++ ++ __ bind(&normal_sequence); ++ int last_index = ++ GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); ++ for (int i = 0; i <= last_index; ++i) { ++ Label next; ++ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); ++ __ cmp(edx, kind); ++ __ j(not_equal, &next); ++ ArraySingleArgumentConstructorStub stub(masm->isolate(), kind); ++ __ TailCallStub(&stub); ++ __ bind(&next); ++ } ++ ++ // If we reached this point there is a problem. ++ __ Abort(kUnexpectedElementsKindInArrayConstructor); ++ } else { ++ UNREACHABLE(); ++ } ++} ++ ++template ++static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { ++ int to_index = ++ GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); ++ for (int i = 0; i <= to_index; ++i) { ++ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); ++ T stub(isolate, kind); ++ stub.GetCode(); ++ if (AllocationSite::ShouldTrack(kind)) { ++ T stub1(isolate, kind, DISABLE_ALLOCATION_SITES); ++ stub1.GetCode(); ++ } ++ } ++} ++ ++void CommonArrayConstructorStub::GenerateStubsAheadOfTime(Isolate* isolate) { ++ ArrayConstructorStubAheadOfTimeHelper( ++ isolate); ++ ArrayConstructorStubAheadOfTimeHelper( ++ isolate); ++ ArrayNArgumentsConstructorStub stub(isolate); ++ stub.GetCode(); ++ ++ ElementsKind kinds[2] = {PACKED_ELEMENTS, HOLEY_ELEMENTS}; ++ for (int i = 0; i < 2; i++) { ++ // For internal arrays we only need a few things ++ InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]); ++ stubh1.GetCode(); ++ InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]); ++ stubh2.GetCode(); ++ } ++} ++ ++void ArrayConstructorStub::GenerateDispatchToArrayStub( ++ MacroAssembler* masm, AllocationSiteOverrideMode mode) { ++ Label not_zero_case, not_one_case; ++ __ test(eax, eax); ++ __ j(not_zero, ¬_zero_case); ++ CreateArrayDispatch(masm, mode); ++ ++ __ bind(¬_zero_case); ++ __ cmp(eax, 1); ++ __ j(greater, ¬_one_case); ++ CreateArrayDispatchOneArgument(masm, mode); ++ ++ __ bind(¬_one_case); ++ ArrayNArgumentsConstructorStub stub(masm->isolate()); ++ __ TailCallStub(&stub); ++} ++ ++void ArrayConstructorStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc (only if argument_count() is ANY or MORE_THAN_ONE) ++ // -- ebx : AllocationSite or undefined ++ // -- edi : constructor ++ // -- edx : Original constructor ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // ----------------------------------- ++ if (FLAG_debug_code) { ++ // The array construct code is only set for the global and natives ++ // builtin Array functions which always have maps. ++ ++ // Initial map for the builtin Array function should be a map. ++ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); ++ // Will both indicate a NULL and a Smi. ++ __ test(ecx, Immediate(kSmiTagMask)); ++ __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); ++ __ CmpObjectType(ecx, MAP_TYPE, ecx); ++ __ Assert(equal, kUnexpectedInitialMapForArrayFunction); ++ ++ // We should either have undefined in ebx or a valid AllocationSite ++ __ AssertUndefinedOrAllocationSite(ebx); ++ } ++ ++ Label subclassing; ++ ++ // Enter the context of the Array function. ++ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ __ cmp(edx, edi); ++ __ j(not_equal, &subclassing); ++ ++ Label no_info; ++ // If the feedback vector is the undefined value call an array constructor ++ // that doesn't use AllocationSites. ++ __ cmp(ebx, isolate()->factory()->undefined_value()); ++ __ j(equal, &no_info); ++ ++ // Only look at the lower 16 bits of the transition info. ++ __ mov(edx, ++ FieldOperand(ebx, AllocationSite::kTransitionInfoOrBoilerplateOffset)); ++ __ SmiUntag(edx); ++ STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); ++ __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask)); ++ GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); ++ ++ __ bind(&no_info); ++ GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); ++ ++ // Subclassing. ++ __ bind(&subclassing); ++ __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); ++ __ add(eax, Immediate(3)); ++ __ PopReturnAddressTo(ecx); ++ __ Push(edx); ++ __ Push(ebx); ++ __ PushReturnAddressFrom(ecx); ++ __ JumpToExternalReference(ExternalReference(Runtime::kNewArray, isolate())); ++} ++ ++void InternalArrayConstructorStub::GenerateCase(MacroAssembler* masm, ++ ElementsKind kind) { ++ Label not_zero_case, not_one_case; ++ Label normal_sequence; ++ ++ __ test(eax, eax); ++ __ j(not_zero, ¬_zero_case); ++ InternalArrayNoArgumentConstructorStub stub0(isolate(), kind); ++ __ TailCallStub(&stub0); ++ ++ __ bind(¬_zero_case); ++ __ cmp(eax, 1); ++ __ j(greater, ¬_one_case); ++ ++ if (IsFastPackedElementsKind(kind)) { ++ // We might need to create a holey array ++ // look at the first argument ++ __ mov(ecx, Operand(esp, kPointerSize)); ++ __ test(ecx, ecx); ++ __ j(zero, &normal_sequence); ++ ++ InternalArraySingleArgumentConstructorStub stub1_holey( ++ isolate(), GetHoleyElementsKind(kind)); ++ __ TailCallStub(&stub1_holey); ++ } ++ ++ __ bind(&normal_sequence); ++ InternalArraySingleArgumentConstructorStub stub1(isolate(), kind); ++ __ TailCallStub(&stub1); ++ ++ __ bind(¬_one_case); ++ ArrayNArgumentsConstructorStub stubN(isolate()); ++ __ TailCallStub(&stubN); ++} ++ ++void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- eax : argc ++ // -- edi : constructor ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // ----------------------------------- ++ ++ if (FLAG_debug_code) { ++ // The array construct code is only set for the global and natives ++ // builtin Array functions which always have maps. ++ ++ // Initial map for the builtin Array function should be a map. ++ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); ++ // Will both indicate a NULL and a Smi. ++ __ test(ecx, Immediate(kSmiTagMask)); ++ __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); ++ __ CmpObjectType(ecx, MAP_TYPE, ecx); ++ __ Assert(equal, kUnexpectedInitialMapForArrayFunction); ++ } ++ ++ // Figure out the right elements kind ++ __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); ++ ++ // Load the map's "bit field 2" into |result|. We only need the first byte, ++ // but the following masking takes care of that anyway. ++ __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); ++ // Retrieve elements_kind from bit field 2. ++ __ DecodeField(ecx); ++ ++ if (FLAG_debug_code) { ++ Label done; ++ __ cmp(ecx, Immediate(PACKED_ELEMENTS)); ++ __ j(equal, &done); ++ __ cmp(ecx, Immediate(HOLEY_ELEMENTS)); ++ __ Assert(equal, kInvalidElementsKindForInternalArrayOrInternalPackedArray); ++ __ bind(&done); ++ } ++ ++ Label fast_elements_case; ++ __ cmp(ecx, Immediate(PACKED_ELEMENTS)); ++ __ j(equal, &fast_elements_case); ++ GenerateCase(masm, HOLEY_ELEMENTS); ++ ++ __ bind(&fast_elements_case); ++ GenerateCase(masm, PACKED_ELEMENTS); ++} ++ ++void FastNewRestParameterStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edi : function ++ // -- esi : context ++ // -- ebp : frame pointer ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // Make edx point to the JavaScript frame. ++ __ mov(edx, ebp); ++ if (skip_stub_frame()) { ++ // For Ignition we need to skip the handler/stub frame to reach the ++ // JavaScript frame for the function. ++ __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); ++ } ++ if (FLAG_debug_code) { ++ Label ok; ++ __ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset)); ++ __ j(equal, &ok); ++ __ Abort(kInvalidFrameForFastNewRestArgumentsStub); ++ __ bind(&ok); ++ } ++ ++ // Check if we have rest parameters (only possible if we have an ++ // arguments adaptor frame below the function frame). ++ Label no_rest_parameters; ++ __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); ++ __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(not_equal, &no_rest_parameters, Label::kNear); ++ ++ // Check if the arguments adaptor frame contains more arguments than ++ // specified by the function's internal formal parameter count. ++ Label rest_parameters; ++ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ sub(eax, ++ FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); ++ __ j(greater, &rest_parameters); ++ ++ // Return an empty rest parameter array. ++ __ bind(&no_rest_parameters); ++ { ++ // ----------- S t a t e ------------- ++ // -- esi : context ++ // -- esp[0] : return address ++ // ----------------------------------- ++ ++ // Allocate an empty rest parameter array. ++ Label allocate, done_allocate; ++ __ Allocate(JSArray::kSize, eax, edx, ecx, &allocate, NO_ALLOCATION_FLAGS); ++ __ bind(&done_allocate); ++ ++ // Setup the rest parameter array in rax. ++ __ LoadGlobalFunction(Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX, ecx); ++ __ mov(FieldOperand(eax, JSArray::kMapOffset), ecx); ++ __ mov(ecx, isolate()->factory()->empty_fixed_array()); ++ __ mov(FieldOperand(eax, JSArray::kPropertiesOrHashOffset), ecx); ++ __ mov(FieldOperand(eax, JSArray::kElementsOffset), ecx); ++ __ mov(FieldOperand(eax, JSArray::kLengthOffset), Immediate(Smi::kZero)); ++ STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); ++ __ Ret(); ++ ++ // Fall back to %AllocateInNewSpace. ++ __ bind(&allocate); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ Push(Smi::FromInt(JSArray::kSize)); ++ __ CallRuntime(Runtime::kAllocateInNewSpace); ++ } ++ __ jmp(&done_allocate); ++ } ++ ++ __ bind(&rest_parameters); ++ { ++ // Compute the pointer to the first rest parameter (skippping the receiver). ++ __ lea(ebx, ++ Operand(ebx, eax, times_half_pointer_size, ++ StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); ++ ++ // ----------- S t a t e ------------- ++ // -- esi : context ++ // -- eax : number of rest parameters (tagged) ++ // -- ebx : pointer to first rest parameters ++ // -- esp[0] : return address ++ // ----------------------------------- ++ ++ // Allocate space for the rest parameter array plus the backing store. ++ Label allocate, done_allocate; ++ __ lea(ecx, Operand(eax, times_half_pointer_size, ++ JSArray::kSize + FixedArray::kHeaderSize)); ++ __ Allocate(ecx, edx, edi, no_reg, &allocate, NO_ALLOCATION_FLAGS); ++ __ bind(&done_allocate); ++ ++ // Setup the elements array in edx. ++ __ mov(FieldOperand(edx, FixedArray::kMapOffset), ++ isolate()->factory()->fixed_array_map()); ++ __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); ++ { ++ Label loop, done_loop; ++ __ Move(ecx, Smi::kZero); ++ __ bind(&loop); ++ __ cmp(ecx, eax); ++ __ j(equal, &done_loop, Label::kNear); ++ __ mov(edi, Operand(ebx, 0 * kPointerSize)); ++ __ mov(FieldOperand(edx, ecx, times_half_pointer_size, ++ FixedArray::kHeaderSize), ++ edi); ++ __ sub(ebx, Immediate(1 * kPointerSize)); ++ __ add(ecx, Immediate(Smi::FromInt(1))); ++ __ jmp(&loop); ++ __ bind(&done_loop); ++ } ++ ++ // Setup the rest parameter array in edi. ++ __ lea(edi, ++ Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); ++ __ LoadGlobalFunction(Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX, ecx); ++ __ mov(FieldOperand(edi, JSArray::kMapOffset), ecx); ++ __ mov(FieldOperand(edi, JSArray::kPropertiesOrHashOffset), ++ isolate()->factory()->empty_fixed_array()); ++ __ mov(FieldOperand(edi, JSArray::kElementsOffset), edx); ++ __ mov(FieldOperand(edi, JSArray::kLengthOffset), eax); ++ STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); ++ __ mov(eax, edi); ++ __ Ret(); ++ ++ // Fall back to %AllocateInNewSpace (if not too big). ++ Label too_big_for_new_space; ++ __ bind(&allocate); ++ __ cmp(ecx, Immediate(kMaxRegularHeapObjectSize)); ++ __ j(greater, &too_big_for_new_space); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ SmiTag(ecx); ++ __ Push(eax); ++ __ Push(ebx); ++ __ Push(ecx); ++ __ CallRuntime(Runtime::kAllocateInNewSpace); ++ __ mov(edx, eax); ++ __ Pop(ebx); ++ __ Pop(eax); ++ } ++ __ jmp(&done_allocate); ++ ++ // Fall back to %NewRestParameter. ++ __ bind(&too_big_for_new_space); ++ __ PopReturnAddressTo(ecx); ++ // We reload the function from the caller frame due to register pressure ++ // within this stub. This is the slow path, hence reloading is preferable. ++ if (skip_stub_frame()) { ++ // For Ignition we need to skip the handler/stub frame to reach the ++ // JavaScript frame for the function. ++ __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ Push(Operand(edx, StandardFrameConstants::kFunctionOffset)); ++ } else { ++ __ Push(Operand(ebp, StandardFrameConstants::kFunctionOffset)); ++ } ++ __ PushReturnAddressFrom(ecx); ++ __ TailCallRuntime(Runtime::kNewRestParameter); ++ } ++} ++ ++void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edi : function ++ // -- esi : context ++ // -- ebp : frame pointer ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // Make ecx point to the JavaScript frame. ++ __ mov(ecx, ebp); ++ if (skip_stub_frame()) { ++ // For Ignition we need to skip the handler/stub frame to reach the ++ // JavaScript frame for the function. ++ __ mov(ecx, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); ++ } ++ if (FLAG_debug_code) { ++ Label ok; ++ __ cmp(edi, Operand(ecx, StandardFrameConstants::kFunctionOffset)); ++ __ j(equal, &ok); ++ __ Abort(kInvalidFrameForFastNewSloppyArgumentsStub); ++ __ bind(&ok); ++ } ++ ++ // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub. ++ __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(ebx, ++ FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); ++ __ lea(edx, Operand(ecx, ebx, times_half_pointer_size, ++ StandardFrameConstants::kCallerSPOffset)); ++ ++ // ebx : number of parameters (tagged) ++ // edx : parameters pointer ++ // edi : function ++ // ecx : JavaScript frame pointer. ++ // esp[0] : return address ++ ++ // Check if the calling frame is an arguments adaptor frame. ++ Label adaptor_frame, try_allocate, runtime; ++ __ mov(eax, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); ++ __ mov(eax, Operand(eax, CommonFrameConstants::kContextOrFrameTypeOffset)); ++ __ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(equal, &adaptor_frame, Label::kNear); ++ ++ // No adaptor, parameter count = argument count. ++ __ mov(ecx, ebx); ++ __ push(ebx); ++ __ jmp(&try_allocate, Label::kNear); ++ ++ // We have an adaptor frame. Patch the parameters pointer. ++ __ bind(&adaptor_frame); ++ __ push(ebx); ++ __ mov(edx, Operand(ecx, StandardFrameConstants::kCallerFPOffset)); ++ __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ lea(edx, ++ Operand(edx, ecx, times_2, StandardFrameConstants::kCallerSPOffset)); ++ ++ // ebx = parameter count (tagged) ++ // ecx = argument count (smi-tagged) ++ // Compute the mapped parameter count = min(ebx, ecx) in ebx. ++ __ cmp(ebx, ecx); ++ __ j(less_equal, &try_allocate, Label::kNear); ++ __ mov(ebx, ecx); ++ ++ // Save mapped parameter count and function. ++ __ bind(&try_allocate); ++ __ push(edi); ++ __ push(ebx); ++ ++ // Compute the sizes of backing store, parameter map, and arguments object. ++ // 1. Parameter map, has 2 extra words containing context and backing store. ++ const int kParameterMapHeaderSize = ++ FixedArray::kHeaderSize + 2 * kPointerSize; ++ Label no_parameter_map; ++ __ test(ebx, ebx); ++ __ j(zero, &no_parameter_map, Label::kNear); ++ __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); ++ __ bind(&no_parameter_map); ++ ++ // 2. Backing store. ++ __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); ++ ++ // 3. Arguments object. ++ __ add(ebx, Immediate(JSSloppyArgumentsObject::kSize)); ++ ++ // Do the allocation of all three objects in one go. ++ __ Allocate(ebx, eax, edi, no_reg, &runtime, NO_ALLOCATION_FLAGS); ++ ++ // eax = address of new object(s) (tagged) ++ // ecx = argument count (smi-tagged) ++ // esp[0] = mapped parameter count (tagged) ++ // esp[4] = function ++ // esp[8] = parameter count (tagged) ++ // Get the arguments map from the current native context into edi. ++ Label has_mapped_parameters, instantiate; ++ __ mov(edi, NativeContextOperand()); ++ __ mov(ebx, Operand(esp, 0 * kPointerSize)); ++ __ test(ebx, ebx); ++ __ j(not_zero, &has_mapped_parameters, Label::kNear); ++ __ mov( ++ edi, ++ Operand(edi, Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX))); ++ __ jmp(&instantiate, Label::kNear); ++ ++ __ bind(&has_mapped_parameters); ++ __ mov(edi, Operand(edi, Context::SlotOffset( ++ Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX))); ++ __ bind(&instantiate); ++ ++ // eax = address of new object (tagged) ++ // ebx = mapped parameter count (tagged) ++ // ecx = argument count (smi-tagged) ++ // edi = address of arguments map (tagged) ++ // esp[0] = mapped parameter count (tagged) ++ // esp[4] = function ++ // esp[8] = parameter count (tagged) ++ // Copy the JS object part. ++ __ mov(FieldOperand(eax, JSObject::kMapOffset), edi); ++ __ mov(FieldOperand(eax, JSObject::kPropertiesOrHashOffset), ++ masm->isolate()->factory()->empty_fixed_array()); ++ __ mov(FieldOperand(eax, JSObject::kElementsOffset), ++ masm->isolate()->factory()->empty_fixed_array()); ++ ++ // Set up the callee in-object property. ++ STATIC_ASSERT(JSSloppyArgumentsObject::kCalleeIndex == 1); ++ __ mov(edi, Operand(esp, 1 * kPointerSize)); ++ __ AssertNotSmi(edi); ++ __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kCalleeOffset), edi); ++ ++ // Use the length (smi tagged) and set that as an in-object property too. ++ __ AssertSmi(ecx); ++ __ mov(FieldOperand(eax, JSSloppyArgumentsObject::kLengthOffset), ecx); ++ ++ // Set up the elements pointer in the allocated arguments object. ++ // If we allocated a parameter map, edi will point there, otherwise to the ++ // backing store. ++ __ lea(edi, Operand(eax, JSSloppyArgumentsObject::kSize)); ++ __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); ++ ++ // eax = address of new object (tagged) ++ // ebx = mapped parameter count (tagged) ++ // ecx = argument count (tagged) ++ // edx = address of receiver argument ++ // edi = address of parameter map or backing store (tagged) ++ // esp[0] = mapped parameter count (tagged) ++ // esp[4] = function ++ // esp[8] = parameter count (tagged) ++ // Free two registers. ++ __ push(edx); ++ __ push(eax); ++ ++ // Initialize parameter map. If there are no mapped arguments, we're done. ++ Label skip_parameter_map; ++ __ test(ebx, ebx); ++ __ j(zero, &skip_parameter_map); ++ ++ __ mov(FieldOperand(edi, FixedArray::kMapOffset), ++ Immediate(isolate()->factory()->sloppy_arguments_elements_map())); ++ __ lea(eax, Operand(ebx, reinterpret_cast(Smi::FromInt(2)))); ++ __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); ++ __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); ++ __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); ++ __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); ++ ++ // Copy the parameter slots and the holes in the arguments. ++ // We need to fill in mapped_parameter_count slots. They index the context, ++ // where parameters are stored in reverse order, at ++ // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 ++ // The mapped parameter thus need to get indices ++ // MIN_CONTEXT_SLOTS+parameter_count-1 .. ++ // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count ++ // We loop from right to left. ++ Label parameters_loop, parameters_test; ++ __ push(ecx); ++ __ mov(eax, Operand(esp, 3 * kPointerSize)); ++ __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); ++ __ add(ebx, Operand(esp, 5 * kPointerSize)); ++ __ sub(ebx, eax); ++ __ mov(ecx, isolate()->factory()->the_hole_value()); ++ __ mov(edx, edi); ++ __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); ++ // eax = loop variable (tagged) ++ // ebx = mapping index (tagged) ++ // ecx = the hole value ++ // edx = address of parameter map (tagged) ++ // edi = address of backing store (tagged) ++ // esp[0] = argument count (tagged) ++ // esp[4] = address of new object (tagged) ++ // esp[8] = address of receiver argument ++ // esp[12] = mapped parameter count (tagged) ++ // esp[16] = function ++ // esp[20] = parameter count (tagged) ++ __ jmp(¶meters_test, Label::kNear); ++ ++ __ bind(¶meters_loop); ++ __ sub(eax, Immediate(Smi::FromInt(1))); ++ __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); ++ __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); ++ __ add(ebx, Immediate(Smi::FromInt(1))); ++ __ bind(¶meters_test); ++ __ test(eax, eax); ++ __ j(not_zero, ¶meters_loop, Label::kNear); ++ __ pop(ecx); ++ ++ __ bind(&skip_parameter_map); ++ ++ // ecx = argument count (tagged) ++ // edi = address of backing store (tagged) ++ // esp[0] = address of new object (tagged) ++ // esp[4] = address of receiver argument ++ // esp[8] = mapped parameter count (tagged) ++ // esp[12] = function ++ // esp[16] = parameter count (tagged) ++ // Copy arguments header and remaining slots (if there are any). ++ __ mov(FieldOperand(edi, FixedArray::kMapOffset), ++ Immediate(isolate()->factory()->fixed_array_map())); ++ __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); ++ ++ Label arguments_loop, arguments_test; ++ __ mov(ebx, Operand(esp, 2 * kPointerSize)); ++ __ mov(edx, Operand(esp, 1 * kPointerSize)); ++ __ sub(edx, ebx); // Is there a smarter way to do negative scaling? ++ __ sub(edx, ebx); ++ __ jmp(&arguments_test, Label::kNear); ++ ++ __ bind(&arguments_loop); ++ __ sub(edx, Immediate(kPointerSize)); ++ __ mov(eax, Operand(edx, 0)); ++ __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); ++ __ add(ebx, Immediate(Smi::FromInt(1))); ++ ++ __ bind(&arguments_test); ++ __ cmp(ebx, ecx); ++ __ j(less, &arguments_loop, Label::kNear); ++ ++ // Restore. ++ __ pop(eax); // Address of arguments object. ++ __ Drop(4); ++ ++ // Return. ++ __ ret(0); ++ ++ // Do the runtime call to allocate the arguments object. ++ __ bind(&runtime); ++ __ pop(eax); // Remove saved mapped parameter count. ++ __ pop(edi); // Pop saved function. ++ __ pop(eax); // Remove saved parameter count. ++ __ pop(eax); // Pop return address. ++ __ push(edi); // Push function. ++ __ push(edx); // Push parameters pointer. ++ __ push(ecx); // Push parameter count. ++ __ push(eax); // Push return address. ++ __ TailCallRuntime(Runtime::kNewSloppyArguments); ++} ++ ++void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edi : function ++ // -- esi : context ++ // -- ebp : frame pointer ++ // -- esp[0] : return address ++ // ----------------------------------- ++ __ AssertFunction(edi); ++ ++ // Make edx point to the JavaScript frame. ++ __ mov(edx, ebp); ++ if (skip_stub_frame()) { ++ // For Ignition we need to skip the handler/stub frame to reach the ++ // JavaScript frame for the function. ++ __ mov(edx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); ++ } ++ if (FLAG_debug_code) { ++ Label ok; ++ __ cmp(edi, Operand(edx, StandardFrameConstants::kFunctionOffset)); ++ __ j(equal, &ok); ++ __ Abort(kInvalidFrameForFastNewStrictArgumentsStub); ++ __ bind(&ok); ++ } ++ ++ // Check if we have an arguments adaptor frame below the function frame. ++ Label arguments_adaptor, arguments_done; ++ __ mov(ebx, Operand(edx, StandardFrameConstants::kCallerFPOffset)); ++ __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); ++ __ j(equal, &arguments_adaptor, Label::kNear); ++ { ++ __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ __ mov(eax, ++ FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset)); ++ __ lea(ebx, ++ Operand(edx, eax, times_half_pointer_size, ++ StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); ++ } ++ __ jmp(&arguments_done, Label::kNear); ++ __ bind(&arguments_adaptor); ++ { ++ __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); ++ __ lea(ebx, ++ Operand(ebx, eax, times_half_pointer_size, ++ StandardFrameConstants::kCallerSPOffset - 1 * kPointerSize)); ++ } ++ __ bind(&arguments_done); ++ ++ // ----------- S t a t e ------------- ++ // -- eax : number of arguments (tagged) ++ // -- ebx : pointer to the first argument ++ // -- esi : context ++ // -- esp[0] : return address ++ // ----------------------------------- ++ ++ // Allocate space for the strict arguments object plus the backing store. ++ Label allocate, done_allocate; ++ __ lea(ecx, ++ Operand(eax, times_half_pointer_size, ++ JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize)); ++ __ Allocate(ecx, edx, edi, no_reg, &allocate, NO_ALLOCATION_FLAGS); ++ __ bind(&done_allocate); ++ ++ // Setup the elements array in edx. ++ __ mov(FieldOperand(edx, FixedArray::kMapOffset), ++ isolate()->factory()->fixed_array_map()); ++ __ mov(FieldOperand(edx, FixedArray::kLengthOffset), eax); ++ { ++ Label loop, done_loop; ++ __ Move(ecx, Smi::kZero); ++ __ bind(&loop); ++ __ cmp(ecx, eax); ++ __ j(equal, &done_loop, Label::kNear); ++ __ mov(edi, Operand(ebx, 0 * kPointerSize)); ++ __ mov(FieldOperand(edx, ecx, times_half_pointer_size, ++ FixedArray::kHeaderSize), ++ edi); ++ __ sub(ebx, Immediate(1 * kPointerSize)); ++ __ add(ecx, Immediate(Smi::FromInt(1))); ++ __ jmp(&loop); ++ __ bind(&done_loop); ++ } ++ ++ // Setup the rest parameter array in edi. ++ __ lea(edi, ++ Operand(edx, eax, times_half_pointer_size, FixedArray::kHeaderSize)); ++ __ LoadGlobalFunction(Context::STRICT_ARGUMENTS_MAP_INDEX, ecx); ++ __ mov(FieldOperand(edi, JSStrictArgumentsObject::kMapOffset), ecx); ++ __ mov(FieldOperand(edi, JSStrictArgumentsObject::kPropertiesOrHashOffset), ++ isolate()->factory()->empty_fixed_array()); ++ __ mov(FieldOperand(edi, JSStrictArgumentsObject::kElementsOffset), edx); ++ __ mov(FieldOperand(edi, JSStrictArgumentsObject::kLengthOffset), eax); ++ STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); ++ __ mov(eax, edi); ++ __ Ret(); ++ ++ // Fall back to %AllocateInNewSpace (if not too big). ++ Label too_big_for_new_space; ++ __ bind(&allocate); ++ __ cmp(ecx, Immediate(kMaxRegularHeapObjectSize)); ++ __ j(greater, &too_big_for_new_space); ++ { ++ FrameScope scope(masm, StackFrame::INTERNAL); ++ __ SmiTag(ecx); ++ __ Push(eax); ++ __ Push(ebx); ++ __ Push(ecx); ++ __ CallRuntime(Runtime::kAllocateInNewSpace); ++ __ mov(edx, eax); ++ __ Pop(ebx); ++ __ Pop(eax); ++ } ++ __ jmp(&done_allocate); ++ ++ // Fall back to %NewStrictArguments. ++ __ bind(&too_big_for_new_space); ++ __ PopReturnAddressTo(ecx); ++ // We reload the function from the caller frame due to register pressure ++ // within this stub. This is the slow path, hence reloading is preferable. ++ if (skip_stub_frame()) { ++ // For Ignition we need to skip the handler/stub frame to reach the ++ // JavaScript frame for the function. ++ __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ __ Push(Operand(edx, StandardFrameConstants::kFunctionOffset)); ++ } else { ++ __ Push(Operand(ebp, StandardFrameConstants::kFunctionOffset)); ++ } ++ __ PushReturnAddressFrom(ecx); ++ __ TailCallRuntime(Runtime::kNewStrictArguments); ++} ++ ++// Generates an Operand for saving parameters after PrepareCallApiFunction. ++static Operand ApiParameterOperand(int index) { ++ return Operand(esp, index * kPointerSize); ++} ++ ++ ++// Prepares stack to put arguments (aligns and so on). Reserves ++// space for return value if needed (assumes the return value is a handle). ++// Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1) ++// etc. Saves context (esi). If space was reserved for return value then ++// stores the pointer to the reserved slot into esi. ++static void PrepareCallApiFunction(MacroAssembler* masm, int argc) { ++ __ EnterApiExitFrame(argc); ++ if (__ emit_debug_code()) { ++ __ mov(esi, Immediate(bit_cast(kZapValue))); ++ } ++} ++ ++ ++// Calls an API function. Allocates HandleScope, extracts returned value ++// from handle and propagates exceptions. Clobbers ebx, edi and ++// caller-save registers. Restores context. On return removes ++// stack_space * kPointerSize (GCed). ++static void CallApiFunctionAndReturn(MacroAssembler* masm, ++ Register function_address, ++ ExternalReference thunk_ref, ++ Operand thunk_last_arg, int stack_space, ++ Operand* stack_space_operand, ++ Operand return_value_operand, ++ Operand* context_restore_operand) { ++ Isolate* isolate = masm->isolate(); ++ ++ ExternalReference next_address = ++ ExternalReference::handle_scope_next_address(isolate); ++ ExternalReference limit_address = ++ ExternalReference::handle_scope_limit_address(isolate); ++ ExternalReference level_address = ++ ExternalReference::handle_scope_level_address(isolate); ++ ++ DCHECK(edx.is(function_address)); ++ // Allocate HandleScope in callee-save registers. ++ __ mov(ebx, Operand::StaticVariable(next_address)); ++ __ mov(edi, Operand::StaticVariable(limit_address)); ++ __ add(Operand::StaticVariable(level_address), Immediate(1)); ++ ++ if (FLAG_log_timer_events) { ++ FrameScope frame(masm, StackFrame::MANUAL); ++ __ PushSafepointRegisters(); ++ __ PrepareCallCFunction(1, eax); ++ __ mov(Operand(esp, 0), ++ Immediate(ExternalReference::isolate_address(isolate))); ++ __ CallCFunction(ExternalReference::log_enter_external_function(isolate), ++ 1); ++ __ PopSafepointRegisters(); ++ } ++ ++ ++ Label profiler_disabled; ++ Label end_profiler_check; ++ __ mov(eax, Immediate(ExternalReference::is_profiling_address(isolate))); ++ __ cmpb(Operand(eax, 0), Immediate(0)); ++ __ j(zero, &profiler_disabled); ++ ++ // Additional parameter is the address of the actual getter function. ++ __ mov(thunk_last_arg, function_address); ++ // Call the api function. ++ __ mov(eax, Immediate(thunk_ref)); ++ __ call(eax); ++ __ jmp(&end_profiler_check); ++ ++ __ bind(&profiler_disabled); ++ // Call the api function. ++ __ call(function_address); ++ __ bind(&end_profiler_check); ++ ++ if (FLAG_log_timer_events) { ++ FrameScope frame(masm, StackFrame::MANUAL); ++ __ PushSafepointRegisters(); ++ __ PrepareCallCFunction(1, eax); ++ __ mov(Operand(esp, 0), ++ Immediate(ExternalReference::isolate_address(isolate))); ++ __ CallCFunction(ExternalReference::log_leave_external_function(isolate), ++ 1); ++ __ PopSafepointRegisters(); ++ } ++ ++ Label prologue; ++ // Load the value from ReturnValue ++ __ mov(eax, return_value_operand); ++ ++ Label promote_scheduled_exception; ++ Label delete_allocated_handles; ++ Label leave_exit_frame; ++ ++ __ bind(&prologue); ++ // No more valid handles (the result handle was the last one). Restore ++ // previous handle scope. ++ __ mov(Operand::StaticVariable(next_address), ebx); ++ __ sub(Operand::StaticVariable(level_address), Immediate(1)); ++ __ Assert(above_equal, kInvalidHandleScopeLevel); ++ __ cmp(edi, Operand::StaticVariable(limit_address)); ++ __ j(not_equal, &delete_allocated_handles); ++ ++ // Leave the API exit frame. ++ __ bind(&leave_exit_frame); ++ bool restore_context = context_restore_operand != NULL; ++ if (restore_context) { ++ __ mov(esi, *context_restore_operand); ++ } ++ if (stack_space_operand != nullptr) { ++ __ mov(ebx, *stack_space_operand); ++ } ++ __ LeaveApiExitFrame(!restore_context); ++ ++ // Check if the function scheduled an exception. ++ ExternalReference scheduled_exception_address = ++ ExternalReference::scheduled_exception_address(isolate); ++ __ cmp(Operand::StaticVariable(scheduled_exception_address), ++ Immediate(isolate->factory()->the_hole_value())); ++ __ j(not_equal, &promote_scheduled_exception); ++ ++#if DEBUG ++ // Check if the function returned a valid JavaScript value. ++ Label ok; ++ Register return_value = eax; ++ Register map = ecx; ++ ++ __ JumpIfSmi(return_value, &ok, Label::kNear); ++ __ mov(map, FieldOperand(return_value, HeapObject::kMapOffset)); ++ ++ __ CmpInstanceType(map, LAST_NAME_TYPE); ++ __ j(below_equal, &ok, Label::kNear); ++ ++ __ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE); ++ __ j(above_equal, &ok, Label::kNear); ++ ++ __ cmp(map, isolate->factory()->heap_number_map()); ++ __ j(equal, &ok, Label::kNear); ++ ++ __ cmp(return_value, isolate->factory()->undefined_value()); ++ __ j(equal, &ok, Label::kNear); ++ ++ __ cmp(return_value, isolate->factory()->true_value()); ++ __ j(equal, &ok, Label::kNear); ++ ++ __ cmp(return_value, isolate->factory()->false_value()); ++ __ j(equal, &ok, Label::kNear); ++ ++ __ cmp(return_value, isolate->factory()->null_value()); ++ __ j(equal, &ok, Label::kNear); ++ ++ __ Abort(kAPICallReturnedInvalidObject); ++ ++ __ bind(&ok); ++#endif ++ ++ if (stack_space_operand != nullptr) { ++ DCHECK_EQ(0, stack_space); ++ __ pop(ecx); ++ __ add(esp, ebx); ++ __ jmp(ecx); ++ } else { ++ __ ret(stack_space * kPointerSize); ++ } ++ ++ // Re-throw by promoting a scheduled exception. ++ __ bind(&promote_scheduled_exception); ++ __ TailCallRuntime(Runtime::kPromoteScheduledException); ++ ++ // HandleScope limit has changed. Delete allocated extensions. ++ ExternalReference delete_extensions = ++ ExternalReference::delete_handle_scope_extensions(isolate); ++ __ bind(&delete_allocated_handles); ++ __ mov(Operand::StaticVariable(limit_address), edi); ++ __ mov(edi, eax); ++ __ mov(Operand(esp, 0), ++ Immediate(ExternalReference::isolate_address(isolate))); ++ __ mov(eax, Immediate(delete_extensions)); ++ __ call(eax); ++ __ mov(eax, edi); ++ __ jmp(&leave_exit_frame); ++} ++ ++void CallApiCallbackStub::Generate(MacroAssembler* masm) { ++ // ----------- S t a t e ------------- ++ // -- edi : callee ++ // -- ebx : call_data ++ // -- ecx : holder ++ // -- edx : api_function_address ++ // -- esi : context ++ // -- ++ // -- esp[0] : return address ++ // -- esp[4] : last argument ++ // -- ... ++ // -- esp[argc * 4] : first argument ++ // -- esp[(argc + 1) * 4] : receiver ++ // ----------------------------------- ++ ++ Register callee = edi; ++ Register call_data = ebx; ++ Register holder = ecx; ++ Register api_function_address = edx; ++ Register context = esi; ++ Register return_address = eax; ++ ++ typedef FunctionCallbackArguments FCA; ++ ++ STATIC_ASSERT(FCA::kContextSaveIndex == 6); ++ STATIC_ASSERT(FCA::kCalleeIndex == 5); ++ STATIC_ASSERT(FCA::kDataIndex == 4); ++ STATIC_ASSERT(FCA::kReturnValueOffset == 3); ++ STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); ++ STATIC_ASSERT(FCA::kIsolateIndex == 1); ++ STATIC_ASSERT(FCA::kHolderIndex == 0); ++ STATIC_ASSERT(FCA::kNewTargetIndex == 7); ++ STATIC_ASSERT(FCA::kArgsLength == 8); ++ ++ __ pop(return_address); ++ ++ // new target ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ ++ // context save. ++ __ push(context); ++ ++ // callee ++ __ push(callee); ++ ++ // call data ++ __ push(call_data); ++ ++ Register scratch = call_data; ++ if (!call_data_undefined()) { ++ // return value ++ __ push(Immediate(masm->isolate()->factory()->undefined_value())); ++ // return value default ++ __ push(Immediate(masm->isolate()->factory()->undefined_value())); ++ } else { ++ // return value ++ __ push(scratch); ++ // return value default ++ __ push(scratch); ++ } ++ // isolate ++ __ push(Immediate(reinterpret_cast(masm->isolate()))); ++ // holder ++ __ push(holder); ++ ++ __ mov(scratch, esp); ++ ++ // push return address ++ __ push(return_address); ++ ++ if (!is_lazy()) { ++ // load context from callee ++ __ mov(context, FieldOperand(callee, JSFunction::kContextOffset)); ++ } ++ ++ // API function gets reference to the v8::Arguments. If CPU profiler ++ // is enabled wrapper function will be called and we need to pass ++ // address of the callback as additional parameter, always allocate ++ // space for it. ++ const int kApiArgc = 1 + 1; ++ ++ // Allocate the v8::Arguments structure in the arguments' space since ++ // it's not controlled by GC. ++ const int kApiStackSpace = 3; ++ ++ PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace); ++ ++ // FunctionCallbackInfo::implicit_args_. ++ __ mov(ApiParameterOperand(2), scratch); ++ __ add(scratch, Immediate((argc() + FCA::kArgsLength - 1) * kPointerSize)); ++ // FunctionCallbackInfo::values_. ++ __ mov(ApiParameterOperand(3), scratch); ++ // FunctionCallbackInfo::length_. ++ __ Move(ApiParameterOperand(4), Immediate(argc())); ++ ++ // v8::InvocationCallback's argument. ++ __ lea(scratch, ApiParameterOperand(2)); ++ __ mov(ApiParameterOperand(0), scratch); ++ ++ ExternalReference thunk_ref = ++ ExternalReference::invoke_function_callback(masm->isolate()); ++ ++ Operand context_restore_operand(ebp, ++ (2 + FCA::kContextSaveIndex) * kPointerSize); ++ // Stores return the first js argument ++ int return_value_offset = 0; ++ if (is_store()) { ++ return_value_offset = 2 + FCA::kArgsLength; ++ } else { ++ return_value_offset = 2 + FCA::kReturnValueOffset; ++ } ++ Operand return_value_operand(ebp, return_value_offset * kPointerSize); ++ int stack_space = 0; ++ Operand length_operand = ApiParameterOperand(4); ++ Operand* stack_space_operand = &length_operand; ++ stack_space = argc() + FCA::kArgsLength + 1; ++ stack_space_operand = nullptr; ++ CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, ++ ApiParameterOperand(1), stack_space, ++ stack_space_operand, return_value_operand, ++ &context_restore_operand); ++} ++ ++ ++void CallApiGetterStub::Generate(MacroAssembler* masm) { ++ // Build v8::PropertyCallbackInfo::args_ array on the stack and push property ++ // name below the exit frame to make GC aware of them. ++ STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0); ++ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1); ++ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2); ++ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3); ++ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4); ++ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5); ++ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6); ++ STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7); ++ ++ Register receiver = ApiGetterDescriptor::ReceiverRegister(); ++ Register holder = ApiGetterDescriptor::HolderRegister(); ++ Register callback = ApiGetterDescriptor::CallbackRegister(); ++ Register scratch = ebx; ++ DCHECK(!AreAliased(receiver, holder, callback, scratch)); ++ ++ __ pop(scratch); // Pop return address to extend the frame. ++ __ push(receiver); ++ __ push(FieldOperand(callback, AccessorInfo::kDataOffset)); ++ __ PushRoot(Heap::kUndefinedValueRootIndex); // ReturnValue ++ // ReturnValue default value ++ __ PushRoot(Heap::kUndefinedValueRootIndex); ++ __ push(Immediate(ExternalReference::isolate_address(isolate()))); ++ __ push(holder); ++ __ push(Immediate(Smi::kZero)); // should_throw_on_error -> false ++ __ push(FieldOperand(callback, AccessorInfo::kNameOffset)); ++ __ push(scratch); // Restore return address. ++ ++ // v8::PropertyCallbackInfo::args_ array and name handle. ++ const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; ++ ++ // Allocate v8::PropertyCallbackInfo object, arguments for callback and ++ // space for optional callback address parameter (in case CPU profiler is ++ // active) in non-GCed stack space. ++ const int kApiArgc = 3 + 1; ++ ++ // Load address of v8::PropertyAccessorInfo::args_ array. ++ __ lea(scratch, Operand(esp, 2 * kPointerSize)); ++ ++ PrepareCallApiFunction(masm, kApiArgc); ++ // Create v8::PropertyCallbackInfo object on the stack and initialize ++ // it's args_ field. ++ Operand info_object = ApiParameterOperand(3); ++ __ mov(info_object, scratch); ++ ++ // Name as handle. ++ __ sub(scratch, Immediate(kPointerSize)); ++ __ mov(ApiParameterOperand(0), scratch); ++ // Arguments pointer. ++ __ lea(scratch, info_object); ++ __ mov(ApiParameterOperand(1), scratch); ++ // Reserve space for optional callback address parameter. ++ Operand thunk_last_arg = ApiParameterOperand(2); ++ ++ ExternalReference thunk_ref = ++ ExternalReference::invoke_accessor_getter_callback(isolate()); ++ ++ __ mov(scratch, FieldOperand(callback, AccessorInfo::kJsGetterOffset)); ++ Register function_address = edx; ++ __ mov(function_address, ++ FieldOperand(scratch, Foreign::kForeignAddressOffset)); ++ // +3 is to skip prolog, return address and name handle. ++ Operand return_value_operand( ++ ebp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize); ++ CallApiFunctionAndReturn(masm, function_address, thunk_ref, thunk_last_arg, ++ kStackUnwindSpace, nullptr, return_value_operand, ++ NULL); ++} ++ ++#undef __ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/code-stubs-x87.h 2017-12-25 17:42:57.221465559 +0100 +@@ -0,0 +1,351 @@ ++// Copyright 2011 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_X87_CODE_STUBS_X87_H_ ++#define V8_X87_CODE_STUBS_X87_H_ ++ ++namespace v8 { ++namespace internal { ++ ++ ++void ArrayNativeCode(MacroAssembler* masm, ++ bool construct_call, ++ Label* call_generic_code); ++ ++ ++class StringHelper : public AllStatic { ++ public: ++ // Compares two flat one byte strings and returns result in eax. ++ static void GenerateCompareFlatOneByteStrings(MacroAssembler* masm, ++ Register left, Register right, ++ Register scratch1, ++ Register scratch2, ++ Register scratch3); ++ ++ // Compares two flat one byte strings for equality and returns result in eax. ++ static void GenerateFlatOneByteStringEquals(MacroAssembler* masm, ++ Register left, Register right, ++ Register scratch1, ++ Register scratch2); ++ ++ private: ++ static void GenerateOneByteCharsCompareLoop( ++ MacroAssembler* masm, Register left, Register right, Register length, ++ Register scratch, Label* chars_not_equal, ++ Label::Distance chars_not_equal_near = Label::kFar); ++ ++ DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); ++}; ++ ++ ++class NameDictionaryLookupStub: public PlatformCodeStub { ++ public: ++ enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; ++ ++ NameDictionaryLookupStub(Isolate* isolate, Register dictionary, ++ Register result, Register index, LookupMode mode) ++ : PlatformCodeStub(isolate) { ++ minor_key_ = DictionaryBits::encode(dictionary.code()) | ++ ResultBits::encode(result.code()) | ++ IndexBits::encode(index.code()) | LookupModeBits::encode(mode); ++ } ++ ++ static void GenerateNegativeLookup(MacroAssembler* masm, ++ Label* miss, ++ Label* done, ++ Register properties, ++ Handle name, ++ Register r0); ++ ++ bool SometimesSetsUpAFrame() override { return false; } ++ ++ private: ++ static const int kInlinedProbes = 4; ++ static const int kTotalProbes = 20; ++ ++ static const int kCapacityOffset = ++ NameDictionary::kHeaderSize + ++ NameDictionary::kCapacityIndex * kPointerSize; ++ ++ static const int kElementsStartOffset = ++ NameDictionary::kHeaderSize + ++ NameDictionary::kElementsStartIndex * kPointerSize; ++ ++ Register dictionary() const { ++ return Register::from_code(DictionaryBits::decode(minor_key_)); ++ } ++ ++ Register result() const { ++ return Register::from_code(ResultBits::decode(minor_key_)); ++ } ++ ++ Register index() const { ++ return Register::from_code(IndexBits::decode(minor_key_)); ++ } ++ ++ LookupMode mode() const { return LookupModeBits::decode(minor_key_); } ++ ++ class DictionaryBits: public BitField {}; ++ class ResultBits: public BitField {}; ++ class IndexBits: public BitField {}; ++ class LookupModeBits: public BitField {}; ++ ++ DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); ++ DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub); ++}; ++ ++ ++class RecordWriteStub: public PlatformCodeStub { ++ public: ++ RecordWriteStub(Isolate* isolate, Register object, Register value, ++ Register address, RememberedSetAction remembered_set_action, ++ SaveFPRegsMode fp_mode) ++ : PlatformCodeStub(isolate), ++ regs_(object, // An input reg. ++ address, // An input reg. ++ value) { // One scratch reg. ++ minor_key_ = ObjectBits::encode(object.code()) | ++ ValueBits::encode(value.code()) | ++ AddressBits::encode(address.code()) | ++ RememberedSetActionBits::encode(remembered_set_action) | ++ SaveFPRegsModeBits::encode(fp_mode); ++ } ++ ++ RecordWriteStub(uint32_t key, Isolate* isolate) ++ : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {} ++ ++ enum Mode { ++ STORE_BUFFER_ONLY, ++ INCREMENTAL, ++ INCREMENTAL_COMPACTION ++ }; ++ ++ bool SometimesSetsUpAFrame() override { return false; } ++ ++ static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8. ++ static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8. ++ ++ static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32. ++ static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32. ++ ++ static Mode GetMode(Code* stub) { ++ byte first_instruction = stub->instruction_start()[0]; ++ byte second_instruction = stub->instruction_start()[2]; ++ ++ if (first_instruction == kTwoByteJumpInstruction) { ++ return INCREMENTAL; ++ } ++ ++ DCHECK(first_instruction == kTwoByteNopInstruction); ++ ++ if (second_instruction == kFiveByteJumpInstruction) { ++ return INCREMENTAL_COMPACTION; ++ } ++ ++ DCHECK(second_instruction == kFiveByteNopInstruction); ++ ++ return STORE_BUFFER_ONLY; ++ } ++ ++ static void Patch(Code* stub, Mode mode) { ++ switch (mode) { ++ case STORE_BUFFER_ONLY: ++ DCHECK(GetMode(stub) == INCREMENTAL || ++ GetMode(stub) == INCREMENTAL_COMPACTION); ++ stub->instruction_start()[0] = kTwoByteNopInstruction; ++ stub->instruction_start()[2] = kFiveByteNopInstruction; ++ break; ++ case INCREMENTAL: ++ DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); ++ stub->instruction_start()[0] = kTwoByteJumpInstruction; ++ break; ++ case INCREMENTAL_COMPACTION: ++ DCHECK(GetMode(stub) == STORE_BUFFER_ONLY); ++ stub->instruction_start()[0] = kTwoByteNopInstruction; ++ stub->instruction_start()[2] = kFiveByteJumpInstruction; ++ break; ++ } ++ DCHECK(GetMode(stub) == mode); ++ Assembler::FlushICache(stub->GetIsolate(), stub->instruction_start(), 7); ++ } ++ ++ DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR(); ++ ++ private: ++ // This is a helper class for freeing up 3 scratch registers, where the third ++ // is always ecx (needed for shift operations). The input is two registers ++ // that must be preserved and one scratch register provided by the caller. ++ class RegisterAllocation { ++ public: ++ RegisterAllocation(Register object, ++ Register address, ++ Register scratch0) ++ : object_orig_(object), ++ address_orig_(address), ++ scratch0_orig_(scratch0), ++ object_(object), ++ address_(address), ++ scratch0_(scratch0) { ++ DCHECK(!AreAliased(scratch0, object, address, no_reg)); ++ scratch1_ = GetRegThatIsNotEcxOr(object_, address_, scratch0_); ++ if (scratch0.is(ecx)) { ++ scratch0_ = GetRegThatIsNotEcxOr(object_, address_, scratch1_); ++ } ++ if (object.is(ecx)) { ++ object_ = GetRegThatIsNotEcxOr(address_, scratch0_, scratch1_); ++ } ++ if (address.is(ecx)) { ++ address_ = GetRegThatIsNotEcxOr(object_, scratch0_, scratch1_); ++ } ++ DCHECK(!AreAliased(scratch0_, object_, address_, ecx)); ++ } ++ ++ void Save(MacroAssembler* masm) { ++ DCHECK(!address_orig_.is(object_)); ++ DCHECK(object_.is(object_orig_) || address_.is(address_orig_)); ++ DCHECK(!AreAliased(object_, address_, scratch1_, scratch0_)); ++ DCHECK(!AreAliased(object_orig_, address_, scratch1_, scratch0_)); ++ DCHECK(!AreAliased(object_, address_orig_, scratch1_, scratch0_)); ++ // We don't have to save scratch0_orig_ because it was given to us as ++ // a scratch register. But if we had to switch to a different reg then ++ // we should save the new scratch0_. ++ if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_); ++ if (!ecx.is(scratch0_orig_) && ++ !ecx.is(object_orig_) && ++ !ecx.is(address_orig_)) { ++ masm->push(ecx); ++ } ++ masm->push(scratch1_); ++ if (!address_.is(address_orig_)) { ++ masm->push(address_); ++ masm->mov(address_, address_orig_); ++ } ++ if (!object_.is(object_orig_)) { ++ masm->push(object_); ++ masm->mov(object_, object_orig_); ++ } ++ } ++ ++ void Restore(MacroAssembler* masm) { ++ // These will have been preserved the entire time, so we just need to move ++ // them back. Only in one case is the orig_ reg different from the plain ++ // one, since only one of them can alias with ecx. ++ if (!object_.is(object_orig_)) { ++ masm->mov(object_orig_, object_); ++ masm->pop(object_); ++ } ++ if (!address_.is(address_orig_)) { ++ masm->mov(address_orig_, address_); ++ masm->pop(address_); ++ } ++ masm->pop(scratch1_); ++ if (!ecx.is(scratch0_orig_) && ++ !ecx.is(object_orig_) && ++ !ecx.is(address_orig_)) { ++ masm->pop(ecx); ++ } ++ if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_); ++ } ++ ++ // If we have to call into C then we need to save and restore all caller- ++ // saved registers that were not already preserved. The caller saved ++ // registers are eax, ecx and edx. The three scratch registers (incl. ecx) ++ // will be restored by other means so we don't bother pushing them here. ++ void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { ++ masm->PushCallerSaved(mode, ecx, scratch0_, scratch1_); ++ } ++ ++ inline void RestoreCallerSaveRegisters(MacroAssembler* masm, ++ SaveFPRegsMode mode) { ++ masm->PopCallerSaved(mode, ecx, scratch0_, scratch1_); ++ } ++ ++ inline Register object() { return object_; } ++ inline Register address() { return address_; } ++ inline Register scratch0() { return scratch0_; } ++ inline Register scratch1() { return scratch1_; } ++ ++ private: ++ Register object_orig_; ++ Register address_orig_; ++ Register scratch0_orig_; ++ Register object_; ++ Register address_; ++ Register scratch0_; ++ Register scratch1_; ++ // Third scratch register is always ecx. ++ ++ Register GetRegThatIsNotEcxOr(Register r1, ++ Register r2, ++ Register r3) { ++ for (int i = 0; i < Register::kNumRegisters; i++) { ++ if (RegisterConfiguration::Crankshaft()->IsAllocatableGeneralCode(i)) { ++ Register candidate = Register::from_code(i); ++ if (candidate.is(ecx)) continue; ++ if (candidate.is(r1)) continue; ++ if (candidate.is(r2)) continue; ++ if (candidate.is(r3)) continue; ++ return candidate; ++ } ++ } ++ UNREACHABLE(); ++ } ++ friend class RecordWriteStub; ++ }; ++ ++ enum OnNoNeedToInformIncrementalMarker { ++ kReturnOnNoNeedToInformIncrementalMarker, ++ kUpdateRememberedSetOnNoNeedToInformIncrementalMarker ++ }; ++ ++ inline Major MajorKey() const final { return RecordWrite; } ++ ++ void Generate(MacroAssembler* masm) override; ++ void GenerateIncremental(MacroAssembler* masm, Mode mode); ++ void CheckNeedsToInformIncrementalMarker( ++ MacroAssembler* masm, ++ OnNoNeedToInformIncrementalMarker on_no_need, ++ Mode mode); ++ void InformIncrementalMarker(MacroAssembler* masm); ++ ++ void Activate(Code* code) override { ++ code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); ++ } ++ ++ Register object() const { ++ return Register::from_code(ObjectBits::decode(minor_key_)); ++ } ++ ++ Register value() const { ++ return Register::from_code(ValueBits::decode(minor_key_)); ++ } ++ ++ Register address() const { ++ return Register::from_code(AddressBits::decode(minor_key_)); ++ } ++ ++ RememberedSetAction remembered_set_action() const { ++ return RememberedSetActionBits::decode(minor_key_); ++ } ++ ++ SaveFPRegsMode save_fp_regs_mode() const { ++ return SaveFPRegsModeBits::decode(minor_key_); ++ } ++ ++ class ObjectBits: public BitField {}; ++ class ValueBits: public BitField {}; ++ class AddressBits: public BitField {}; ++ class RememberedSetActionBits: public BitField {}; ++ class SaveFPRegsModeBits : public BitField {}; ++ ++ RegisterAllocation regs_; ++ ++ DISALLOW_COPY_AND_ASSIGN(RecordWriteStub); ++}; ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_CODE_STUBS_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/cpu-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/cpu-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/cpu-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/cpu-x87.cc 2017-12-25 17:42:57.221465559 +0100 +@@ -0,0 +1,43 @@ ++// Copyright 2011 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++// CPU specific code for ia32 independent of OS goes here. ++ ++#ifdef __GNUC__ ++#include "src/third_party/valgrind/valgrind.h" ++#endif ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/assembler.h" ++#include "src/macro-assembler.h" ++ ++namespace v8 { ++namespace internal { ++ ++void CpuFeatures::FlushICache(void* start, size_t size) { ++ // No need to flush the instruction cache on Intel. On Intel instruction ++ // cache flushing is only necessary when multiple cores running the same ++ // code simultaneously. V8 (and JavaScript) is single threaded and when code ++ // is patched on an intel CPU the core performing the patching will have its ++ // own instruction cache updated automatically. ++ ++ // If flushing of the instruction cache becomes necessary Windows has the ++ // API function FlushInstructionCache. ++ ++ // By default, valgrind only checks the stack for writes that might need to ++ // invalidate already cached translated code. This leads to random ++ // instability when code patches or moves are sometimes unnoticed. One ++ // solution is to run valgrind with --smc-check=all, but this comes at a big ++ // performance cost. We can notify valgrind to invalidate its cache. ++#ifdef VALGRIND_DISCARD_TRANSLATIONS ++ unsigned res = VALGRIND_DISCARD_TRANSLATIONS(start, size); ++ USE(res); ++#endif ++} ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/deoptimizer-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/deoptimizer-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/deoptimizer-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/deoptimizer-x87.cc 2017-12-25 17:42:57.222465544 +0100 +@@ -0,0 +1,412 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/codegen.h" ++#include "src/deoptimizer.h" ++#include "src/full-codegen/full-codegen.h" ++#include "src/register-configuration.h" ++#include "src/safepoint-table.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++const int Deoptimizer::table_entry_size_ = 10; ++ ++ ++int Deoptimizer::patch_size() { ++ return Assembler::kCallInstructionLength; ++} ++ ++ ++void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle code) { ++ Isolate* isolate = code->GetIsolate(); ++ HandleScope scope(isolate); ++ ++ // Compute the size of relocation information needed for the code ++ // patching in Deoptimizer::PatchCodeForDeoptimization below. ++ int min_reloc_size = 0; ++ int prev_pc_offset = 0; ++ DeoptimizationInputData* deopt_data = ++ DeoptimizationInputData::cast(code->deoptimization_data()); ++ for (int i = 0; i < deopt_data->DeoptCount(); i++) { ++ int pc_offset = deopt_data->Pc(i)->value(); ++ if (pc_offset == -1) continue; ++ pc_offset = pc_offset + 1; // We will encode the pc offset after the call. ++ DCHECK_GE(pc_offset, prev_pc_offset); ++ int pc_delta = pc_offset - prev_pc_offset; ++ // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes ++ // if encodable with small pc delta encoding and up to 6 bytes ++ // otherwise. ++ if (pc_delta <= RelocInfo::kMaxSmallPCDelta) { ++ min_reloc_size += 2; ++ } else { ++ min_reloc_size += 6; ++ } ++ prev_pc_offset = pc_offset; ++ } ++ ++ // If the relocation information is not big enough we create a new ++ // relocation info object that is padded with comments to make it ++ // big enough for lazy doptimization. ++ int reloc_length = code->relocation_info()->length(); ++ if (min_reloc_size > reloc_length) { ++ int comment_reloc_size = RelocInfo::kMinRelocCommentSize; ++ // Padding needed. ++ int min_padding = min_reloc_size - reloc_length; ++ // Number of comments needed to take up at least that much space. ++ int additional_comments = ++ (min_padding + comment_reloc_size - 1) / comment_reloc_size; ++ // Actual padding size. ++ int padding = additional_comments * comment_reloc_size; ++ // Allocate new relocation info and copy old relocation to the end ++ // of the new relocation info array because relocation info is ++ // written and read backwards. ++ Factory* factory = isolate->factory(); ++ Handle new_reloc = ++ factory->NewByteArray(reloc_length + padding, TENURED); ++ MemCopy(new_reloc->GetDataStartAddress() + padding, ++ code->relocation_info()->GetDataStartAddress(), reloc_length); ++ // Create a relocation writer to write the comments in the padding ++ // space. Use position 0 for everything to ensure short encoding. ++ RelocInfoWriter reloc_info_writer( ++ new_reloc->GetDataStartAddress() + padding, 0); ++ intptr_t comment_string ++ = reinterpret_cast(RelocInfo::kFillerCommentString); ++ RelocInfo rinfo(isolate, 0, RelocInfo::COMMENT, comment_string, NULL); ++ for (int i = 0; i < additional_comments; ++i) { ++#ifdef DEBUG ++ byte* pos_before = reloc_info_writer.pos(); ++#endif ++ reloc_info_writer.Write(&rinfo); ++ DCHECK(RelocInfo::kMinRelocCommentSize == ++ pos_before - reloc_info_writer.pos()); ++ } ++ // Replace relocation information on the code object. ++ code->set_relocation_info(*new_reloc); ++ } ++} ++ ++ ++void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { ++ Address code_start_address = code->instruction_start(); ++ ++ // Fail hard and early if we enter this code object again. ++ byte* pointer = code->FindCodeAgeSequence(); ++ if (pointer != NULL) { ++ pointer += kNoCodeAgeSequenceLength; ++ } else { ++ pointer = code->instruction_start(); ++ } ++ CodePatcher patcher(isolate, pointer, 1); ++ patcher.masm()->int3(); ++ ++ DeoptimizationInputData* data = ++ DeoptimizationInputData::cast(code->deoptimization_data()); ++ int osr_offset = data->OsrPcOffset()->value(); ++ if (osr_offset > 0) { ++ CodePatcher osr_patcher(isolate, code_start_address + osr_offset, 1); ++ osr_patcher.masm()->int3(); ++ } ++ ++ // We will overwrite the code's relocation info in-place. Relocation info ++ // is written backward. The relocation info is the payload of a byte ++ // array. Later on we will slide this to the start of the byte array and ++ // create a filler object in the remaining space. ++ ByteArray* reloc_info = code->relocation_info(); ++ Address reloc_end_address = reloc_info->address() + reloc_info->Size(); ++ RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address); ++ ++ // Since the call is a relative encoding, write new ++ // reloc info. We do not need any of the existing reloc info because the ++ // existing code will not be used again (we zap it in debug builds). ++ // ++ // Emit call to lazy deoptimization at all lazy deopt points. ++ DeoptimizationInputData* deopt_data = ++ DeoptimizationInputData::cast(code->deoptimization_data()); ++#ifdef DEBUG ++ Address prev_call_address = NULL; ++#endif ++ // For each LLazyBailout instruction insert a call to the corresponding ++ // deoptimization entry. ++ for (int i = 0; i < deopt_data->DeoptCount(); i++) { ++ if (deopt_data->Pc(i)->value() == -1) continue; ++ // Patch lazy deoptimization entry. ++ Address call_address = code_start_address + deopt_data->Pc(i)->value(); ++ CodePatcher patcher(isolate, call_address, patch_size()); ++ Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); ++ patcher.masm()->call(deopt_entry, RelocInfo::NONE32); ++ // We use RUNTIME_ENTRY for deoptimization bailouts. ++ RelocInfo rinfo(isolate, call_address + 1, // 1 after the call opcode. ++ RelocInfo::RUNTIME_ENTRY, ++ reinterpret_cast(deopt_entry), NULL); ++ reloc_info_writer.Write(&rinfo); ++ DCHECK_GE(reloc_info_writer.pos(), ++ reloc_info->address() + ByteArray::kHeaderSize); ++ DCHECK(prev_call_address == NULL || ++ call_address >= prev_call_address + patch_size()); ++ DCHECK(call_address + patch_size() <= code->instruction_end()); ++#ifdef DEBUG ++ prev_call_address = call_address; ++#endif ++ } ++ ++ // Move the relocation info to the beginning of the byte array. ++ const int new_reloc_length = reloc_end_address - reloc_info_writer.pos(); ++ MemMove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_length); ++ ++ // Right trim the relocation info to free up remaining space. ++ const int delta = reloc_info->length() - new_reloc_length; ++ if (delta > 0) { ++ isolate->heap()->RightTrimFixedArray(reloc_info, delta); ++ } ++} ++ ++ ++#define __ masm()-> ++ ++void Deoptimizer::TableEntryGenerator::Generate() { ++ GeneratePrologue(); ++ ++ // Save all general purpose registers before messing with them. ++ const int kNumberOfRegisters = Register::kNumRegisters; ++ ++ const int kDoubleRegsSize = kDoubleSize * X87Register::kMaxNumRegisters; ++ ++ // Reserve space for x87 fp registers. ++ __ sub(esp, Immediate(kDoubleRegsSize)); ++ ++ __ pushad(); ++ ++ ExternalReference c_entry_fp_address(IsolateAddressId::kCEntryFPAddress, ++ isolate()); ++ __ mov(Operand::StaticVariable(c_entry_fp_address), ebp); ++ ++ // GP registers are safe to use now. ++ // Save used x87 fp registers in correct position of previous reserve space. ++ Label loop, done; ++ // Get the layout of x87 stack. ++ __ sub(esp, Immediate(kPointerSize)); ++ __ fistp_s(MemOperand(esp, 0)); ++ __ pop(eax); ++ // Preserve stack layout in edi ++ __ mov(edi, eax); ++ // Get the x87 stack depth, the first 3 bits. ++ __ mov(ecx, eax); ++ __ and_(ecx, 0x7); ++ __ j(zero, &done, Label::kNear); ++ ++ __ bind(&loop); ++ __ shr(eax, 0x3); ++ __ mov(ebx, eax); ++ __ and_(ebx, 0x7); // Extract the st_x index into ebx. ++ // Pop TOS to the correct position. The disp(0x20) is due to pushad. ++ // The st_i should be saved to (esp + ebx * kDoubleSize + 0x20). ++ __ fstp_d(Operand(esp, ebx, times_8, 0x20)); ++ __ dec(ecx); // Decrease stack depth. ++ __ j(not_zero, &loop, Label::kNear); ++ __ bind(&done); ++ ++ const int kSavedRegistersAreaSize = ++ kNumberOfRegisters * kPointerSize + kDoubleRegsSize; ++ ++ // Get the bailout id from the stack. ++ __ mov(ebx, Operand(esp, kSavedRegistersAreaSize)); ++ ++ // Get the address of the location in the code object ++ // and compute the fp-to-sp delta in register edx. ++ __ mov(ecx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize)); ++ __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 2 * kPointerSize)); ++ ++ __ sub(edx, ebp); ++ __ neg(edx); ++ ++ __ push(edi); ++ // Allocate a new deoptimizer object. ++ __ PrepareCallCFunction(6, eax); ++ __ mov(eax, Immediate(0)); ++ Label context_check; ++ __ mov(edi, Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset)); ++ __ JumpIfSmi(edi, &context_check); ++ __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ __ bind(&context_check); ++ __ mov(Operand(esp, 0 * kPointerSize), eax); // Function. ++ __ mov(Operand(esp, 1 * kPointerSize), Immediate(type())); // Bailout type. ++ __ mov(Operand(esp, 2 * kPointerSize), ebx); // Bailout id. ++ __ mov(Operand(esp, 3 * kPointerSize), ecx); // Code address or 0. ++ __ mov(Operand(esp, 4 * kPointerSize), edx); // Fp-to-sp delta. ++ __ mov(Operand(esp, 5 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ { ++ AllowExternalCallThatCantCauseGC scope(masm()); ++ __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); ++ } ++ ++ __ pop(edi); ++ ++ // Preserve deoptimizer object in register eax and get the input ++ // frame descriptor pointer. ++ __ mov(ebx, Operand(eax, Deoptimizer::input_offset())); ++ ++ // Fill in the input registers. ++ for (int i = kNumberOfRegisters - 1; i >= 0; i--) { ++ int offset = (i * kPointerSize) + FrameDescription::registers_offset(); ++ __ pop(Operand(ebx, offset)); ++ } ++ ++ int double_regs_offset = FrameDescription::double_registers_offset(); ++ const RegisterConfiguration* config = RegisterConfiguration::Crankshaft(); ++ // Fill in the double input registers. ++ for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) { ++ int code = config->GetAllocatableDoubleCode(i); ++ int dst_offset = code * kDoubleSize + double_regs_offset; ++ int src_offset = code * kDoubleSize; ++ __ fld_d(Operand(esp, src_offset)); ++ __ fstp_d(Operand(ebx, dst_offset)); ++ } ++ ++ // Clear FPU all exceptions. ++ // TODO(ulan): Find out why the TOP register is not zero here in some cases, ++ // and check that the generated code never deoptimizes with unbalanced stack. ++ __ fnclex(); ++ ++ // Remove the bailout id, return address and the double registers. ++ __ add(esp, Immediate(kDoubleRegsSize + 2 * kPointerSize)); ++ ++ // Compute a pointer to the unwinding limit in register ecx; that is ++ // the first stack slot not part of the input frame. ++ __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset())); ++ __ add(ecx, esp); ++ ++ // Unwind the stack down to - but not including - the unwinding ++ // limit and copy the contents of the activation frame to the input ++ // frame description. ++ __ lea(edx, Operand(ebx, FrameDescription::frame_content_offset())); ++ Label pop_loop_header; ++ __ jmp(&pop_loop_header); ++ Label pop_loop; ++ __ bind(&pop_loop); ++ __ pop(Operand(edx, 0)); ++ __ add(edx, Immediate(sizeof(uint32_t))); ++ __ bind(&pop_loop_header); ++ __ cmp(ecx, esp); ++ __ j(not_equal, &pop_loop); ++ ++ // Compute the output frame in the deoptimizer. ++ __ push(edi); ++ __ push(eax); ++ __ PrepareCallCFunction(1, ebx); ++ __ mov(Operand(esp, 0 * kPointerSize), eax); ++ { ++ AllowExternalCallThatCantCauseGC scope(masm()); ++ __ CallCFunction( ++ ExternalReference::compute_output_frames_function(isolate()), 1); ++ } ++ __ pop(eax); ++ __ pop(edi); ++ __ mov(esp, Operand(eax, Deoptimizer::caller_frame_top_offset())); ++ ++ // Replace the current (input) frame with the output frames. ++ Label outer_push_loop, inner_push_loop, ++ outer_loop_header, inner_loop_header; ++ // Outer loop state: eax = current FrameDescription**, edx = one past the ++ // last FrameDescription**. ++ __ mov(edx, Operand(eax, Deoptimizer::output_count_offset())); ++ __ mov(eax, Operand(eax, Deoptimizer::output_offset())); ++ __ lea(edx, Operand(eax, edx, times_4, 0)); ++ __ jmp(&outer_loop_header); ++ __ bind(&outer_push_loop); ++ // Inner loop state: ebx = current FrameDescription*, ecx = loop index. ++ __ mov(ebx, Operand(eax, 0)); ++ __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset())); ++ __ jmp(&inner_loop_header); ++ __ bind(&inner_push_loop); ++ __ sub(ecx, Immediate(sizeof(uint32_t))); ++ __ push(Operand(ebx, ecx, times_1, FrameDescription::frame_content_offset())); ++ __ bind(&inner_loop_header); ++ __ test(ecx, ecx); ++ __ j(not_zero, &inner_push_loop); ++ __ add(eax, Immediate(kPointerSize)); ++ __ bind(&outer_loop_header); ++ __ cmp(eax, edx); ++ __ j(below, &outer_push_loop); ++ ++ ++ // In case of a failed STUB, we have to restore the x87 stack. ++ // x87 stack layout is in edi. ++ Label loop2, done2; ++ // Get the x87 stack depth, the first 3 bits. ++ __ mov(ecx, edi); ++ __ and_(ecx, 0x7); ++ __ j(zero, &done2, Label::kNear); ++ ++ __ lea(ecx, Operand(ecx, ecx, times_2, 0)); ++ __ bind(&loop2); ++ __ mov(eax, edi); ++ __ shr_cl(eax); ++ __ and_(eax, 0x7); ++ __ fld_d(Operand(ebx, eax, times_8, double_regs_offset)); ++ __ sub(ecx, Immediate(0x3)); ++ __ j(not_zero, &loop2, Label::kNear); ++ __ bind(&done2); ++ ++ // Push state, pc, and continuation from the last output frame. ++ __ push(Operand(ebx, FrameDescription::state_offset())); ++ __ push(Operand(ebx, FrameDescription::pc_offset())); ++ __ push(Operand(ebx, FrameDescription::continuation_offset())); ++ ++ ++ // Push the registers from the last output frame. ++ for (int i = 0; i < kNumberOfRegisters; i++) { ++ int offset = (i * kPointerSize) + FrameDescription::registers_offset(); ++ __ push(Operand(ebx, offset)); ++ } ++ ++ // Restore the registers from the stack. ++ __ popad(); ++ ++ // Return to the continuation point. ++ __ ret(0); ++} ++ ++ ++void Deoptimizer::TableEntryGenerator::GeneratePrologue() { ++ // Create a sequence of deoptimization entries. ++ Label done; ++ for (int i = 0; i < count(); i++) { ++ int start = masm()->pc_offset(); ++ USE(start); ++ __ push_imm32(i); ++ __ jmp(&done); ++ DCHECK(masm()->pc_offset() - start == table_entry_size_); ++ } ++ __ bind(&done); ++} ++ ++ ++void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { ++ SetFrameSlot(offset, value); ++} ++ ++ ++void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { ++ SetFrameSlot(offset, value); ++} ++ ++ ++void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { ++ // No embedded constant pool support. ++ UNREACHABLE(); ++} ++ ++ ++#undef __ ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/disasm-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/disasm-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/disasm-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/disasm-x87.cc 2017-12-25 17:42:57.222465544 +0100 +@@ -0,0 +1,1874 @@ ++// Copyright 2011 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include ++#include ++#include ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/base/compiler-specific.h" ++#include "src/disasm.h" ++ ++namespace disasm { ++ ++enum OperandOrder { ++ UNSET_OP_ORDER = 0, ++ REG_OPER_OP_ORDER, ++ OPER_REG_OP_ORDER ++}; ++ ++ ++//------------------------------------------------------------------ ++// Tables ++//------------------------------------------------------------------ ++struct ByteMnemonic { ++ int b; // -1 terminates, otherwise must be in range (0..255) ++ const char* mnem; ++ OperandOrder op_order_; ++}; ++ ++static const ByteMnemonic two_operands_instr[] = { ++ {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER}, ++ {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER}, ++ {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER}, ++ {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER}, ++ {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER}, ++ {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER}, ++ {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER}, ++ {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER}, ++ {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER}, ++ {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER}, ++ {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER}, ++ {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER}, ++ {-1, "", UNSET_OP_ORDER}}; ++ ++static const ByteMnemonic zero_operands_instr[] = { ++ {0xC3, "ret", UNSET_OP_ORDER}, ++ {0xC9, "leave", UNSET_OP_ORDER}, ++ {0x90, "nop", UNSET_OP_ORDER}, ++ {0xF4, "hlt", UNSET_OP_ORDER}, ++ {0xCC, "int3", UNSET_OP_ORDER}, ++ {0x60, "pushad", UNSET_OP_ORDER}, ++ {0x61, "popad", UNSET_OP_ORDER}, ++ {0x9C, "pushfd", UNSET_OP_ORDER}, ++ {0x9D, "popfd", UNSET_OP_ORDER}, ++ {0x9E, "sahf", UNSET_OP_ORDER}, ++ {0x99, "cdq", UNSET_OP_ORDER}, ++ {0x9B, "fwait", UNSET_OP_ORDER}, ++ {0xFC, "cld", UNSET_OP_ORDER}, ++ {0xAB, "stos", UNSET_OP_ORDER}, ++ {-1, "", UNSET_OP_ORDER} ++}; ++ ++ ++static const ByteMnemonic call_jump_instr[] = { ++ {0xE8, "call", UNSET_OP_ORDER}, ++ {0xE9, "jmp", UNSET_OP_ORDER}, ++ {-1, "", UNSET_OP_ORDER} ++}; ++ ++ ++static const ByteMnemonic short_immediate_instr[] = { ++ {0x05, "add", UNSET_OP_ORDER}, ++ {0x0D, "or", UNSET_OP_ORDER}, ++ {0x15, "adc", UNSET_OP_ORDER}, ++ {0x25, "and", UNSET_OP_ORDER}, ++ {0x2D, "sub", UNSET_OP_ORDER}, ++ {0x35, "xor", UNSET_OP_ORDER}, ++ {0x3D, "cmp", UNSET_OP_ORDER}, ++ {-1, "", UNSET_OP_ORDER} ++}; ++ ++ ++// Generally we don't want to generate these because they are subject to partial ++// register stalls. They are included for completeness and because the cmp ++// variant is used by the RecordWrite stub. Because it does not update the ++// register it is not subject to partial register stalls. ++static ByteMnemonic byte_immediate_instr[] = { ++ {0x0c, "or", UNSET_OP_ORDER}, ++ {0x24, "and", UNSET_OP_ORDER}, ++ {0x34, "xor", UNSET_OP_ORDER}, ++ {0x3c, "cmp", UNSET_OP_ORDER}, ++ {-1, "", UNSET_OP_ORDER} ++}; ++ ++ ++static const char* const jump_conditional_mnem[] = { ++ /*0*/ "jo", "jno", "jc", "jnc", ++ /*4*/ "jz", "jnz", "jna", "ja", ++ /*8*/ "js", "jns", "jpe", "jpo", ++ /*12*/ "jl", "jnl", "jng", "jg" ++}; ++ ++ ++static const char* const set_conditional_mnem[] = { ++ /*0*/ "seto", "setno", "setc", "setnc", ++ /*4*/ "setz", "setnz", "setna", "seta", ++ /*8*/ "sets", "setns", "setpe", "setpo", ++ /*12*/ "setl", "setnl", "setng", "setg" ++}; ++ ++ ++static const char* const conditional_move_mnem[] = { ++ /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc", ++ /*4*/ "cmovz", "cmovnz", "cmovna", "cmova", ++ /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo", ++ /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg" ++}; ++ ++ ++enum InstructionType { ++ NO_INSTR, ++ ZERO_OPERANDS_INSTR, ++ TWO_OPERANDS_INSTR, ++ JUMP_CONDITIONAL_SHORT_INSTR, ++ REGISTER_INSTR, ++ MOVE_REG_INSTR, ++ CALL_JUMP_INSTR, ++ SHORT_IMMEDIATE_INSTR, ++ BYTE_IMMEDIATE_INSTR ++}; ++ ++ ++struct InstructionDesc { ++ const char* mnem; ++ InstructionType type; ++ OperandOrder op_order_; ++}; ++ ++ ++class InstructionTable { ++ public: ++ InstructionTable(); ++ const InstructionDesc& Get(byte x) const { return instructions_[x]; } ++ static InstructionTable* get_instance() { ++ static InstructionTable table; ++ return &table; ++ } ++ ++ private: ++ InstructionDesc instructions_[256]; ++ void Clear(); ++ void Init(); ++ void CopyTable(const ByteMnemonic bm[], InstructionType type); ++ void SetTableRange(InstructionType type, ++ byte start, ++ byte end, ++ const char* mnem); ++ void AddJumpConditionalShort(); ++}; ++ ++ ++InstructionTable::InstructionTable() { ++ Clear(); ++ Init(); ++} ++ ++ ++void InstructionTable::Clear() { ++ for (int i = 0; i < 256; i++) { ++ instructions_[i].mnem = ""; ++ instructions_[i].type = NO_INSTR; ++ instructions_[i].op_order_ = UNSET_OP_ORDER; ++ } ++} ++ ++ ++void InstructionTable::Init() { ++ CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); ++ CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); ++ CopyTable(call_jump_instr, CALL_JUMP_INSTR); ++ CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); ++ CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR); ++ AddJumpConditionalShort(); ++ SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); ++ SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); ++ SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); ++ SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); ++ SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. ++ SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); ++} ++ ++ ++void InstructionTable::CopyTable(const ByteMnemonic bm[], ++ InstructionType type) { ++ for (int i = 0; bm[i].b >= 0; i++) { ++ InstructionDesc* id = &instructions_[bm[i].b]; ++ id->mnem = bm[i].mnem; ++ id->op_order_ = bm[i].op_order_; ++ DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. ++ id->type = type; ++ } ++} ++ ++ ++void InstructionTable::SetTableRange(InstructionType type, ++ byte start, ++ byte end, ++ const char* mnem) { ++ for (byte b = start; b <= end; b++) { ++ InstructionDesc* id = &instructions_[b]; ++ DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. ++ id->mnem = mnem; ++ id->type = type; ++ } ++} ++ ++ ++void InstructionTable::AddJumpConditionalShort() { ++ for (byte b = 0x70; b <= 0x7F; b++) { ++ InstructionDesc* id = &instructions_[b]; ++ DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. ++ id->mnem = jump_conditional_mnem[b & 0x0F]; ++ id->type = JUMP_CONDITIONAL_SHORT_INSTR; ++ } ++} ++ ++ ++// The X87 disassembler implementation. ++class DisassemblerX87 { ++ public: ++ DisassemblerX87(const NameConverter& converter, ++ bool abort_on_unimplemented = true) ++ : converter_(converter), ++ instruction_table_(InstructionTable::get_instance()), ++ tmp_buffer_pos_(0), ++ abort_on_unimplemented_(abort_on_unimplemented) { ++ tmp_buffer_[0] = '\0'; ++ } ++ ++ virtual ~DisassemblerX87() {} ++ ++ // Writes one disassembled instruction into 'buffer' (0-terminated). ++ // Returns the length of the disassembled machine instruction in bytes. ++ int InstructionDecode(v8::internal::Vector buffer, byte* instruction); ++ ++ private: ++ const NameConverter& converter_; ++ InstructionTable* instruction_table_; ++ v8::internal::EmbeddedVector tmp_buffer_; ++ unsigned int tmp_buffer_pos_; ++ bool abort_on_unimplemented_; ++ ++ enum { ++ eax = 0, ++ ecx = 1, ++ edx = 2, ++ ebx = 3, ++ esp = 4, ++ ebp = 5, ++ esi = 6, ++ edi = 7 ++ }; ++ ++ ++ enum ShiftOpcodeExtension { ++ kROL = 0, ++ kROR = 1, ++ kRCL = 2, ++ kRCR = 3, ++ kSHL = 4, ++ KSHR = 5, ++ kSAR = 7 ++ }; ++ ++ ++ const char* NameOfCPURegister(int reg) const { ++ return converter_.NameOfCPURegister(reg); ++ } ++ ++ ++ const char* NameOfByteCPURegister(int reg) const { ++ return converter_.NameOfByteCPURegister(reg); ++ } ++ ++ ++ const char* NameOfXMMRegister(int reg) const { ++ return converter_.NameOfXMMRegister(reg); ++ } ++ ++ ++ const char* NameOfAddress(byte* addr) const { ++ return converter_.NameOfAddress(addr); ++ } ++ ++ ++ // Disassembler helper functions. ++ static void get_modrm(byte data, int* mod, int* regop, int* rm) { ++ *mod = (data >> 6) & 3; ++ *regop = (data & 0x38) >> 3; ++ *rm = data & 7; ++ } ++ ++ ++ static void get_sib(byte data, int* scale, int* index, int* base) { ++ *scale = (data >> 6) & 3; ++ *index = (data >> 3) & 7; ++ *base = data & 7; ++ } ++ ++ typedef const char* (DisassemblerX87::*RegisterNameMapping)(int reg) const; ++ ++ int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); ++ int PrintRightOperand(byte* modrmp); ++ int PrintRightByteOperand(byte* modrmp); ++ int PrintRightXMMOperand(byte* modrmp); ++ int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); ++ int PrintImmediateOp(byte* data); ++ int F7Instruction(byte* data); ++ int D1D3C1Instruction(byte* data); ++ int JumpShort(byte* data); ++ int JumpConditional(byte* data, const char* comment); ++ int JumpConditionalShort(byte* data, const char* comment); ++ int SetCC(byte* data); ++ int CMov(byte* data); ++ int FPUInstruction(byte* data); ++ int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); ++ int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); ++ PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...); ++ ++ void UnimplementedInstruction() { ++ if (abort_on_unimplemented_) { ++ UNIMPLEMENTED(); ++ } else { ++ AppendToBuffer("'Unimplemented Instruction'"); ++ } ++ } ++}; ++ ++ ++void DisassemblerX87::AppendToBuffer(const char* format, ...) { ++ v8::internal::Vector buf = tmp_buffer_ + tmp_buffer_pos_; ++ va_list args; ++ va_start(args, format); ++ int result = v8::internal::VSNPrintF(buf, format, args); ++ va_end(args); ++ tmp_buffer_pos_ += result; ++} ++ ++int DisassemblerX87::PrintRightOperandHelper( ++ byte* modrmp, ++ RegisterNameMapping direct_register_name) { ++ int mod, regop, rm; ++ get_modrm(*modrmp, &mod, ®op, &rm); ++ RegisterNameMapping register_name = (mod == 3) ? direct_register_name : ++ &DisassemblerX87::NameOfCPURegister; ++ switch (mod) { ++ case 0: ++ if (rm == ebp) { ++ int32_t disp = *reinterpret_cast(modrmp+1); ++ AppendToBuffer("[0x%x]", disp); ++ return 5; ++ } else if (rm == esp) { ++ byte sib = *(modrmp + 1); ++ int scale, index, base; ++ get_sib(sib, &scale, &index, &base); ++ if (index == esp && base == esp && scale == 0 /*times_1*/) { ++ AppendToBuffer("[%s]", (this->*register_name)(rm)); ++ return 2; ++ } else if (base == ebp) { ++ int32_t disp = *reinterpret_cast(modrmp + 2); ++ AppendToBuffer("[%s*%d%s0x%x]", ++ (this->*register_name)(index), ++ 1 << scale, ++ disp < 0 ? "-" : "+", ++ disp < 0 ? -disp : disp); ++ return 6; ++ } else if (index != esp && base != ebp) { ++ // [base+index*scale] ++ AppendToBuffer("[%s+%s*%d]", ++ (this->*register_name)(base), ++ (this->*register_name)(index), ++ 1 << scale); ++ return 2; ++ } else { ++ UnimplementedInstruction(); ++ return 1; ++ } ++ } else { ++ AppendToBuffer("[%s]", (this->*register_name)(rm)); ++ return 1; ++ } ++ break; ++ case 1: // fall through ++ case 2: ++ if (rm == esp) { ++ byte sib = *(modrmp + 1); ++ int scale, index, base; ++ get_sib(sib, &scale, &index, &base); ++ int disp = mod == 2 ? *reinterpret_cast(modrmp + 2) ++ : *reinterpret_cast(modrmp + 2); ++ if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { ++ AppendToBuffer("[%s%s0x%x]", ++ (this->*register_name)(rm), ++ disp < 0 ? "-" : "+", ++ disp < 0 ? -disp : disp); ++ } else { ++ AppendToBuffer("[%s+%s*%d%s0x%x]", ++ (this->*register_name)(base), ++ (this->*register_name)(index), ++ 1 << scale, ++ disp < 0 ? "-" : "+", ++ disp < 0 ? -disp : disp); ++ } ++ return mod == 2 ? 6 : 3; ++ } else { ++ // No sib. ++ int disp = mod == 2 ? *reinterpret_cast(modrmp + 1) ++ : *reinterpret_cast(modrmp + 1); ++ AppendToBuffer("[%s%s0x%x]", ++ (this->*register_name)(rm), ++ disp < 0 ? "-" : "+", ++ disp < 0 ? -disp : disp); ++ return mod == 2 ? 5 : 2; ++ } ++ break; ++ case 3: ++ AppendToBuffer("%s", (this->*register_name)(rm)); ++ return 1; ++ default: ++ UnimplementedInstruction(); ++ return 1; ++ } ++ UNREACHABLE(); ++} ++ ++ ++int DisassemblerX87::PrintRightOperand(byte* modrmp) { ++ return PrintRightOperandHelper(modrmp, &DisassemblerX87::NameOfCPURegister); ++} ++ ++ ++int DisassemblerX87::PrintRightByteOperand(byte* modrmp) { ++ return PrintRightOperandHelper(modrmp, ++ &DisassemblerX87::NameOfByteCPURegister); ++} ++ ++ ++int DisassemblerX87::PrintRightXMMOperand(byte* modrmp) { ++ return PrintRightOperandHelper(modrmp, ++ &DisassemblerX87::NameOfXMMRegister); ++} ++ ++ ++// Returns number of bytes used including the current *data. ++// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. ++int DisassemblerX87::PrintOperands(const char* mnem, ++ OperandOrder op_order, ++ byte* data) { ++ byte modrm = *data; ++ int mod, regop, rm; ++ get_modrm(modrm, &mod, ®op, &rm); ++ int advance = 0; ++ switch (op_order) { ++ case REG_OPER_OP_ORDER: { ++ AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); ++ advance = PrintRightOperand(data); ++ break; ++ } ++ case OPER_REG_OP_ORDER: { ++ AppendToBuffer("%s ", mnem); ++ advance = PrintRightOperand(data); ++ AppendToBuffer(",%s", NameOfCPURegister(regop)); ++ break; ++ } ++ default: ++ UNREACHABLE(); ++ break; ++ } ++ return advance; ++} ++ ++ ++// Returns number of bytes used by machine instruction, including *data byte. ++// Writes immediate instructions to 'tmp_buffer_'. ++int DisassemblerX87::PrintImmediateOp(byte* data) { ++ bool sign_extension_bit = (*data & 0x02) != 0; ++ byte modrm = *(data+1); ++ int mod, regop, rm; ++ get_modrm(modrm, &mod, ®op, &rm); ++ const char* mnem = "Imm???"; ++ switch (regop) { ++ case 0: mnem = "add"; break; ++ case 1: mnem = "or"; break; ++ case 2: mnem = "adc"; break; ++ case 4: mnem = "and"; break; ++ case 5: mnem = "sub"; break; ++ case 6: mnem = "xor"; break; ++ case 7: mnem = "cmp"; break; ++ default: UnimplementedInstruction(); ++ } ++ AppendToBuffer("%s ", mnem); ++ int count = PrintRightOperand(data+1); ++ if (sign_extension_bit) { ++ AppendToBuffer(",0x%x", *(data + 1 + count)); ++ return 1 + count + 1 /*int8*/; ++ } else { ++ AppendToBuffer(",0x%x", *reinterpret_cast(data + 1 + count)); ++ return 1 + count + 4 /*int32_t*/; ++ } ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::F7Instruction(byte* data) { ++ DCHECK_EQ(0xF7, *data); ++ byte modrm = *++data; ++ int mod, regop, rm; ++ get_modrm(modrm, &mod, ®op, &rm); ++ const char* mnem = NULL; ++ switch (regop) { ++ case 0: ++ mnem = "test"; ++ break; ++ case 2: ++ mnem = "not"; ++ break; ++ case 3: ++ mnem = "neg"; ++ break; ++ case 4: ++ mnem = "mul"; ++ break; ++ case 5: ++ mnem = "imul"; ++ break; ++ case 6: ++ mnem = "div"; ++ break; ++ case 7: ++ mnem = "idiv"; ++ break; ++ default: ++ UnimplementedInstruction(); ++ } ++ AppendToBuffer("%s ", mnem); ++ int count = PrintRightOperand(data); ++ if (regop == 0) { ++ AppendToBuffer(",0x%x", *reinterpret_cast(data + count)); ++ count += 4; ++ } ++ return 1 + count; ++} ++ ++ ++int DisassemblerX87::D1D3C1Instruction(byte* data) { ++ byte op = *data; ++ DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1); ++ byte modrm = *++data; ++ int mod, regop, rm; ++ get_modrm(modrm, &mod, ®op, &rm); ++ int imm8 = -1; ++ const char* mnem = NULL; ++ switch (regop) { ++ case kROL: ++ mnem = "rol"; ++ break; ++ case kROR: ++ mnem = "ror"; ++ break; ++ case kRCL: ++ mnem = "rcl"; ++ break; ++ case kRCR: ++ mnem = "rcr"; ++ break; ++ case kSHL: ++ mnem = "shl"; ++ break; ++ case KSHR: ++ mnem = "shr"; ++ break; ++ case kSAR: ++ mnem = "sar"; ++ break; ++ default: ++ UnimplementedInstruction(); ++ } ++ AppendToBuffer("%s ", mnem); ++ int count = PrintRightOperand(data); ++ if (op == 0xD1) { ++ imm8 = 1; ++ } else if (op == 0xC1) { ++ imm8 = *(data + 1); ++ count++; ++ } else if (op == 0xD3) { ++ // Shift/rotate by cl. ++ } ++ if (imm8 >= 0) { ++ AppendToBuffer(",%d", imm8); ++ } else { ++ AppendToBuffer(",cl"); ++ } ++ return 1 + count; ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::JumpShort(byte* data) { ++ DCHECK_EQ(0xEB, *data); ++ byte b = *(data+1); ++ byte* dest = data + static_cast(b) + 2; ++ AppendToBuffer("jmp %s", NameOfAddress(dest)); ++ return 2; ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::JumpConditional(byte* data, const char* comment) { ++ DCHECK_EQ(0x0F, *data); ++ byte cond = *(data+1) & 0x0F; ++ byte* dest = data + *reinterpret_cast(data+2) + 6; ++ const char* mnem = jump_conditional_mnem[cond]; ++ AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); ++ if (comment != NULL) { ++ AppendToBuffer(", %s", comment); ++ } ++ return 6; // includes 0x0F ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::JumpConditionalShort(byte* data, const char* comment) { ++ byte cond = *data & 0x0F; ++ byte b = *(data+1); ++ byte* dest = data + static_cast(b) + 2; ++ const char* mnem = jump_conditional_mnem[cond]; ++ AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); ++ if (comment != NULL) { ++ AppendToBuffer(", %s", comment); ++ } ++ return 2; ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::SetCC(byte* data) { ++ DCHECK_EQ(0x0F, *data); ++ byte cond = *(data+1) & 0x0F; ++ const char* mnem = set_conditional_mnem[cond]; ++ AppendToBuffer("%s ", mnem); ++ PrintRightByteOperand(data+2); ++ return 3; // Includes 0x0F. ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::CMov(byte* data) { ++ DCHECK_EQ(0x0F, *data); ++ byte cond = *(data + 1) & 0x0F; ++ const char* mnem = conditional_move_mnem[cond]; ++ int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); ++ return 2 + op_size; // includes 0x0F ++} ++ ++ ++// Returns number of bytes used, including *data. ++int DisassemblerX87::FPUInstruction(byte* data) { ++ byte escape_opcode = *data; ++ DCHECK_EQ(0xD8, escape_opcode & 0xF8); ++ byte modrm_byte = *(data+1); ++ ++ if (modrm_byte >= 0xC0) { ++ return RegisterFPUInstruction(escape_opcode, modrm_byte); ++ } else { ++ return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); ++ } ++} ++ ++int DisassemblerX87::MemoryFPUInstruction(int escape_opcode, ++ int modrm_byte, ++ byte* modrm_start) { ++ const char* mnem = "?"; ++ int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. ++ switch (escape_opcode) { ++ case 0xD9: switch (regop) { ++ case 0: mnem = "fld_s"; break; ++ case 2: mnem = "fst_s"; break; ++ case 3: mnem = "fstp_s"; break; ++ case 5: ++ mnem = "fldcw"; ++ break; ++ case 7: ++ mnem = "fnstcw"; ++ break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDB: switch (regop) { ++ case 0: mnem = "fild_s"; break; ++ case 1: mnem = "fisttp_s"; break; ++ case 2: mnem = "fist_s"; break; ++ case 3: mnem = "fistp_s"; break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDC: ++ switch (regop) { ++ case 0: ++ mnem = "fadd_d"; ++ break; ++ case 1: ++ mnem = "fmul_d"; ++ break; ++ case 4: ++ mnem = "fsub_d"; ++ break; ++ case 5: ++ mnem = "fsubr_d"; ++ break; ++ case 6: ++ mnem = "fdiv_d"; ++ break; ++ case 7: ++ mnem = "fdivr_d"; ++ break; ++ default: ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDD: switch (regop) { ++ case 0: mnem = "fld_d"; break; ++ case 1: mnem = "fisttp_d"; break; ++ case 2: mnem = "fst_d"; break; ++ case 3: mnem = "fstp_d"; break; ++ case 4: ++ mnem = "frstor"; ++ break; ++ case 6: ++ mnem = "fnsave"; ++ break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDF: switch (regop) { ++ case 5: mnem = "fild_d"; break; ++ case 7: mnem = "fistp_d"; break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ default: UnimplementedInstruction(); ++ } ++ AppendToBuffer("%s ", mnem); ++ int count = PrintRightOperand(modrm_start); ++ return count + 1; ++} ++ ++int DisassemblerX87::RegisterFPUInstruction(int escape_opcode, ++ byte modrm_byte) { ++ bool has_register = false; // Is the FPU register encoded in modrm_byte? ++ const char* mnem = "?"; ++ ++ switch (escape_opcode) { ++ case 0xD8: ++ has_register = true; ++ switch (modrm_byte & 0xF8) { ++ case 0xC0: mnem = "fadd_i"; break; ++ case 0xE0: mnem = "fsub_i"; break; ++ case 0xC8: mnem = "fmul_i"; break; ++ case 0xF0: mnem = "fdiv_i"; break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xD9: ++ switch (modrm_byte & 0xF8) { ++ case 0xC0: ++ mnem = "fld"; ++ has_register = true; ++ break; ++ case 0xC8: ++ mnem = "fxch"; ++ has_register = true; ++ break; ++ default: ++ switch (modrm_byte) { ++ case 0xE0: mnem = "fchs"; break; ++ case 0xE1: mnem = "fabs"; break; ++ case 0xE4: mnem = "ftst"; break; ++ case 0xE8: mnem = "fld1"; break; ++ case 0xEB: mnem = "fldpi"; break; ++ case 0xED: mnem = "fldln2"; break; ++ case 0xEE: mnem = "fldz"; break; ++ case 0xF0: mnem = "f2xm1"; break; ++ case 0xF1: mnem = "fyl2x"; break; ++ case 0xF4: mnem = "fxtract"; break; ++ case 0xF5: mnem = "fprem1"; break; ++ case 0xF7: mnem = "fincstp"; break; ++ case 0xF8: mnem = "fprem"; break; ++ case 0xFC: mnem = "frndint"; break; ++ case 0xFD: mnem = "fscale"; break; ++ case 0xFE: mnem = "fsin"; break; ++ case 0xFF: mnem = "fcos"; break; ++ default: UnimplementedInstruction(); ++ } ++ } ++ break; ++ ++ case 0xDA: ++ if (modrm_byte == 0xE9) { ++ mnem = "fucompp"; ++ } else { ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDB: ++ if ((modrm_byte & 0xF8) == 0xE8) { ++ mnem = "fucomi"; ++ has_register = true; ++ } else if (modrm_byte == 0xE2) { ++ mnem = "fclex"; ++ } else if (modrm_byte == 0xE3) { ++ mnem = "fninit"; ++ } else { ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDC: ++ has_register = true; ++ switch (modrm_byte & 0xF8) { ++ case 0xC0: mnem = "fadd"; break; ++ case 0xE8: mnem = "fsub"; break; ++ case 0xC8: mnem = "fmul"; break; ++ case 0xF8: mnem = "fdiv"; break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDD: ++ has_register = true; ++ switch (modrm_byte & 0xF8) { ++ case 0xC0: mnem = "ffree"; break; ++ case 0xD0: mnem = "fst"; break; ++ case 0xD8: mnem = "fstp"; break; ++ default: UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xDE: ++ if (modrm_byte == 0xD9) { ++ mnem = "fcompp"; ++ } else { ++ has_register = true; ++ switch (modrm_byte & 0xF8) { ++ case 0xC0: mnem = "faddp"; break; ++ case 0xE8: mnem = "fsubp"; break; ++ case 0xC8: mnem = "fmulp"; break; ++ case 0xF8: mnem = "fdivp"; break; ++ default: UnimplementedInstruction(); ++ } ++ } ++ break; ++ ++ case 0xDF: ++ if (modrm_byte == 0xE0) { ++ mnem = "fnstsw_ax"; ++ } else if ((modrm_byte & 0xF8) == 0xE8) { ++ mnem = "fucomip"; ++ has_register = true; ++ } ++ break; ++ ++ default: UnimplementedInstruction(); ++ } ++ ++ if (has_register) { ++ AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); ++ } else { ++ AppendToBuffer("%s", mnem); ++ } ++ return 2; ++} ++ ++ ++// Mnemonics for instructions 0xF0 byte. ++// Returns NULL if the instruction is not handled here. ++static const char* F0Mnem(byte f0byte) { ++ switch (f0byte) { ++ case 0x0B: ++ return "ud2"; ++ case 0x18: ++ return "prefetch"; ++ case 0xA2: ++ return "cpuid"; ++ case 0xBE: ++ return "movsx_b"; ++ case 0xBF: ++ return "movsx_w"; ++ case 0xB6: ++ return "movzx_b"; ++ case 0xB7: ++ return "movzx_w"; ++ case 0xAF: ++ return "imul"; ++ case 0xA4: ++ return "shld"; ++ case 0xA5: ++ return "shld"; ++ case 0xAD: ++ return "shrd"; ++ case 0xAC: ++ return "shrd"; // 3-operand version. ++ case 0xAB: ++ return "bts"; ++ case 0xB0: ++ return "cmpxchg_b"; ++ case 0xB1: ++ return "cmpxchg"; ++ case 0xBC: ++ return "bsf"; ++ case 0xBD: ++ return "bsr"; ++ default: return NULL; ++ } ++} ++ ++ ++// Disassembled instruction '*instr' and writes it into 'out_buffer'. ++int DisassemblerX87::InstructionDecode(v8::internal::Vector out_buffer, ++ byte* instr) { ++ tmp_buffer_pos_ = 0; // starting to write as position 0 ++ byte* data = instr; ++ // Check for hints. ++ const char* branch_hint = NULL; ++ // We use these two prefixes only with branch prediction ++ if (*data == 0x3E /*ds*/) { ++ branch_hint = "predicted taken"; ++ data++; ++ } else if (*data == 0x2E /*cs*/) { ++ branch_hint = "predicted not taken"; ++ data++; ++ } else if (*data == 0xF0 /*lock*/) { ++ AppendToBuffer("lock "); ++ data++; ++ } ++ ++ bool processed = true; // Will be set to false if the current instruction ++ // is not in 'instructions' table. ++ const InstructionDesc& idesc = instruction_table_->Get(*data); ++ switch (idesc.type) { ++ case ZERO_OPERANDS_INSTR: ++ AppendToBuffer("%s", idesc.mnem); ++ data++; ++ break; ++ ++ case TWO_OPERANDS_INSTR: ++ data++; ++ data += PrintOperands(idesc.mnem, idesc.op_order_, data); ++ break; ++ ++ case JUMP_CONDITIONAL_SHORT_INSTR: ++ data += JumpConditionalShort(data, branch_hint); ++ break; ++ ++ case REGISTER_INSTR: ++ AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); ++ data++; ++ break; ++ ++ case MOVE_REG_INSTR: { ++ byte* addr = reinterpret_cast(*reinterpret_cast(data+1)); ++ AppendToBuffer("mov %s,%s", ++ NameOfCPURegister(*data & 0x07), ++ NameOfAddress(addr)); ++ data += 5; ++ break; ++ } ++ ++ case CALL_JUMP_INSTR: { ++ byte* addr = data + *reinterpret_cast(data+1) + 5; ++ AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); ++ data += 5; ++ break; ++ } ++ ++ case SHORT_IMMEDIATE_INSTR: { ++ byte* addr = reinterpret_cast(*reinterpret_cast(data+1)); ++ AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); ++ data += 5; ++ break; ++ } ++ ++ case BYTE_IMMEDIATE_INSTR: { ++ AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); ++ data += 2; ++ break; ++ } ++ ++ case NO_INSTR: ++ processed = false; ++ break; ++ ++ default: ++ UNIMPLEMENTED(); // This type is not implemented. ++ } ++ //---------------------------- ++ if (!processed) { ++ switch (*data) { ++ case 0xC2: ++ AppendToBuffer("ret 0x%x", *reinterpret_cast(data+1)); ++ data += 3; ++ break; ++ ++ case 0x6B: { ++ data++; ++ data += PrintOperands("imul", REG_OPER_OP_ORDER, data); ++ AppendToBuffer(",%d", *data); ++ data++; ++ } break; ++ ++ case 0x69: { ++ data++; ++ data += PrintOperands("imul", REG_OPER_OP_ORDER, data); ++ AppendToBuffer(",%d", *reinterpret_cast(data)); ++ data += 4; ++ } ++ break; ++ ++ case 0xF6: ++ { data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (regop == eax) { ++ AppendToBuffer("test_b "); ++ data += PrintRightByteOperand(data); ++ int32_t imm = *data; ++ AppendToBuffer(",0x%x", imm); ++ data++; ++ } else { ++ UnimplementedInstruction(); ++ } ++ } ++ break; ++ ++ case 0x81: // fall through ++ case 0x83: // 0x81 with sign extension bit set ++ data += PrintImmediateOp(data); ++ break; ++ ++ case 0x0F: ++ { byte f0byte = data[1]; ++ const char* f0mnem = F0Mnem(f0byte); ++ if (f0byte == 0x18) { ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ const char* suffix[] = {"nta", "1", "2", "3"}; ++ AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); ++ data += PrintRightOperand(data); ++ } else if (f0byte == 0x1F && data[2] == 0) { ++ AppendToBuffer("nop"); // 3 byte nop. ++ data += 3; ++ } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { ++ AppendToBuffer("nop"); // 4 byte nop. ++ data += 4; ++ } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && ++ data[4] == 0) { ++ AppendToBuffer("nop"); // 5 byte nop. ++ data += 5; ++ } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && ++ data[4] == 0 && data[5] == 0 && data[6] == 0) { ++ AppendToBuffer("nop"); // 7 byte nop. ++ data += 7; ++ } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && ++ data[4] == 0 && data[5] == 0 && data[6] == 0 && ++ data[7] == 0) { ++ AppendToBuffer("nop"); // 8 byte nop. ++ data += 8; ++ } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) { ++ AppendToBuffer("%s", f0mnem); ++ data += 2; ++ } else if (f0byte == 0x28) { ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movaps %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (f0byte >= 0x53 && f0byte <= 0x5F) { ++ const char* const pseudo_op[] = { ++ "rcpps", ++ "andps", ++ "andnps", ++ "orps", ++ "xorps", ++ "addps", ++ "mulps", ++ "cvtps2pd", ++ "cvtdq2ps", ++ "subps", ++ "minps", ++ "divps", ++ "maxps", ++ }; ++ ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("%s %s,", ++ pseudo_op[f0byte - 0x53], ++ NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (f0byte == 0x50) { ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movmskps %s,%s", ++ NameOfCPURegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (f0byte== 0xC6) { ++ // shufps xmm, xmm/m128, imm8 ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("shufps %s,%s,%d", ++ NameOfXMMRegister(rm), ++ NameOfXMMRegister(regop), ++ static_cast(imm8)); ++ data += 2; ++ } else if ((f0byte & 0xF0) == 0x80) { ++ data += JumpConditional(data, branch_hint); ++ } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || ++ f0byte == 0xB7 || f0byte == 0xAF) { ++ data += 2; ++ data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); ++ } else if ((f0byte & 0xF0) == 0x90) { ++ data += SetCC(data); ++ } else if ((f0byte & 0xF0) == 0x40) { ++ data += CMov(data); ++ } else if (f0byte == 0xA4 || f0byte == 0xAC) { ++ // shld, shrd ++ data += 2; ++ AppendToBuffer("%s ", f0mnem); ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ data += 2; ++ AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm), ++ NameOfCPURegister(regop), static_cast(imm8)); ++ } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { ++ // shrd_cl, shld_cl, bts ++ data += 2; ++ AppendToBuffer("%s ", f0mnem); ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightOperand(data); ++ if (f0byte == 0xAB) { ++ AppendToBuffer(",%s", NameOfCPURegister(regop)); ++ } else { ++ AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); ++ } ++ } else if (f0byte == 0xB0) { ++ // cmpxchg_b ++ data += 2; ++ AppendToBuffer("%s ", f0mnem); ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightOperand(data); ++ AppendToBuffer(",%s", NameOfByteCPURegister(regop)); ++ } else if (f0byte == 0xB1) { ++ // cmpxchg ++ data += 2; ++ data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data); ++ } else if (f0byte == 0xBC) { ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); ++ data += PrintRightOperand(data); ++ } else if (f0byte == 0xBD) { ++ data += 2; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); ++ data += PrintRightOperand(data); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } ++ break; ++ ++ case 0x8F: ++ { data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (regop == eax) { ++ AppendToBuffer("pop "); ++ data += PrintRightOperand(data); ++ } ++ } ++ break; ++ ++ case 0xFF: ++ { data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ const char* mnem = NULL; ++ switch (regop) { ++ case esi: mnem = "push"; break; ++ case eax: mnem = "inc"; break; ++ case ecx: mnem = "dec"; break; ++ case edx: mnem = "call"; break; ++ case esp: mnem = "jmp"; break; ++ default: mnem = "???"; ++ } ++ AppendToBuffer("%s ", mnem); ++ data += PrintRightOperand(data); ++ } ++ break; ++ ++ case 0xC7: // imm32, fall through ++ case 0xC6: // imm8 ++ { bool is_byte = *data == 0xC6; ++ data++; ++ if (is_byte) { ++ AppendToBuffer("%s ", "mov_b"); ++ data += PrintRightByteOperand(data); ++ int32_t imm = *data; ++ AppendToBuffer(",0x%x", imm); ++ data++; ++ } else { ++ AppendToBuffer("%s ", "mov"); ++ data += PrintRightOperand(data); ++ int32_t imm = *reinterpret_cast(data); ++ AppendToBuffer(",0x%x", imm); ++ data += 4; ++ } ++ } ++ break; ++ ++ case 0x80: ++ { data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ const char* mnem = NULL; ++ switch (regop) { ++ case 5: mnem = "subb"; break; ++ case 7: mnem = "cmpb"; break; ++ default: UnimplementedInstruction(); ++ } ++ AppendToBuffer("%s ", mnem); ++ data += PrintRightByteOperand(data); ++ int32_t imm = *data; ++ AppendToBuffer(",0x%x", imm); ++ data++; ++ } ++ break; ++ ++ case 0x88: // 8bit, fall through ++ case 0x89: // 32bit ++ { bool is_byte = *data == 0x88; ++ int mod, regop, rm; ++ data++; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (is_byte) { ++ AppendToBuffer("%s ", "mov_b"); ++ data += PrintRightByteOperand(data); ++ AppendToBuffer(",%s", NameOfByteCPURegister(regop)); ++ } else { ++ AppendToBuffer("%s ", "mov"); ++ data += PrintRightOperand(data); ++ AppendToBuffer(",%s", NameOfCPURegister(regop)); ++ } ++ } ++ break; ++ ++ case 0x66: // prefix ++ while (*data == 0x66) data++; ++ if (*data == 0xf && data[1] == 0x1f) { ++ AppendToBuffer("nop"); // 0x66 prefix ++ } else if (*data == 0x39) { ++ data++; ++ data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data); ++ } else if (*data == 0x3B) { ++ data++; ++ data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data); ++ } else if (*data == 0x81) { ++ data++; ++ AppendToBuffer("cmpw "); ++ data += PrintRightOperand(data); ++ int imm = *reinterpret_cast(data); ++ AppendToBuffer(",0x%x", imm); ++ data += 2; ++ } else if (*data == 0x87) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop)); ++ data += PrintRightOperand(data); ++ } else if (*data == 0x89) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("mov_w "); ++ data += PrintRightOperand(data); ++ AppendToBuffer(",%s", NameOfCPURegister(regop)); ++ } else if (*data == 0x8B) { ++ data++; ++ data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); ++ } else if (*data == 0x90) { ++ AppendToBuffer("nop"); // 0x66 prefix ++ } else if (*data == 0xC7) { ++ data++; ++ AppendToBuffer("%s ", "mov_w"); ++ data += PrintRightOperand(data); ++ int imm = *reinterpret_cast(data); ++ AppendToBuffer(",0x%x", imm); ++ data += 2; ++ } else if (*data == 0xF7) { ++ data++; ++ AppendToBuffer("%s ", "test_w"); ++ data += PrintRightOperand(data); ++ int imm = *reinterpret_cast(data); ++ AppendToBuffer(",0x%x", imm); ++ data += 2; ++ } else if (*data == 0x0F) { ++ data++; ++ if (*data == 0x38) { ++ data++; ++ if (*data == 0x17) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("ptest %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x2A) { ++ // movntdqa ++ UnimplementedInstruction(); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } else if (*data == 0x3A) { ++ data++; ++ if (*data == 0x0B) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("roundsd %s,%s,%d", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm), ++ static_cast(imm8)); ++ data += 2; ++ } else if (*data == 0x16) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, &rm, ®op); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("pextrd %s,%s,%d", ++ NameOfCPURegister(regop), ++ NameOfXMMRegister(rm), ++ static_cast(imm8)); ++ data += 2; ++ } else if (*data == 0x17) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("extractps %s,%s,%d", ++ NameOfCPURegister(rm), ++ NameOfXMMRegister(regop), ++ static_cast(imm8)); ++ data += 2; ++ } else if (*data == 0x22) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("pinsrd %s,%s,%d", ++ NameOfXMMRegister(regop), ++ NameOfCPURegister(rm), ++ static_cast(imm8)); ++ data += 2; ++ } else { ++ UnimplementedInstruction(); ++ } ++ } else if (*data == 0x2E || *data == 0x2F) { ++ const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (mod == 0x3) { ++ AppendToBuffer("%s %s,%s", mnem, ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else { ++ AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); ++ data += PrintRightOperand(data); ++ } ++ } else if (*data == 0x50) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movmskpd %s,%s", ++ NameOfCPURegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x54) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("andpd %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x56) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("orpd %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x57) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("xorpd %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x6E) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); ++ data += PrintRightOperand(data); ++ } else if (*data == 0x6F) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (*data == 0x70) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ AppendToBuffer("pshufd %s,%s,%d", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm), ++ static_cast(imm8)); ++ data += 2; ++ } else if (*data == 0x76) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("pcmpeqd %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x90) { ++ data++; ++ AppendToBuffer("nop"); // 2 byte nop. ++ } else if (*data == 0xF3) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("psllq %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x73) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ int8_t imm8 = static_cast(data[1]); ++ DCHECK(regop == esi || regop == edx); ++ AppendToBuffer("%s %s,%d", ++ (regop == esi) ? "psllq" : "psrlq", ++ NameOfXMMRegister(rm), ++ static_cast(imm8)); ++ data += 2; ++ } else if (*data == 0xD3) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("psrlq %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0x7F) { ++ AppendToBuffer("movdqa "); ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightXMMOperand(data); ++ AppendToBuffer(",%s", NameOfXMMRegister(regop)); ++ } else if (*data == 0x7E) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movd "); ++ data += PrintRightOperand(data); ++ AppendToBuffer(",%s", NameOfXMMRegister(regop)); ++ } else if (*data == 0xDB) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("pand %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0xE7) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (mod == 3) { ++ // movntdq ++ UnimplementedInstruction(); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } else if (*data == 0xEF) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("pxor %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0xEB) { ++ data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("por %s,%s", ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data++; ++ } else if (*data == 0xB1) { ++ data++; ++ data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } else { ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xFE: ++ { data++; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (regop == ecx) { ++ AppendToBuffer("dec_b "); ++ data += PrintRightOperand(data); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } ++ break; ++ ++ case 0x68: ++ AppendToBuffer("push 0x%x", *reinterpret_cast(data+1)); ++ data += 5; ++ break; ++ ++ case 0x6A: ++ AppendToBuffer("push 0x%x", *reinterpret_cast(data + 1)); ++ data += 2; ++ break; ++ ++ case 0xA8: ++ AppendToBuffer("test al,0x%x", *reinterpret_cast(data+1)); ++ data += 2; ++ break; ++ ++ case 0xA9: ++ AppendToBuffer("test eax,0x%x", *reinterpret_cast(data+1)); ++ data += 5; ++ break; ++ ++ case 0xD1: // fall through ++ case 0xD3: // fall through ++ case 0xC1: ++ data += D1D3C1Instruction(data); ++ break; ++ ++ case 0xD8: // fall through ++ case 0xD9: // fall through ++ case 0xDA: // fall through ++ case 0xDB: // fall through ++ case 0xDC: // fall through ++ case 0xDD: // fall through ++ case 0xDE: // fall through ++ case 0xDF: ++ data += FPUInstruction(data); ++ break; ++ ++ case 0xEB: ++ data += JumpShort(data); ++ break; ++ ++ case 0xF2: ++ if (*(data+1) == 0x0F) { ++ byte b2 = *(data+2); ++ if (b2 == 0x11) { ++ AppendToBuffer("movsd "); ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightXMMOperand(data); ++ AppendToBuffer(",%s", NameOfXMMRegister(regop)); ++ } else if (b2 == 0x10) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0x5A) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else { ++ const char* mnem = "?"; ++ switch (b2) { ++ case 0x2A: mnem = "cvtsi2sd"; break; ++ case 0x2C: mnem = "cvttsd2si"; break; ++ case 0x2D: mnem = "cvtsd2si"; break; ++ case 0x51: mnem = "sqrtsd"; break; ++ case 0x58: mnem = "addsd"; break; ++ case 0x59: mnem = "mulsd"; break; ++ case 0x5C: mnem = "subsd"; break; ++ case 0x5E: mnem = "divsd"; break; ++ } ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ if (b2 == 0x2A) { ++ AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); ++ data += PrintRightOperand(data); ++ } else if (b2 == 0x2C || b2 == 0x2D) { ++ AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0xC2) { ++ // Intel manual 2A, Table 3-18. ++ const char* const pseudo_op[] = { ++ "cmpeqsd", ++ "cmpltsd", ++ "cmplesd", ++ "cmpunordsd", ++ "cmpneqsd", ++ "cmpnltsd", ++ "cmpnlesd", ++ "cmpordsd" ++ }; ++ AppendToBuffer("%s %s,%s", ++ pseudo_op[data[1]], ++ NameOfXMMRegister(regop), ++ NameOfXMMRegister(rm)); ++ data += 2; ++ } else { ++ AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } ++ } ++ } else { ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xF3: ++ if (*(data+1) == 0x0F) { ++ byte b2 = *(data+2); ++ if (b2 == 0x11) { ++ AppendToBuffer("movss "); ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightXMMOperand(data); ++ AppendToBuffer(",%s", NameOfXMMRegister(regop)); ++ } else if (b2 == 0x10) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0x2C) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0x5A) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0x6F) { ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); ++ data += PrintRightXMMOperand(data); ++ } else if (b2 == 0x7F) { ++ AppendToBuffer("movdqu "); ++ data += 3; ++ int mod, regop, rm; ++ get_modrm(*data, &mod, ®op, &rm); ++ data += PrintRightXMMOperand(data); ++ AppendToBuffer(",%s", NameOfXMMRegister(regop)); ++ } else { ++ UnimplementedInstruction(); ++ } ++ } else if (*(data+1) == 0xA5) { ++ data += 2; ++ AppendToBuffer("rep_movs"); ++ } else if (*(data+1) == 0xAB) { ++ data += 2; ++ AppendToBuffer("rep_stos"); ++ } else { ++ UnimplementedInstruction(); ++ } ++ break; ++ ++ case 0xF7: ++ data += F7Instruction(data); ++ break; ++ ++ default: ++ UnimplementedInstruction(); ++ } ++ } ++ ++ if (tmp_buffer_pos_ < sizeof tmp_buffer_) { ++ tmp_buffer_[tmp_buffer_pos_] = '\0'; ++ } ++ ++ int instr_len = data - instr; ++ if (instr_len == 0) { ++ printf("%02x", *data); ++ } ++ DCHECK(instr_len > 0); // Ensure progress. ++ ++ int outp = 0; ++ // Instruction bytes. ++ for (byte* bp = instr; bp < data; bp++) { ++ outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp); ++ } ++ for (int i = 6 - instr_len; i >= 0; i--) { ++ outp += v8::internal::SNPrintF(out_buffer + outp, " "); ++ } ++ ++ outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.start()); ++ return instr_len; ++} // NOLINT (function is too long) ++ ++ ++//------------------------------------------------------------------------------ ++ ++ ++static const char* const cpu_regs[8] = { ++ "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" ++}; ++ ++ ++static const char* const byte_cpu_regs[8] = { ++ "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" ++}; ++ ++ ++static const char* const xmm_regs[8] = { ++ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ++}; ++ ++ ++const char* NameConverter::NameOfAddress(byte* addr) const { ++ v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast(addr)); ++ return tmp_buffer_.start(); ++} ++ ++ ++const char* NameConverter::NameOfConstant(byte* addr) const { ++ return NameOfAddress(addr); ++} ++ ++ ++const char* NameConverter::NameOfCPURegister(int reg) const { ++ if (0 <= reg && reg < 8) return cpu_regs[reg]; ++ return "noreg"; ++} ++ ++ ++const char* NameConverter::NameOfByteCPURegister(int reg) const { ++ if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; ++ return "noreg"; ++} ++ ++ ++const char* NameConverter::NameOfXMMRegister(int reg) const { ++ if (0 <= reg && reg < 8) return xmm_regs[reg]; ++ return "noxmmreg"; ++} ++ ++ ++const char* NameConverter::NameInCode(byte* addr) const { ++ // X87 does not embed debug strings at the moment. ++ UNREACHABLE(); ++} ++ ++ ++//------------------------------------------------------------------------------ ++ ++Disassembler::Disassembler(const NameConverter& converter) ++ : converter_(converter) {} ++ ++ ++Disassembler::~Disassembler() {} ++ ++ ++int Disassembler::InstructionDecode(v8::internal::Vector buffer, ++ byte* instruction) { ++ DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/); ++ return d.InstructionDecode(buffer, instruction); ++} ++ ++ ++// The IA-32 assembler does not currently use constant pools. ++int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } ++ ++ ++/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { ++ NameConverter converter; ++ Disassembler d(converter); ++ for (byte* pc = begin; pc < end;) { ++ v8::internal::EmbeddedVector buffer; ++ buffer[0] = '\0'; ++ byte* prev_pc = pc; ++ pc += d.InstructionDecode(buffer, pc); ++ fprintf(f, "%p", static_cast(prev_pc)); ++ fprintf(f, " "); ++ ++ for (byte* bp = prev_pc; bp < pc; bp++) { ++ fprintf(f, "%02x", *bp); ++ } ++ for (int i = 6 - (pc - prev_pc); i >= 0; i--) { ++ fprintf(f, " "); ++ } ++ fprintf(f, " %s\n", buffer.start()); ++ } ++} ++ ++ ++} // namespace disasm ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/frames-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/frames-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/frames-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/frames-x87.cc 2017-12-25 17:42:57.222465544 +0100 +@@ -0,0 +1,27 @@ ++// Copyright 2006-2008 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/assembler.h" ++#include "src/frames.h" ++#include "src/x87/assembler-x87-inl.h" ++#include "src/x87/assembler-x87.h" ++#include "src/x87/frames-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++ ++Register JavaScriptFrame::fp_register() { return ebp; } ++Register JavaScriptFrame::context_register() { return esi; } ++Register JavaScriptFrame::constant_pool_pointer_register() { ++ UNREACHABLE(); ++} ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/frames-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/frames-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/frames-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/frames-x87.h 2017-12-25 17:42:57.222465544 +0100 +@@ -0,0 +1,78 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_X87_FRAMES_X87_H_ ++#define V8_X87_FRAMES_X87_H_ ++ ++namespace v8 { ++namespace internal { ++ ++ ++// Register lists ++// Note that the bit values must match those used in actual instruction encoding ++const int kNumRegs = 8; ++ ++ ++// Caller-saved registers ++const RegList kJSCallerSaved = ++ 1 << 0 | // eax ++ 1 << 1 | // ecx ++ 1 << 2 | // edx ++ 1 << 3 | // ebx - used as a caller-saved register in JavaScript code ++ 1 << 7; // edi - callee function ++ ++const int kNumJSCallerSaved = 5; ++ ++ ++// Number of registers for which space is reserved in safepoints. ++const int kNumSafepointRegisters = 8; ++ ++// ---------------------------------------------------- ++ ++ ++class EntryFrameConstants : public AllStatic { ++ public: ++ static const int kCallerFPOffset = -6 * kPointerSize; ++ ++ static const int kNewTargetArgOffset = +2 * kPointerSize; ++ static const int kFunctionArgOffset = +3 * kPointerSize; ++ static const int kReceiverArgOffset = +4 * kPointerSize; ++ static const int kArgcOffset = +5 * kPointerSize; ++ static const int kArgvOffset = +6 * kPointerSize; ++}; ++ ++class ExitFrameConstants : public TypedFrameConstants { ++ public: ++ static const int kSPOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); ++ static const int kCodeOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); ++ DEFINE_TYPED_FRAME_SIZES(2); ++ ++ static const int kCallerFPOffset = 0 * kPointerSize; ++ static const int kCallerPCOffset = +1 * kPointerSize; ++ ++ // FP-relative displacement of the caller's SP. It points just ++ // below the saved PC. ++ static const int kCallerSPDisplacement = +2 * kPointerSize; ++ ++ static const int kConstantPoolOffset = 0; // Not used ++}; ++ ++ ++class JavaScriptFrameConstants : public AllStatic { ++ public: ++ // FP-relative. ++ static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset; ++ static const int kLastParameterOffset = +2 * kPointerSize; ++ static const int kFunctionOffset = StandardFrameConstants::kFunctionOffset; ++ ++ // Caller SP-relative. ++ static const int kParam0Offset = -2 * kPointerSize; ++ static const int kReceiverOffset = -1 * kPointerSize; ++}; ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_FRAMES_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/interface-descriptors-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/interface-descriptors-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/interface-descriptors-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/interface-descriptors-x87.cc 2017-12-25 17:42:57.223465529 +0100 +@@ -0,0 +1,386 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/interface-descriptors.h" ++ ++namespace v8 { ++namespace internal { ++ ++const Register CallInterfaceDescriptor::ContextRegister() { return esi; } ++ ++void CallInterfaceDescriptor::DefaultInitializePlatformSpecific( ++ CallInterfaceDescriptorData* data, int register_parameter_count) { ++ const Register default_stub_registers[] = {eax, ebx, ecx, edx, edi}; ++ CHECK_LE(static_cast(register_parameter_count), ++ arraysize(default_stub_registers)); ++ data->InitializePlatformSpecific(register_parameter_count, ++ default_stub_registers); ++} ++ ++const Register FastNewFunctionContextDescriptor::FunctionRegister() { ++ return edi; ++} ++const Register FastNewFunctionContextDescriptor::SlotsRegister() { return eax; } ++ ++const Register LoadDescriptor::ReceiverRegister() { return edx; } ++const Register LoadDescriptor::NameRegister() { return ecx; } ++const Register LoadDescriptor::SlotRegister() { return eax; } ++ ++const Register LoadWithVectorDescriptor::VectorRegister() { return ebx; } ++ ++const Register LoadICProtoArrayDescriptor::HandlerRegister() { return edi; } ++ ++const Register StoreDescriptor::ReceiverRegister() { return edx; } ++const Register StoreDescriptor::NameRegister() { return ecx; } ++const Register StoreDescriptor::ValueRegister() { return eax; } ++const Register StoreDescriptor::SlotRegister() { return edi; } ++ ++const Register StoreWithVectorDescriptor::VectorRegister() { return ebx; } ++ ++const Register StoreTransitionDescriptor::SlotRegister() { return no_reg; } ++const Register StoreTransitionDescriptor::VectorRegister() { return ebx; } ++const Register StoreTransitionDescriptor::MapRegister() { return edi; } ++ ++const Register StringCompareDescriptor::LeftRegister() { return edx; } ++const Register StringCompareDescriptor::RightRegister() { return eax; } ++ ++const Register StringConcatDescriptor::ArgumentsCountRegister() { return eax; } ++ ++const Register ApiGetterDescriptor::HolderRegister() { return ecx; } ++const Register ApiGetterDescriptor::CallbackRegister() { return eax; } ++ ++const Register MathPowTaggedDescriptor::exponent() { return eax; } ++ ++const Register MathPowIntegerDescriptor::exponent() { ++ return MathPowTaggedDescriptor::exponent(); ++} ++ ++ ++const Register GrowArrayElementsDescriptor::ObjectRegister() { return eax; } ++const Register GrowArrayElementsDescriptor::KeyRegister() { return ebx; } ++ ++ ++void FastNewClosureDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // SharedFunctionInfo, vector, slot index. ++ Register registers[] = {ebx, ecx, edx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void FastNewRestParameterDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void FastNewSloppyArgumentsDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void FastNewStrictArgumentsDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++// static ++const Register TypeConversionDescriptor::ArgumentRegister() { return eax; } ++ ++void TypeofDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void FastCloneRegExpDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi, eax, ecx, edx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void FastCloneShallowArrayDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {eax, ebx, ecx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void FastCloneShallowObjectDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {eax, ebx, ecx, edx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void CreateAllocationSiteDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {ebx, edx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void CreateWeakCellDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {ebx, edx, edi}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void CallFunctionDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void CallICTrampolineDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi, eax, edx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void CallICDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edi, eax, edx, ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void CallConstructDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // eax : number of arguments ++ // ebx : feedback vector ++ // ecx : new target (for IsSuperConstructorCall) ++ // edx : slot in feedback vector (Smi, for RecordCallTarget) ++ // edi : constructor function ++ // TODO(turbofan): So far we don't gather type feedback and hence skip the ++ // slot parameter, but ArrayConstructStub needs the vector to be undefined. ++ Register registers[] = {eax, edi, ecx, ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void CallTrampolineDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // eax : number of arguments ++ // edi : the target to call ++ Register registers[] = {edi, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void CallForwardVarargsDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // ecx : start index (to support rest parameters) ++ // edi : the target to call ++ Register registers[] = {edi, ecx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void ConstructStubDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // eax : number of arguments ++ // edx : the new target ++ // edi : the target to call ++ // ebx : allocation site or undefined ++ Register registers[] = {edi, edx, eax, ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void ConstructTrampolineDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // eax : number of arguments ++ // edx : the new target ++ // edi : the target to call ++ Register registers[] = {edi, edx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++ ++void TransitionElementsKindDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {eax, ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void AllocateHeapNumberDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // register state ++ data->InitializePlatformSpecific(0, nullptr, nullptr); ++} ++ ++void ArrayNoArgumentConstructorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // register state ++ // eax -- number of arguments ++ // edi -- function ++ // ebx -- allocation site with elements kind ++ Register registers[] = {edi, ebx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void ArraySingleArgumentConstructorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // register state ++ // eax -- number of arguments ++ // edi -- function ++ // ebx -- allocation site with elements kind ++ Register registers[] = {edi, ebx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void ArrayNArgumentsConstructorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // register state ++ // eax -- number of arguments ++ // edi -- function ++ // ebx -- allocation site with elements kind ++ Register registers[] = {edi, ebx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void VarArgFunctionDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // stack param count needs (arg count) ++ Register registers[] = {eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void CompareDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void BinaryOpDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++ ++void BinaryOpWithAllocationSiteDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {ecx, edx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void BinaryOpWithVectorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ // register state ++ // edx -- lhs ++ // eax -- rhs ++ // edi -- slot id ++ // ebx -- vector ++ Register registers[] = {edx, eax, edi, ebx}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void CountOpDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void StringAddDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = {edx, eax}; ++ data->InitializePlatformSpecific(arraysize(registers), registers, NULL); ++} ++ ++void ArgumentAdaptorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ edi, // JSFunction ++ edx, // the new target ++ eax, // actual number of arguments ++ ebx, // expected number of arguments ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void ApiCallbackDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ edi, // callee ++ ebx, // call_data ++ ecx, // holder ++ edx, // api_function_address ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void InterpreterDispatchDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ kInterpreterAccumulatorRegister, kInterpreterBytecodeOffsetRegister, ++ kInterpreterBytecodeArrayRegister, kInterpreterDispatchTableRegister}; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ eax, // argument count (not including receiver) ++ ebx, // address of first argument ++ edi // the target callable to be call ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ eax, // argument count (not including receiver) ++ edx, // new target ++ edi, // constructor ++ ebx, // allocation site feedback ++ ecx, // address of first argument ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void InterpreterPushArgsThenConstructArrayDescriptor:: ++ InitializePlatformSpecific(CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ eax, // argument count (not including receiver) ++ edx, // target to the call. It is checked to be Array function. ++ ebx, // allocation site feedback ++ ecx, // address of first argument ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void InterpreterCEntryDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ eax, // argument count (argc) ++ ecx, // address of first argument (argv) ++ ebx // the runtime function to call ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++void ResumeGeneratorDescriptor::InitializePlatformSpecific( ++ CallInterfaceDescriptorData* data) { ++ Register registers[] = { ++ eax, // the value to pass to the generator ++ ebx, // the JSGeneratorObject to resume ++ edx // the resume mode (tagged) ++ }; ++ data->InitializePlatformSpecific(arraysize(registers), registers); ++} ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.cc 2017-12-25 17:42:57.223465529 +0100 +@@ -0,0 +1,2546 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#if V8_TARGET_ARCH_X87 ++ ++#include "src/base/bits.h" ++#include "src/base/division-by-constant.h" ++#include "src/bootstrapper.h" ++#include "src/codegen.h" ++#include "src/debug/debug.h" ++#include "src/runtime/runtime.h" ++#include "src/x87/frames-x87.h" ++#include "src/x87/macro-assembler-x87.h" ++ ++namespace v8 { ++namespace internal { ++ ++// ------------------------------------------------------------------------- ++// MacroAssembler implementation. ++ ++MacroAssembler::MacroAssembler(Isolate* isolate, void* buffer, int size, ++ CodeObjectRequired create_code_object) ++ : Assembler(arg_isolate, buffer, size), ++ generating_stub_(false), ++ has_frame_(false), ++ isolate_(isolate) { ++ if (create_code_object == CodeObjectRequired::kYes) { ++ code_object_ = ++ Handle::New(isolate_->heap()->undefined_value(), isolate_); ++ } ++} ++ ++ ++void MacroAssembler::Load(Register dst, const Operand& src, Representation r) { ++ DCHECK(!r.IsDouble()); ++ if (r.IsInteger8()) { ++ movsx_b(dst, src); ++ } else if (r.IsUInteger8()) { ++ movzx_b(dst, src); ++ } else if (r.IsInteger16()) { ++ movsx_w(dst, src); ++ } else if (r.IsUInteger16()) { ++ movzx_w(dst, src); ++ } else { ++ mov(dst, src); ++ } ++} ++ ++ ++void MacroAssembler::Store(Register src, const Operand& dst, Representation r) { ++ DCHECK(!r.IsDouble()); ++ if (r.IsInteger8() || r.IsUInteger8()) { ++ mov_b(dst, src); ++ } else if (r.IsInteger16() || r.IsUInteger16()) { ++ mov_w(dst, src); ++ } else { ++ if (r.IsHeapObject()) { ++ AssertNotSmi(src); ++ } else if (r.IsSmi()) { ++ AssertSmi(src); ++ } ++ mov(dst, src); ++ } ++} ++ ++ ++void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) { ++ if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) { ++ mov(destination, isolate()->heap()->root_handle(index)); ++ return; ++ } ++ ExternalReference roots_array_start = ++ ExternalReference::roots_array_start(isolate()); ++ mov(destination, Immediate(index)); ++ mov(destination, Operand::StaticArray(destination, ++ times_pointer_size, ++ roots_array_start)); ++} ++ ++ ++void MacroAssembler::StoreRoot(Register source, ++ Register scratch, ++ Heap::RootListIndex index) { ++ DCHECK(Heap::RootCanBeWrittenAfterInitialization(index)); ++ ExternalReference roots_array_start = ++ ExternalReference::roots_array_start(isolate()); ++ mov(scratch, Immediate(index)); ++ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), ++ source); ++} ++ ++ ++void MacroAssembler::CompareRoot(Register with, ++ Register scratch, ++ Heap::RootListIndex index) { ++ ExternalReference roots_array_start = ++ ExternalReference::roots_array_start(isolate()); ++ mov(scratch, Immediate(index)); ++ cmp(with, Operand::StaticArray(scratch, ++ times_pointer_size, ++ roots_array_start)); ++} ++ ++ ++void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { ++ DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); ++ cmp(with, isolate()->heap()->root_handle(index)); ++} ++ ++ ++void MacroAssembler::CompareRoot(const Operand& with, ++ Heap::RootListIndex index) { ++ DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); ++ cmp(with, isolate()->heap()->root_handle(index)); ++} ++ ++ ++void MacroAssembler::PushRoot(Heap::RootListIndex index) { ++ DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index)); ++ Push(isolate()->heap()->root_handle(index)); ++} ++ ++#define REG(Name) \ ++ { Register::kCode_##Name } ++ ++static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)}; ++ ++#undef REG ++ ++static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); ++ ++void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, ++ Register exclusion1, Register exclusion2, ++ Register exclusion3) { ++ // We don't allow a GC during a store buffer overflow so there is no need to ++ // store the registers in any particular way, but we do have to store and ++ // restore them. ++ for (int i = 0; i < kNumberOfSavedRegs; i++) { ++ Register reg = saved_regs[i]; ++ if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { ++ push(reg); ++ } ++ } ++ if (fp_mode == kSaveFPRegs) { ++ // Save FPU state in m108byte. ++ sub(esp, Immediate(108)); ++ fnsave(Operand(esp, 0)); ++ } ++} ++ ++void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, ++ Register exclusion2, Register exclusion3) { ++ if (fp_mode == kSaveFPRegs) { ++ // Restore FPU state in m108byte. ++ frstor(Operand(esp, 0)); ++ add(esp, Immediate(108)); ++ } ++ ++ for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { ++ Register reg = saved_regs[i]; ++ if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) { ++ pop(reg); ++ } ++ } ++} ++ ++void MacroAssembler::InNewSpace(Register object, Register scratch, Condition cc, ++ Label* condition_met, ++ Label::Distance distance) { ++ CheckPageFlag(object, scratch, MemoryChunk::kIsInNewSpaceMask, cc, ++ condition_met, distance); ++} ++ ++ ++void MacroAssembler::RememberedSetHelper( ++ Register object, // Only used for debug checks. ++ Register addr, Register scratch, SaveFPRegsMode save_fp, ++ MacroAssembler::RememberedSetFinalAction and_then) { ++ Label done; ++ if (emit_debug_code()) { ++ Label ok; ++ JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear); ++ int3(); ++ bind(&ok); ++ } ++ // Load store buffer top. ++ ExternalReference store_buffer = ++ ExternalReference::store_buffer_top(isolate()); ++ mov(scratch, Operand::StaticVariable(store_buffer)); ++ // Store pointer to buffer. ++ mov(Operand(scratch, 0), addr); ++ // Increment buffer top. ++ add(scratch, Immediate(kPointerSize)); ++ // Write back new top of buffer. ++ mov(Operand::StaticVariable(store_buffer), scratch); ++ // Call stub on end of buffer. ++ // Check for end of buffer. ++ test(scratch, Immediate(StoreBuffer::kStoreBufferMask)); ++ if (and_then == kReturnAtEnd) { ++ Label buffer_overflowed; ++ j(equal, &buffer_overflowed, Label::kNear); ++ ret(0); ++ bind(&buffer_overflowed); ++ } else { ++ DCHECK(and_then == kFallThroughAtEnd); ++ j(not_equal, &done, Label::kNear); ++ } ++ StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp); ++ CallStub(&store_buffer_overflow); ++ if (and_then == kReturnAtEnd) { ++ ret(0); ++ } else { ++ DCHECK(and_then == kFallThroughAtEnd); ++ bind(&done); ++ } ++} ++ ++ ++void MacroAssembler::ClampTOSToUint8(Register result_reg) { ++ Label done, conv_failure; ++ sub(esp, Immediate(kPointerSize)); ++ fnclex(); ++ fist_s(Operand(esp, 0)); ++ pop(result_reg); ++ X87CheckIA(); ++ j(equal, &conv_failure, Label::kNear); ++ test(result_reg, Immediate(0xFFFFFF00)); ++ j(zero, &done, Label::kNear); ++ setcc(sign, result_reg); ++ sub(result_reg, Immediate(1)); ++ and_(result_reg, Immediate(255)); ++ jmp(&done, Label::kNear); ++ bind(&conv_failure); ++ fnclex(); ++ fldz(); ++ fld(1); ++ FCmp(); ++ setcc(below, result_reg); // 1 if negative, 0 if positive. ++ dec_b(result_reg); // 0 if negative, 255 if positive. ++ bind(&done); ++} ++ ++ ++void MacroAssembler::ClampUint8(Register reg) { ++ Label done; ++ test(reg, Immediate(0xFFFFFF00)); ++ j(zero, &done, Label::kNear); ++ setcc(negative, reg); // 1 if negative, 0 if positive. ++ dec_b(reg); // 0 if negative, 255 if positive. ++ bind(&done); ++} ++ ++ ++void MacroAssembler::SlowTruncateToI(Register result_reg, ++ Register input_reg, ++ int offset) { ++ DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true); ++ call(stub.GetCode(), RelocInfo::CODE_TARGET); ++} ++ ++ ++void MacroAssembler::TruncateX87TOSToI(Register result_reg) { ++ sub(esp, Immediate(kDoubleSize)); ++ fst_d(MemOperand(esp, 0)); ++ SlowTruncateToI(result_reg, esp, 0); ++ add(esp, Immediate(kDoubleSize)); ++} ++ ++ ++void MacroAssembler::X87TOSToI(Register result_reg, ++ MinusZeroMode minus_zero_mode, ++ Label* lost_precision, Label* is_nan, ++ Label* minus_zero, Label::Distance dst) { ++ Label done; ++ sub(esp, Immediate(kPointerSize)); ++ fld(0); ++ fist_s(MemOperand(esp, 0)); ++ fild_s(MemOperand(esp, 0)); ++ pop(result_reg); ++ FCmp(); ++ j(not_equal, lost_precision, dst); ++ j(parity_even, is_nan, dst); ++ if (minus_zero_mode == FAIL_ON_MINUS_ZERO) { ++ test(result_reg, Operand(result_reg)); ++ j(not_zero, &done, Label::kNear); ++ // To check for minus zero, we load the value again as float, and check ++ // if that is still 0. ++ sub(esp, Immediate(kPointerSize)); ++ fst_s(MemOperand(esp, 0)); ++ pop(result_reg); ++ test(result_reg, Operand(result_reg)); ++ j(not_zero, minus_zero, dst); ++ } ++ bind(&done); ++} ++ ++ ++void MacroAssembler::TruncateHeapNumberToI(Register result_reg, ++ Register input_reg) { ++ Label done, slow_case; ++ ++ SlowTruncateToI(result_reg, input_reg); ++ bind(&done); ++} ++ ++ ++void MacroAssembler::LoadUint32NoSSE2(const Operand& src) { ++ Label done; ++ push(src); ++ fild_s(Operand(esp, 0)); ++ cmp(src, Immediate(0)); ++ j(not_sign, &done, Label::kNear); ++ ExternalReference uint32_bias = ++ ExternalReference::address_of_uint32_bias(); ++ fld_d(Operand::StaticVariable(uint32_bias)); ++ faddp(1); ++ bind(&done); ++ add(esp, Immediate(kPointerSize)); ++} ++ ++ ++void MacroAssembler::RecordWriteField( ++ Register object, int offset, Register value, Register dst, ++ SaveFPRegsMode save_fp, RememberedSetAction remembered_set_action, ++ SmiCheck smi_check, PointersToHereCheck pointers_to_here_check_for_value) { ++ // First, check if a write barrier is even needed. The tests below ++ // catch stores of Smis. ++ Label done; ++ ++ // Skip barrier if writing a smi. ++ if (smi_check == INLINE_SMI_CHECK) { ++ JumpIfSmi(value, &done, Label::kNear); ++ } ++ ++ // Although the object register is tagged, the offset is relative to the start ++ // of the object, so so offset must be a multiple of kPointerSize. ++ DCHECK(IsAligned(offset, kPointerSize)); ++ ++ lea(dst, FieldOperand(object, offset)); ++ if (emit_debug_code()) { ++ Label ok; ++ test_b(dst, Immediate(kPointerSize - 1)); ++ j(zero, &ok, Label::kNear); ++ int3(); ++ bind(&ok); ++ } ++ ++ RecordWrite(object, dst, value, save_fp, remembered_set_action, ++ OMIT_SMI_CHECK, pointers_to_here_check_for_value); ++ ++ bind(&done); ++ ++ // Clobber clobbered input registers when running with the debug-code flag ++ // turned on to provoke errors. ++ if (emit_debug_code()) { ++ mov(value, Immediate(bit_cast(kZapValue))); ++ mov(dst, Immediate(bit_cast(kZapValue))); ++ } ++} ++ ++ ++void MacroAssembler::RecordWriteForMap(Register object, Handle map, ++ Register scratch1, Register scratch2, ++ SaveFPRegsMode save_fp) { ++ Label done; ++ ++ Register address = scratch1; ++ Register value = scratch2; ++ if (emit_debug_code()) { ++ Label ok; ++ lea(address, FieldOperand(object, HeapObject::kMapOffset)); ++ test_b(address, Immediate(kPointerSize - 1)); ++ j(zero, &ok, Label::kNear); ++ int3(); ++ bind(&ok); ++ } ++ ++ DCHECK(!object.is(value)); ++ DCHECK(!object.is(address)); ++ DCHECK(!value.is(address)); ++ AssertNotSmi(object); ++ ++ if (!FLAG_incremental_marking) { ++ return; ++ } ++ ++ // Compute the address. ++ lea(address, FieldOperand(object, HeapObject::kMapOffset)); ++ ++ // A single check of the map's pages interesting flag suffices, since it is ++ // only set during incremental collection, and then it's also guaranteed that ++ // the from object's page's interesting flag is also set. This optimization ++ // relies on the fact that maps can never be in new space. ++ DCHECK(!isolate()->heap()->InNewSpace(*map)); ++ CheckPageFlagForMap(map, ++ MemoryChunk::kPointersToHereAreInterestingMask, ++ zero, ++ &done, ++ Label::kNear); ++ ++ RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET, ++ save_fp); ++ CallStub(&stub); ++ ++ bind(&done); ++ ++ // Count number of write barriers in generated code. ++ isolate()->counters()->write_barriers_static()->Increment(); ++ IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); ++ ++ // Clobber clobbered input registers when running with the debug-code flag ++ // turned on to provoke errors. ++ if (emit_debug_code()) { ++ mov(value, Immediate(bit_cast(kZapValue))); ++ mov(scratch1, Immediate(bit_cast(kZapValue))); ++ mov(scratch2, Immediate(bit_cast(kZapValue))); ++ } ++} ++ ++ ++void MacroAssembler::RecordWrite( ++ Register object, Register address, Register value, SaveFPRegsMode fp_mode, ++ RememberedSetAction remembered_set_action, SmiCheck smi_check, ++ PointersToHereCheck pointers_to_here_check_for_value) { ++ DCHECK(!object.is(value)); ++ DCHECK(!object.is(address)); ++ DCHECK(!value.is(address)); ++ AssertNotSmi(object); ++ ++ if (remembered_set_action == OMIT_REMEMBERED_SET && ++ !FLAG_incremental_marking) { ++ return; ++ } ++ ++ if (emit_debug_code()) { ++ Label ok; ++ cmp(value, Operand(address, 0)); ++ j(equal, &ok, Label::kNear); ++ int3(); ++ bind(&ok); ++ } ++ ++ // First, check if a write barrier is even needed. The tests below ++ // catch stores of Smis and stores into young gen. ++ Label done; ++ ++ if (smi_check == INLINE_SMI_CHECK) { ++ // Skip barrier if writing a smi. ++ JumpIfSmi(value, &done, Label::kNear); ++ } ++ ++ if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { ++ CheckPageFlag(value, ++ value, // Used as scratch. ++ MemoryChunk::kPointersToHereAreInterestingMask, ++ zero, ++ &done, ++ Label::kNear); ++ } ++ CheckPageFlag(object, ++ value, // Used as scratch. ++ MemoryChunk::kPointersFromHereAreInterestingMask, ++ zero, ++ &done, ++ Label::kNear); ++ ++ RecordWriteStub stub(isolate(), object, value, address, remembered_set_action, ++ fp_mode); ++ CallStub(&stub); ++ ++ bind(&done); ++ ++ // Count number of write barriers in generated code. ++ isolate()->counters()->write_barriers_static()->Increment(); ++ IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1); ++ ++ // Clobber clobbered registers when running with the debug-code flag ++ // turned on to provoke errors. ++ if (emit_debug_code()) { ++ mov(address, Immediate(bit_cast(kZapValue))); ++ mov(value, Immediate(bit_cast(kZapValue))); ++ } ++} ++ ++void MacroAssembler::RecordWriteCodeEntryField(Register js_function, ++ Register code_entry, ++ Register scratch) { ++ const int offset = JSFunction::kCodeEntryOffset; ++ ++ // Since a code entry (value) is always in old space, we don't need to update ++ // remembered set. If incremental marking is off, there is nothing for us to ++ // do. ++ if (!FLAG_incremental_marking) return; ++ ++ DCHECK(!js_function.is(code_entry)); ++ DCHECK(!js_function.is(scratch)); ++ DCHECK(!code_entry.is(scratch)); ++ AssertNotSmi(js_function); ++ ++ if (emit_debug_code()) { ++ Label ok; ++ lea(scratch, FieldOperand(js_function, offset)); ++ cmp(code_entry, Operand(scratch, 0)); ++ j(equal, &ok, Label::kNear); ++ int3(); ++ bind(&ok); ++ } ++ ++ // First, check if a write barrier is even needed. The tests below ++ // catch stores of Smis and stores into young gen. ++ Label done; ++ ++ CheckPageFlag(code_entry, scratch, ++ MemoryChunk::kPointersToHereAreInterestingMask, zero, &done, ++ Label::kNear); ++ CheckPageFlag(js_function, scratch, ++ MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done, ++ Label::kNear); ++ ++ // Save input registers. ++ push(js_function); ++ push(code_entry); ++ ++ const Register dst = scratch; ++ lea(dst, FieldOperand(js_function, offset)); ++ ++ // Save caller-saved registers. ++ PushCallerSaved(kDontSaveFPRegs, js_function, code_entry); ++ ++ int argument_count = 3; ++ PrepareCallCFunction(argument_count, code_entry); ++ mov(Operand(esp, 0 * kPointerSize), js_function); ++ mov(Operand(esp, 1 * kPointerSize), dst); // Slot. ++ mov(Operand(esp, 2 * kPointerSize), ++ Immediate(ExternalReference::isolate_address(isolate()))); ++ ++ { ++ AllowExternalCallThatCantCauseGC scope(this); ++ CallCFunction( ++ ExternalReference::incremental_marking_record_write_code_entry_function( ++ isolate()), ++ argument_count); ++ } ++ ++ // Restore caller-saved registers. ++ PopCallerSaved(kDontSaveFPRegs, js_function, code_entry); ++ ++ // Restore input registers. ++ pop(code_entry); ++ pop(js_function); ++ ++ bind(&done); ++} ++ ++void MacroAssembler::DebugBreak() { ++ Move(eax, Immediate(0)); ++ mov(ebx, Immediate(ExternalReference(Runtime::kHandleDebuggerStatement, ++ isolate()))); ++ CEntryStub ces(isolate(), 1); ++ call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); ++} ++ ++void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) { ++ if (shift >= 32) { ++ mov(high, low); ++ shl(high, shift - 32); ++ xor_(low, low); ++ } else { ++ shld(high, low, shift); ++ shl(low, shift); ++ } ++} ++ ++void MacroAssembler::ShlPair_cl(Register high, Register low) { ++ shld_cl(high, low); ++ shl_cl(low); ++ Label done; ++ test(ecx, Immediate(0x20)); ++ j(equal, &done, Label::kNear); ++ mov(high, low); ++ xor_(low, low); ++ bind(&done); ++} ++ ++void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) { ++ if (shift >= 32) { ++ mov(low, high); ++ shr(low, shift - 32); ++ xor_(high, high); ++ } else { ++ shrd(high, low, shift); ++ shr(high, shift); ++ } ++} ++ ++void MacroAssembler::ShrPair_cl(Register high, Register low) { ++ shrd_cl(low, high); ++ shr_cl(high); ++ Label done; ++ test(ecx, Immediate(0x20)); ++ j(equal, &done, Label::kNear); ++ mov(low, high); ++ xor_(high, high); ++ bind(&done); ++} ++ ++void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) { ++ if (shift >= 32) { ++ mov(low, high); ++ sar(low, shift - 32); ++ sar(high, 31); ++ } else { ++ shrd(high, low, shift); ++ sar(high, shift); ++ } ++} ++ ++void MacroAssembler::SarPair_cl(Register high, Register low) { ++ shrd_cl(low, high); ++ sar_cl(high); ++ Label done; ++ test(ecx, Immediate(0x20)); ++ j(equal, &done, Label::kNear); ++ mov(low, high); ++ sar(high, 31); ++ bind(&done); ++} ++ ++bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { ++ static const int kMaxImmediateBits = 17; ++ if (!RelocInfo::IsNone(x.rmode_)) return false; ++ return !is_intn(x.x_, kMaxImmediateBits); ++} ++ ++ ++void MacroAssembler::SafeMove(Register dst, const Immediate& x) { ++ if (IsUnsafeImmediate(x) && jit_cookie() != 0) { ++ Move(dst, Immediate(x.x_ ^ jit_cookie())); ++ xor_(dst, jit_cookie()); ++ } else { ++ Move(dst, x); ++ } ++} ++ ++ ++void MacroAssembler::SafePush(const Immediate& x) { ++ if (IsUnsafeImmediate(x) && jit_cookie() != 0) { ++ push(Immediate(x.x_ ^ jit_cookie())); ++ xor_(Operand(esp, 0), Immediate(jit_cookie())); ++ } else { ++ push(x); ++ } ++} ++ ++ ++void MacroAssembler::CmpObjectType(Register heap_object, ++ InstanceType type, ++ Register map) { ++ mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); ++ CmpInstanceType(map, type); ++} ++ ++ ++void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { ++ cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type)); ++} ++ ++void MacroAssembler::CompareMap(Register obj, Handle map) { ++ cmp(FieldOperand(obj, HeapObject::kMapOffset), map); ++} ++ ++ ++void MacroAssembler::CheckMap(Register obj, ++ Handle map, ++ Label* fail, ++ SmiCheckType smi_check_type) { ++ if (smi_check_type == DO_SMI_CHECK) { ++ JumpIfSmi(obj, fail); ++ } ++ ++ CompareMap(obj, map); ++ j(not_equal, fail); ++} ++ ++ ++Condition MacroAssembler::IsObjectStringType(Register heap_object, ++ Register map, ++ Register instance_type) { ++ mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); ++ movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); ++ STATIC_ASSERT(kNotStringTag != 0); ++ test(instance_type, Immediate(kIsNotStringMask)); ++ return zero; ++} ++ ++ ++void MacroAssembler::FCmp() { ++ fucompp(); ++ push(eax); ++ fnstsw_ax(); ++ sahf(); ++ pop(eax); ++} ++ ++ ++void MacroAssembler::FXamMinusZero() { ++ fxam(); ++ push(eax); ++ fnstsw_ax(); ++ and_(eax, Immediate(0x4700)); ++ // For minus zero, C3 == 1 && C1 == 1. ++ cmp(eax, Immediate(0x4200)); ++ pop(eax); ++ fstp(0); ++} ++ ++ ++void MacroAssembler::FXamSign() { ++ fxam(); ++ push(eax); ++ fnstsw_ax(); ++ // For negative value (including -0.0), C1 == 1. ++ and_(eax, Immediate(0x0200)); ++ pop(eax); ++ fstp(0); ++} ++ ++ ++void MacroAssembler::X87CheckIA() { ++ push(eax); ++ fnstsw_ax(); ++ // For #IA, IE == 1 && SF == 0. ++ and_(eax, Immediate(0x0041)); ++ cmp(eax, Immediate(0x0001)); ++ pop(eax); ++} ++ ++ ++// rc=00B, round to nearest. ++// rc=01B, round down. ++// rc=10B, round up. ++// rc=11B, round toward zero. ++void MacroAssembler::X87SetRC(int rc) { ++ sub(esp, Immediate(kPointerSize)); ++ fnstcw(MemOperand(esp, 0)); ++ and_(MemOperand(esp, 0), Immediate(0xF3FF)); ++ or_(MemOperand(esp, 0), Immediate(rc)); ++ fldcw(MemOperand(esp, 0)); ++ add(esp, Immediate(kPointerSize)); ++} ++ ++ ++void MacroAssembler::X87SetFPUCW(int cw) { ++ RecordComment("-- X87SetFPUCW start --"); ++ push(Immediate(cw)); ++ fldcw(MemOperand(esp, 0)); ++ add(esp, Immediate(kPointerSize)); ++ RecordComment("-- X87SetFPUCW end--"); ++} ++ ++ ++void MacroAssembler::AssertSmi(Register object) { ++ if (emit_debug_code()) { ++ test(object, Immediate(kSmiTagMask)); ++ Check(equal, kOperandIsNotASmi); ++ } ++} ++ ++ ++void MacroAssembler::AssertFunction(Register object) { ++ if (emit_debug_code()) { ++ test(object, Immediate(kSmiTagMask)); ++ Check(not_equal, kOperandIsASmiAndNotAFunction); ++ Push(object); ++ CmpObjectType(object, JS_FUNCTION_TYPE, object); ++ Pop(object); ++ Check(equal, kOperandIsNotAFunction); ++ } ++} ++ ++ ++void MacroAssembler::AssertBoundFunction(Register object) { ++ if (emit_debug_code()) { ++ test(object, Immediate(kSmiTagMask)); ++ Check(not_equal, kOperandIsASmiAndNotABoundFunction); ++ Push(object); ++ CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); ++ Pop(object); ++ Check(equal, kOperandIsNotABoundFunction); ++ } ++} ++ ++void MacroAssembler::AssertGeneratorObject(Register object) { ++ if (emit_debug_code()) { ++ test(object, Immediate(kSmiTagMask)); ++ Check(not_equal, kOperandIsASmiAndNotAGeneratorObject); ++ Push(object); ++ CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object); ++ Pop(object); ++ Check(equal, kOperandIsNotAGeneratorObject); ++ } ++} ++ ++void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) { ++ if (emit_debug_code()) { ++ Label done_checking; ++ AssertNotSmi(object); ++ cmp(object, isolate()->factory()->undefined_value()); ++ j(equal, &done_checking); ++ cmp(FieldOperand(object, 0), ++ Immediate(isolate()->factory()->allocation_site_map())); ++ Assert(equal, kExpectedUndefinedOrCell); ++ bind(&done_checking); ++ } ++} ++ ++ ++void MacroAssembler::AssertNotSmi(Register object) { ++ if (emit_debug_code()) { ++ test(object, Immediate(kSmiTagMask)); ++ Check(not_equal, kOperandIsASmi); ++ } ++} ++ ++void MacroAssembler::StubPrologue(StackFrame::Type type) { ++ push(ebp); // Caller's frame pointer. ++ mov(ebp, esp); ++ push(Immediate(Smi::FromInt(type))); ++} ++ ++ ++void MacroAssembler::Prologue(bool code_pre_aging) { ++ PredictableCodeSizeScope predictible_code_size_scope(this, ++ kNoCodeAgeSequenceLength); ++ if (code_pre_aging) { ++ // Pre-age the code. ++ call(isolate()->builtins()->MarkCodeAsExecutedOnce(), ++ RelocInfo::CODE_AGE_SEQUENCE); ++ Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength); ++ } else { ++ push(ebp); // Caller's frame pointer. ++ mov(ebp, esp); ++ push(esi); // Callee's context. ++ push(edi); // Callee's JS function. ++ } ++} ++ ++void MacroAssembler::EmitLoadFeedbackVector(Register vector) { ++ mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); ++ mov(vector, FieldOperand(vector, JSFunction::kFeedbackVectorOffset)); ++ mov(vector, FieldOperand(vector, Cell::kValueOffset)); ++} ++ ++ ++void MacroAssembler::EnterFrame(StackFrame::Type type, ++ bool load_constant_pool_pointer_reg) { ++ // Out-of-line constant pool not implemented on x87. ++ UNREACHABLE(); ++} ++ ++ ++void MacroAssembler::EnterFrame(StackFrame::Type type) { ++ push(ebp); ++ mov(ebp, esp); ++ push(Immediate(Smi::FromInt(type))); ++ if (type == StackFrame::INTERNAL) { ++ push(Immediate(CodeObject())); ++ } ++ if (emit_debug_code()) { ++ cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value())); ++ Check(not_equal, kCodeObjectNotProperlyPatched); ++ } ++} ++ ++ ++void MacroAssembler::LeaveFrame(StackFrame::Type type) { ++ if (emit_debug_code()) { ++ cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), ++ Immediate(Smi::FromInt(type))); ++ Check(equal, kStackFrameTypesMustMatch); ++ } ++ leave(); ++} ++ ++void MacroAssembler::EnterBuiltinFrame(Register context, Register target, ++ Register argc) { ++ Push(ebp); ++ Move(ebp, esp); ++ Push(context); ++ Push(target); ++ Push(argc); ++} ++ ++void MacroAssembler::LeaveBuiltinFrame(Register context, Register target, ++ Register argc) { ++ Pop(argc); ++ Pop(target); ++ Pop(context); ++ leave(); ++} ++ ++void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) { ++ DCHECK(frame_type == StackFrame::EXIT || ++ frame_type == StackFrame::BUILTIN_EXIT); ++ ++ // Set up the frame structure on the stack. ++ DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); ++ DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); ++ DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); ++ push(ebp); ++ mov(ebp, esp); ++ ++ // Reserve room for entry stack pointer and push the code object. ++ push(Immediate(Smi::FromInt(frame_type))); ++ DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset); ++ push(Immediate(0)); // Saved entry sp, patched before call. ++ DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset); ++ push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot. ++ ++ // Save the frame pointer and the context in top. ++ ExternalReference c_entry_fp_address(IsolateAddressId::kCEntryFPAddress, ++ isolate()); ++ ExternalReference context_address(IsolateAddressId::kContextAddress, ++ isolate()); ++ ExternalReference c_function_address(IsolateAddressId::kCFunctionAddress, ++ isolate()); ++ mov(Operand::StaticVariable(c_entry_fp_address), ebp); ++ mov(Operand::StaticVariable(context_address), esi); ++ mov(Operand::StaticVariable(c_function_address), ebx); ++} ++ ++ ++void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { ++ // Optionally save FPU state. ++ if (save_doubles) { ++ // Store FPU state to m108byte. ++ int space = 108 + argc * kPointerSize; ++ sub(esp, Immediate(space)); ++ const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; ++ fnsave(MemOperand(ebp, offset - 108)); ++ } else { ++ sub(esp, Immediate(argc * kPointerSize)); ++ } ++ ++ // Get the required frame alignment for the OS. ++ const int kFrameAlignment = base::OS::ActivationFrameAlignment(); ++ if (kFrameAlignment > 0) { ++ DCHECK(base::bits::IsPowerOfTwo(kFrameAlignment)); ++ and_(esp, -kFrameAlignment); ++ } ++ ++ // Patch the saved entry sp. ++ mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); ++} ++ ++void MacroAssembler::EnterExitFrame(int argc, bool save_doubles, ++ StackFrame::Type frame_type) { ++ EnterExitFramePrologue(frame_type); ++ ++ // Set up argc and argv in callee-saved registers. ++ int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; ++ mov(edi, eax); ++ lea(esi, Operand(ebp, eax, times_4, offset)); ++ ++ // Reserve space for argc, argv and isolate. ++ EnterExitFrameEpilogue(argc, save_doubles); ++} ++ ++ ++void MacroAssembler::EnterApiExitFrame(int argc) { ++ EnterExitFramePrologue(StackFrame::EXIT); ++ EnterExitFrameEpilogue(argc, false); ++} ++ ++ ++void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) { ++ // Optionally restore FPU state. ++ if (save_doubles) { ++ const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; ++ frstor(MemOperand(ebp, offset - 108)); ++ } ++ ++ if (pop_arguments) { ++ // Get the return address from the stack and restore the frame pointer. ++ mov(ecx, Operand(ebp, 1 * kPointerSize)); ++ mov(ebp, Operand(ebp, 0 * kPointerSize)); ++ ++ // Pop the arguments and the receiver from the caller stack. ++ lea(esp, Operand(esi, 1 * kPointerSize)); ++ ++ // Push the return address to get ready to return. ++ push(ecx); ++ } else { ++ // Otherwise just leave the exit frame. ++ leave(); ++ } ++ ++ LeaveExitFrameEpilogue(true); ++} ++ ++ ++void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) { ++ // Restore current context from top and clear it in debug mode. ++ ExternalReference context_address(IsolateAddressId::kContextAddress, ++ isolate()); ++ if (restore_context) { ++ mov(esi, Operand::StaticVariable(context_address)); ++ } ++#ifdef DEBUG ++ mov(Operand::StaticVariable(context_address), Immediate(0)); ++#endif ++ ++ // Clear the top frame. ++ ExternalReference c_entry_fp_address(IsolateAddressId::kCEntryFPAddress, ++ isolate()); ++ mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0)); ++} ++ ++ ++void MacroAssembler::LeaveApiExitFrame(bool restore_context) { ++ mov(esp, ebp); ++ pop(ebp); ++ ++ LeaveExitFrameEpilogue(restore_context); ++} ++ ++ ++void MacroAssembler::PushStackHandler() { ++ // Adjust this code if not the case. ++ STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize); ++ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); ++ ++ // Link the current handler as the next handler. ++ ExternalReference handler_address(IsolateAddressId::kHandlerAddress, ++ isolate()); ++ push(Operand::StaticVariable(handler_address)); ++ ++ // Set this new handler as the current one. ++ mov(Operand::StaticVariable(handler_address), esp); ++} ++ ++ ++void MacroAssembler::PopStackHandler() { ++ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); ++ ExternalReference handler_address(IsolateAddressId::kHandlerAddress, ++ isolate()); ++ pop(Operand::StaticVariable(handler_address)); ++ add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize)); ++} ++ ++ ++// Compute the hash code from the untagged key. This must be kept in sync with ++// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in ++// code-stub-hydrogen.cc ++// ++// Note: r0 will contain hash code ++void MacroAssembler::GetNumberHash(Register r0, Register scratch) { ++ // Xor original key with a seed. ++ if (serializer_enabled()) { ++ ExternalReference roots_array_start = ++ ExternalReference::roots_array_start(isolate()); ++ mov(scratch, Immediate(Heap::kHashSeedRootIndex)); ++ mov(scratch, ++ Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); ++ SmiUntag(scratch); ++ xor_(r0, scratch); ++ } else { ++ int32_t seed = isolate()->heap()->HashSeed(); ++ xor_(r0, Immediate(seed)); ++ } ++ ++ // hash = ~hash + (hash << 15); ++ mov(scratch, r0); ++ not_(r0); ++ shl(scratch, 15); ++ add(r0, scratch); ++ // hash = hash ^ (hash >> 12); ++ mov(scratch, r0); ++ shr(scratch, 12); ++ xor_(r0, scratch); ++ // hash = hash + (hash << 2); ++ lea(r0, Operand(r0, r0, times_4, 0)); ++ // hash = hash ^ (hash >> 4); ++ mov(scratch, r0); ++ shr(scratch, 4); ++ xor_(r0, scratch); ++ // hash = hash * 2057; ++ imul(r0, r0, 2057); ++ // hash = hash ^ (hash >> 16); ++ mov(scratch, r0); ++ shr(scratch, 16); ++ xor_(r0, scratch); ++ and_(r0, 0x3fffffff); ++} ++ ++void MacroAssembler::LoadAllocationTopHelper(Register result, ++ Register scratch, ++ AllocationFlags flags) { ++ ExternalReference allocation_top = ++ AllocationUtils::GetAllocationTopReference(isolate(), flags); ++ ++ // Just return if allocation top is already known. ++ if ((flags & RESULT_CONTAINS_TOP) != 0) { ++ // No use of scratch if allocation top is provided. ++ DCHECK(scratch.is(no_reg)); ++#ifdef DEBUG ++ // Assert that result actually contains top on entry. ++ cmp(result, Operand::StaticVariable(allocation_top)); ++ Check(equal, kUnexpectedAllocationTop); ++#endif ++ return; ++ } ++ ++ // Move address of new object to result. Use scratch register if available. ++ if (scratch.is(no_reg)) { ++ mov(result, Operand::StaticVariable(allocation_top)); ++ } else { ++ mov(scratch, Immediate(allocation_top)); ++ mov(result, Operand(scratch, 0)); ++ } ++} ++ ++ ++void MacroAssembler::UpdateAllocationTopHelper(Register result_end, ++ Register scratch, ++ AllocationFlags flags) { ++ if (emit_debug_code()) { ++ test(result_end, Immediate(kObjectAlignmentMask)); ++ Check(zero, kUnalignedAllocationInNewSpace); ++ } ++ ++ ExternalReference allocation_top = ++ AllocationUtils::GetAllocationTopReference(isolate(), flags); ++ ++ // Update new top. Use scratch if available. ++ if (scratch.is(no_reg)) { ++ mov(Operand::StaticVariable(allocation_top), result_end); ++ } else { ++ mov(Operand(scratch, 0), result_end); ++ } ++} ++ ++ ++void MacroAssembler::Allocate(int object_size, ++ Register result, ++ Register result_end, ++ Register scratch, ++ Label* gc_required, ++ AllocationFlags flags) { ++ DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); ++ DCHECK(object_size <= kMaxRegularHeapObjectSize); ++ if (!FLAG_inline_new) { ++ if (emit_debug_code()) { ++ // Trash the registers to simulate an allocation failure. ++ mov(result, Immediate(0x7091)); ++ if (result_end.is_valid()) { ++ mov(result_end, Immediate(0x7191)); ++ } ++ if (scratch.is_valid()) { ++ mov(scratch, Immediate(0x7291)); ++ } ++ } ++ jmp(gc_required); ++ return; ++ } ++ DCHECK(!result.is(result_end)); ++ ++ // Load address of new object into result. ++ LoadAllocationTopHelper(result, scratch, flags); ++ ++ ExternalReference allocation_limit = ++ AllocationUtils::GetAllocationLimitReference(isolate(), flags); ++ ++ // Align the next allocation. Storing the filler map without checking top is ++ // safe in new-space because the limit of the heap is aligned there. ++ if ((flags & DOUBLE_ALIGNMENT) != 0) { ++ DCHECK(kPointerAlignment * 2 == kDoubleAlignment); ++ Label aligned; ++ test(result, Immediate(kDoubleAlignmentMask)); ++ j(zero, &aligned, Label::kNear); ++ if ((flags & PRETENURE) != 0) { ++ cmp(result, Operand::StaticVariable(allocation_limit)); ++ j(above_equal, gc_required); ++ } ++ mov(Operand(result, 0), ++ Immediate(isolate()->factory()->one_pointer_filler_map())); ++ add(result, Immediate(kDoubleSize / 2)); ++ bind(&aligned); ++ } ++ ++ // Calculate new top and bail out if space is exhausted. ++ Register top_reg = result_end.is_valid() ? result_end : result; ++ ++ if (!top_reg.is(result)) { ++ mov(top_reg, result); ++ } ++ add(top_reg, Immediate(object_size)); ++ cmp(top_reg, Operand::StaticVariable(allocation_limit)); ++ j(above, gc_required); ++ ++ UpdateAllocationTopHelper(top_reg, scratch, flags); ++ ++ if (top_reg.is(result)) { ++ sub(result, Immediate(object_size - kHeapObjectTag)); ++ } else { ++ // Tag the result. ++ DCHECK(kHeapObjectTag == 1); ++ inc(result); ++ } ++} ++ ++ ++void MacroAssembler::Allocate(int header_size, ++ ScaleFactor element_size, ++ Register element_count, ++ RegisterValueType element_count_type, ++ Register result, ++ Register result_end, ++ Register scratch, ++ Label* gc_required, ++ AllocationFlags flags) { ++ DCHECK((flags & SIZE_IN_WORDS) == 0); ++ if (!FLAG_inline_new) { ++ if (emit_debug_code()) { ++ // Trash the registers to simulate an allocation failure. ++ mov(result, Immediate(0x7091)); ++ mov(result_end, Immediate(0x7191)); ++ if (scratch.is_valid()) { ++ mov(scratch, Immediate(0x7291)); ++ } ++ // Register element_count is not modified by the function. ++ } ++ jmp(gc_required); ++ return; ++ } ++ DCHECK(!result.is(result_end)); ++ ++ // Load address of new object into result. ++ LoadAllocationTopHelper(result, scratch, flags); ++ ++ ExternalReference allocation_limit = ++ AllocationUtils::GetAllocationLimitReference(isolate(), flags); ++ ++ // Align the next allocation. Storing the filler map without checking top is ++ // safe in new-space because the limit of the heap is aligned there. ++ if ((flags & DOUBLE_ALIGNMENT) != 0) { ++ DCHECK(kPointerAlignment * 2 == kDoubleAlignment); ++ Label aligned; ++ test(result, Immediate(kDoubleAlignmentMask)); ++ j(zero, &aligned, Label::kNear); ++ if ((flags & PRETENURE) != 0) { ++ cmp(result, Operand::StaticVariable(allocation_limit)); ++ j(above_equal, gc_required); ++ } ++ mov(Operand(result, 0), ++ Immediate(isolate()->factory()->one_pointer_filler_map())); ++ add(result, Immediate(kDoubleSize / 2)); ++ bind(&aligned); ++ } ++ ++ // Calculate new top and bail out if space is exhausted. ++ // We assume that element_count*element_size + header_size does not ++ // overflow. ++ if (element_count_type == REGISTER_VALUE_IS_SMI) { ++ STATIC_ASSERT(static_cast(times_2 - 1) == times_1); ++ STATIC_ASSERT(static_cast(times_4 - 1) == times_2); ++ STATIC_ASSERT(static_cast(times_8 - 1) == times_4); ++ DCHECK(element_size >= times_2); ++ DCHECK(kSmiTagSize == 1); ++ element_size = static_cast(element_size - 1); ++ } else { ++ DCHECK(element_count_type == REGISTER_VALUE_IS_INT32); ++ } ++ lea(result_end, Operand(element_count, element_size, header_size)); ++ add(result_end, result); ++ j(carry, gc_required); ++ cmp(result_end, Operand::StaticVariable(allocation_limit)); ++ j(above, gc_required); ++ ++ // Tag result. ++ DCHECK(kHeapObjectTag == 1); ++ inc(result); ++ ++ // Update allocation top. ++ UpdateAllocationTopHelper(result_end, scratch, flags); ++} ++ ++void MacroAssembler::Allocate(Register object_size, ++ Register result, ++ Register result_end, ++ Register scratch, ++ Label* gc_required, ++ AllocationFlags flags) { ++ DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0); ++ if (!FLAG_inline_new) { ++ if (emit_debug_code()) { ++ // Trash the registers to simulate an allocation failure. ++ mov(result, Immediate(0x7091)); ++ mov(result_end, Immediate(0x7191)); ++ if (scratch.is_valid()) { ++ mov(scratch, Immediate(0x7291)); ++ } ++ // object_size is left unchanged by this function. ++ } ++ jmp(gc_required); ++ return; ++ } ++ DCHECK(!result.is(result_end)); ++ ++ // Load address of new object into result. ++ LoadAllocationTopHelper(result, scratch, flags); ++ ++ ExternalReference allocation_limit = ++ AllocationUtils::GetAllocationLimitReference(isolate(), flags); ++ ++ // Align the next allocation. Storing the filler map without checking top is ++ // safe in new-space because the limit of the heap is aligned there. ++ if ((flags & DOUBLE_ALIGNMENT) != 0) { ++ DCHECK(kPointerAlignment * 2 == kDoubleAlignment); ++ Label aligned; ++ test(result, Immediate(kDoubleAlignmentMask)); ++ j(zero, &aligned, Label::kNear); ++ if ((flags & PRETENURE) != 0) { ++ cmp(result, Operand::StaticVariable(allocation_limit)); ++ j(above_equal, gc_required); ++ } ++ mov(Operand(result, 0), ++ Immediate(isolate()->factory()->one_pointer_filler_map())); ++ add(result, Immediate(kDoubleSize / 2)); ++ bind(&aligned); ++ } ++ ++ // Calculate new top and bail out if space is exhausted. ++ if (!object_size.is(result_end)) { ++ mov(result_end, object_size); ++ } ++ add(result_end, result); ++ cmp(result_end, Operand::StaticVariable(allocation_limit)); ++ j(above, gc_required); ++ ++ // Tag result. ++ DCHECK(kHeapObjectTag == 1); ++ inc(result); ++ ++ UpdateAllocationTopHelper(result_end, scratch, flags); ++} ++ ++void MacroAssembler::AllocateHeapNumber(Register result, ++ Register scratch1, ++ Register scratch2, ++ Label* gc_required, ++ MutableMode mode) { ++ // Allocate heap number in new space. ++ Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, ++ NO_ALLOCATION_FLAGS); ++ ++ Handle map = mode == MUTABLE ++ ? isolate()->factory()->mutable_heap_number_map() ++ : isolate()->factory()->heap_number_map(); ++ ++ // Set the map. ++ mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map)); ++} ++ ++void MacroAssembler::AllocateJSValue(Register result, Register constructor, ++ Register value, Register scratch, ++ Label* gc_required) { ++ DCHECK(!result.is(constructor)); ++ DCHECK(!result.is(scratch)); ++ DCHECK(!result.is(value)); ++ ++ // Allocate JSValue in new space. ++ Allocate(JSValue::kSize, result, scratch, no_reg, gc_required, ++ NO_ALLOCATION_FLAGS); ++ ++ // Initialize the JSValue. ++ LoadGlobalFunctionInitialMap(constructor, scratch); ++ mov(FieldOperand(result, HeapObject::kMapOffset), scratch); ++ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex); ++ mov(FieldOperand(result, JSObject::kPropertiesOrHashOffset), scratch); ++ mov(FieldOperand(result, JSObject::kElementsOffset), scratch); ++ mov(FieldOperand(result, JSValue::kValueOffset), value); ++ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); ++} ++ ++void MacroAssembler::InitializeFieldsWithFiller(Register current_address, ++ Register end_address, ++ Register filler) { ++ Label loop, entry; ++ jmp(&entry, Label::kNear); ++ bind(&loop); ++ mov(Operand(current_address, 0), filler); ++ add(current_address, Immediate(kPointerSize)); ++ bind(&entry); ++ cmp(current_address, end_address); ++ j(below, &loop, Label::kNear); ++} ++ ++ ++void MacroAssembler::BooleanBitTest(Register object, ++ int field_offset, ++ int bit_index) { ++ bit_index += kSmiTagSize + kSmiShiftSize; ++ DCHECK(base::bits::IsPowerOfTwo(kBitsPerByte)); ++ int byte_index = bit_index / kBitsPerByte; ++ int byte_bit_index = bit_index & (kBitsPerByte - 1); ++ test_b(FieldOperand(object, field_offset + byte_index), ++ Immediate(1 << byte_bit_index)); ++} ++ ++void MacroAssembler::GetMapConstructor(Register result, Register map, ++ Register temp) { ++ Label done, loop; ++ mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset)); ++ bind(&loop); ++ JumpIfSmi(result, &done, Label::kNear); ++ CmpObjectType(result, MAP_TYPE, temp); ++ j(not_equal, &done, Label::kNear); ++ mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset)); ++ jmp(&loop); ++ bind(&done); ++} ++ ++void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { ++ DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs. ++ call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); ++} ++ ++ ++void MacroAssembler::TailCallStub(CodeStub* stub) { ++ jmp(stub->GetCode(), RelocInfo::CODE_TARGET); ++} ++ ++ ++ ++bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { ++ return has_frame_ || !stub->SometimesSetsUpAFrame(); ++} ++ ++void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, ++ SaveFPRegsMode save_doubles) { ++ // If the expected number of arguments of the runtime function is ++ // constant, we check that the actual number of arguments match the ++ // expectation. ++ CHECK(f->nargs < 0 || f->nargs == num_arguments); ++ ++ // TODO(1236192): Most runtime routines don't need the number of ++ // arguments passed in because it is constant. At some point we ++ // should remove this need and make the runtime routine entry code ++ // smarter. ++ Move(eax, Immediate(num_arguments)); ++ mov(ebx, Immediate(ExternalReference(f, isolate()))); ++ CEntryStub ces(isolate(), 1, save_doubles); ++ CallStub(&ces); ++} ++ ++ ++void MacroAssembler::CallExternalReference(ExternalReference ref, ++ int num_arguments) { ++ mov(eax, Immediate(num_arguments)); ++ mov(ebx, Immediate(ref)); ++ ++ CEntryStub stub(isolate(), 1); ++ CallStub(&stub); ++} ++ ++ ++void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { ++ // ----------- S t a t e ------------- ++ // -- esp[0] : return address ++ // -- esp[8] : argument num_arguments - 1 ++ // ... ++ // -- esp[8 * num_arguments] : argument 0 (receiver) ++ // ++ // For runtime functions with variable arguments: ++ // -- eax : number of arguments ++ // ----------------------------------- ++ ++ const Runtime::Function* function = Runtime::FunctionForId(fid); ++ DCHECK_EQ(1, function->result_size); ++ if (function->nargs >= 0) { ++ // TODO(1236192): Most runtime routines don't need the number of ++ // arguments passed in because it is constant. At some point we ++ // should remove this need and make the runtime routine entry code ++ // smarter. ++ mov(eax, Immediate(function->nargs)); ++ } ++ JumpToExternalReference(ExternalReference(fid, isolate())); ++} ++ ++void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, ++ bool builtin_exit_frame) { ++ // Set the entry point and jump to the C entry runtime stub. ++ mov(ebx, Immediate(ext)); ++ CEntryStub ces(isolate(), 1, kDontSaveFPRegs, kArgvOnStack, ++ builtin_exit_frame); ++ jmp(ces.GetCode(), RelocInfo::CODE_TARGET); ++} ++ ++void MacroAssembler::PrepareForTailCall( ++ const ParameterCount& callee_args_count, Register caller_args_count_reg, ++ Register scratch0, Register scratch1, ReturnAddressState ra_state, ++ int number_of_temp_values_after_return_address) { ++#if DEBUG ++ if (callee_args_count.is_reg()) { ++ DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0, ++ scratch1)); ++ } else { ++ DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1)); ++ } ++ DCHECK(ra_state != ReturnAddressState::kNotOnStack || ++ number_of_temp_values_after_return_address == 0); ++#endif ++ ++ // Calculate the destination address where we will put the return address ++ // after we drop current frame. ++ Register new_sp_reg = scratch0; ++ if (callee_args_count.is_reg()) { ++ sub(caller_args_count_reg, callee_args_count.reg()); ++ lea(new_sp_reg, ++ Operand(ebp, caller_args_count_reg, times_pointer_size, ++ StandardFrameConstants::kCallerPCOffset - ++ number_of_temp_values_after_return_address * kPointerSize)); ++ } else { ++ lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size, ++ StandardFrameConstants::kCallerPCOffset - ++ (callee_args_count.immediate() + ++ number_of_temp_values_after_return_address) * ++ kPointerSize)); ++ } ++ ++ if (FLAG_debug_code) { ++ cmp(esp, new_sp_reg); ++ Check(below, kStackAccessBelowStackPointer); ++ } ++ ++ // Copy return address from caller's frame to current frame's return address ++ // to avoid its trashing and let the following loop copy it to the right ++ // place. ++ Register tmp_reg = scratch1; ++ if (ra_state == ReturnAddressState::kOnStack) { ++ mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset)); ++ mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize), ++ tmp_reg); ++ } else { ++ DCHECK(ReturnAddressState::kNotOnStack == ra_state); ++ DCHECK_EQ(0, number_of_temp_values_after_return_address); ++ Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset)); ++ } ++ ++ // Restore caller's frame pointer now as it could be overwritten by ++ // the copying loop. ++ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); ++ ++ // +2 here is to copy both receiver and return address. ++ Register count_reg = caller_args_count_reg; ++ if (callee_args_count.is_reg()) { ++ lea(count_reg, Operand(callee_args_count.reg(), ++ 2 + number_of_temp_values_after_return_address)); ++ } else { ++ mov(count_reg, Immediate(callee_args_count.immediate() + 2 + ++ number_of_temp_values_after_return_address)); ++ // TODO(ishell): Unroll copying loop for small immediate values. ++ } ++ ++ // Now copy callee arguments to the caller frame going backwards to avoid ++ // callee arguments corruption (source and destination areas could overlap). ++ Label loop, entry; ++ jmp(&entry, Label::kNear); ++ bind(&loop); ++ dec(count_reg); ++ mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0)); ++ mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg); ++ bind(&entry); ++ cmp(count_reg, Immediate(0)); ++ j(not_equal, &loop, Label::kNear); ++ ++ // Leave current frame. ++ mov(esp, new_sp_reg); ++} ++ ++void MacroAssembler::InvokePrologue(const ParameterCount& expected, ++ const ParameterCount& actual, ++ Label* done, ++ bool* definitely_mismatches, ++ InvokeFlag flag, ++ Label::Distance done_near, ++ const CallWrapper& call_wrapper) { ++ bool definitely_matches = false; ++ *definitely_mismatches = false; ++ Label invoke; ++ if (expected.is_immediate()) { ++ DCHECK(actual.is_immediate()); ++ mov(eax, actual.immediate()); ++ if (expected.immediate() == actual.immediate()) { ++ definitely_matches = true; ++ } else { ++ const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; ++ if (expected.immediate() == sentinel) { ++ // Don't worry about adapting arguments for builtins that ++ // don't want that done. Skip adaption code by making it look ++ // like we have a match between expected and actual number of ++ // arguments. ++ definitely_matches = true; ++ } else { ++ *definitely_mismatches = true; ++ mov(ebx, expected.immediate()); ++ } ++ } ++ } else { ++ if (actual.is_immediate()) { ++ // Expected is in register, actual is immediate. This is the ++ // case when we invoke function values without going through the ++ // IC mechanism. ++ mov(eax, actual.immediate()); ++ cmp(expected.reg(), actual.immediate()); ++ j(equal, &invoke); ++ DCHECK(expected.reg().is(ebx)); ++ } else if (!expected.reg().is(actual.reg())) { ++ // Both expected and actual are in (different) registers. This ++ // is the case when we invoke functions using call and apply. ++ cmp(expected.reg(), actual.reg()); ++ j(equal, &invoke); ++ DCHECK(actual.reg().is(eax)); ++ DCHECK(expected.reg().is(ebx)); ++ } else { ++ Move(eax, actual.reg()); ++ } ++ } ++ ++ if (!definitely_matches) { ++ Handle adaptor = ++ isolate()->builtins()->ArgumentsAdaptorTrampoline(); ++ if (flag == CALL_FUNCTION) { ++ call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET)); ++ call(adaptor, RelocInfo::CODE_TARGET); ++ call_wrapper.AfterCall(); ++ if (!*definitely_mismatches) { ++ jmp(done, done_near); ++ } ++ } else { ++ jmp(adaptor, RelocInfo::CODE_TARGET); ++ } ++ bind(&invoke); ++ } ++} ++ ++void MacroAssembler::CheckDebugHook(Register fun, Register new_target, ++ const ParameterCount& expected, ++ const ParameterCount& actual) { ++ Label skip_hook; ++ ExternalReference debug_hook_active = ++ ExternalReference::debug_hook_on_function_call_address(isolate()); ++ cmpb(Operand::StaticVariable(debug_hook_active), Immediate(0)); ++ j(equal, &skip_hook); ++ { ++ FrameScope frame(this, ++ has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); ++ if (expected.is_reg()) { ++ SmiTag(expected.reg()); ++ Push(expected.reg()); ++ } ++ if (actual.is_reg()) { ++ SmiTag(actual.reg()); ++ Push(actual.reg()); ++ } ++ if (new_target.is_valid()) { ++ Push(new_target); ++ } ++ Push(fun); ++ Push(fun); ++ CallRuntime(Runtime::kDebugOnFunctionCall); ++ Pop(fun); ++ if (new_target.is_valid()) { ++ Pop(new_target); ++ } ++ if (actual.is_reg()) { ++ Pop(actual.reg()); ++ SmiUntag(actual.reg()); ++ } ++ if (expected.is_reg()) { ++ Pop(expected.reg()); ++ SmiUntag(expected.reg()); ++ } ++ } ++ bind(&skip_hook); ++} ++ ++ ++void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ++ const ParameterCount& expected, ++ const ParameterCount& actual, ++ InvokeFlag flag, ++ const CallWrapper& call_wrapper) { ++ // You can't call a function without a valid frame. ++ DCHECK(flag == JUMP_FUNCTION || has_frame()); ++ DCHECK(function.is(edi)); ++ DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx)); ++ ++ if (call_wrapper.NeedsDebugHookCheck()) { ++ CheckDebugHook(function, new_target, expected, actual); ++ } ++ ++ // Clear the new.target register if not given. ++ if (!new_target.is_valid()) { ++ mov(edx, isolate()->factory()->undefined_value()); ++ } ++ ++ Label done; ++ bool definitely_mismatches = false; ++ InvokePrologue(expected, actual, &done, &definitely_mismatches, flag, ++ Label::kNear, call_wrapper); ++ if (!definitely_mismatches) { ++ // We call indirectly through the code field in the function to ++ // allow recompilation to take effect without changing any of the ++ // call sites. ++ Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset); ++ if (flag == CALL_FUNCTION) { ++ call_wrapper.BeforeCall(CallSize(code)); ++ call(code); ++ call_wrapper.AfterCall(); ++ } else { ++ DCHECK(flag == JUMP_FUNCTION); ++ jmp(code); ++ } ++ bind(&done); ++ } ++} ++ ++ ++void MacroAssembler::InvokeFunction(Register fun, Register new_target, ++ const ParameterCount& actual, ++ InvokeFlag flag, ++ const CallWrapper& call_wrapper) { ++ // You can't call a function without a valid frame. ++ DCHECK(flag == JUMP_FUNCTION || has_frame()); ++ ++ DCHECK(fun.is(edi)); ++ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); ++ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); ++ ++ ParameterCount expected(ebx); ++ InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper); ++} ++ ++ ++void MacroAssembler::InvokeFunction(Register fun, ++ const ParameterCount& expected, ++ const ParameterCount& actual, ++ InvokeFlag flag, ++ const CallWrapper& call_wrapper) { ++ // You can't call a function without a valid frame. ++ DCHECK(flag == JUMP_FUNCTION || has_frame()); ++ ++ DCHECK(fun.is(edi)); ++ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); ++ ++ InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper); ++} ++ ++ ++void MacroAssembler::InvokeFunction(Handle function, ++ const ParameterCount& expected, ++ const ParameterCount& actual, ++ InvokeFlag flag, ++ const CallWrapper& call_wrapper) { ++ LoadHeapObject(edi, function); ++ InvokeFunction(edi, expected, actual, flag, call_wrapper); ++} ++ ++ ++void MacroAssembler::LoadContext(Register dst, int context_chain_length) { ++ if (context_chain_length > 0) { ++ // Move up the chain of contexts to the context containing the slot. ++ mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX))); ++ for (int i = 1; i < context_chain_length; i++) { ++ mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); ++ } ++ } else { ++ // Slot is in the current function context. Move it into the ++ // destination register in case we store into it (the write barrier ++ // cannot be allowed to destroy the context in esi). ++ mov(dst, esi); ++ } ++ ++ // We should not have found a with context by walking the context chain ++ // (i.e., the static scope chain and runtime context chain do not agree). ++ // A variable occurring in such a scope should have slot type LOOKUP and ++ // not CONTEXT. ++ if (emit_debug_code()) { ++ cmp(FieldOperand(dst, HeapObject::kMapOffset), ++ isolate()->factory()->with_context_map()); ++ Check(not_equal, kVariableResolvedToWithContext); ++ } ++} ++ ++ ++void MacroAssembler::LoadGlobalProxy(Register dst) { ++ mov(dst, NativeContextOperand()); ++ mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX)); ++} ++ ++void MacroAssembler::LoadGlobalFunction(int index, Register function) { ++ // Load the native context from the current context. ++ mov(function, NativeContextOperand()); ++ // Load the function from the native context. ++ mov(function, ContextOperand(function, index)); ++} ++ ++ ++void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, ++ Register map) { ++ // Load the initial map. The global functions all have initial maps. ++ mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); ++ if (emit_debug_code()) { ++ Label ok, fail; ++ CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK); ++ jmp(&ok); ++ bind(&fail); ++ Abort(kGlobalFunctionsMustHaveInitialMap); ++ bind(&ok); ++ } ++} ++ ++ ++// Store the value in register src in the safepoint register stack ++// slot for register dst. ++void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) { ++ mov(SafepointRegisterSlot(dst), src); ++} ++ ++ ++void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) { ++ mov(SafepointRegisterSlot(dst), src); ++} ++ ++ ++void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { ++ mov(dst, SafepointRegisterSlot(src)); ++} ++ ++ ++Operand MacroAssembler::SafepointRegisterSlot(Register reg) { ++ return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); ++} ++ ++ ++int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { ++ // The registers are pushed starting with the lowest encoding, ++ // which means that lowest encodings are furthest away from ++ // the stack pointer. ++ DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters); ++ return kNumSafepointRegisters - reg_code - 1; ++} ++ ++ ++void MacroAssembler::LoadHeapObject(Register result, ++ Handle object) { ++ mov(result, object); ++} ++ ++ ++void MacroAssembler::CmpHeapObject(Register reg, Handle object) { ++ cmp(reg, object); ++} ++ ++void MacroAssembler::PushHeapObject(Handle object) { Push(object); } ++ ++void MacroAssembler::GetWeakValue(Register value, Handle cell) { ++ mov(value, cell); ++ mov(value, FieldOperand(value, WeakCell::kValueOffset)); ++} ++ ++ ++void MacroAssembler::LoadWeakValue(Register value, Handle cell, ++ Label* miss) { ++ GetWeakValue(value, cell); ++ JumpIfSmi(value, miss); ++} ++ ++ ++void MacroAssembler::Ret() { ++ ret(0); ++} ++ ++ ++void MacroAssembler::Ret(int bytes_dropped, Register scratch) { ++ if (is_uint16(bytes_dropped)) { ++ ret(bytes_dropped); ++ } else { ++ pop(scratch); ++ add(esp, Immediate(bytes_dropped)); ++ push(scratch); ++ ret(0); ++ } ++} ++ ++ ++void MacroAssembler::VerifyX87StackDepth(uint32_t depth) { ++ // Turn off the stack depth check when serializer is enabled to reduce the ++ // code size. ++ if (serializer_enabled()) return; ++ // Make sure the floating point stack is either empty or has depth items. ++ DCHECK(depth <= 7); ++ // This is very expensive. ++ DCHECK(FLAG_debug_code && FLAG_enable_slow_asserts); ++ ++ // The top-of-stack (tos) is 7 if there is one item pushed. ++ int tos = (8 - depth) % 8; ++ const int kTopMask = 0x3800; ++ push(eax); ++ fwait(); ++ fnstsw_ax(); ++ and_(eax, kTopMask); ++ shr(eax, 11); ++ cmp(eax, Immediate(tos)); ++ Check(equal, kUnexpectedFPUStackDepthAfterInstruction); ++ fnclex(); ++ pop(eax); ++} ++ ++ ++void MacroAssembler::Drop(int stack_elements) { ++ if (stack_elements > 0) { ++ add(esp, Immediate(stack_elements * kPointerSize)); ++ } ++} ++ ++ ++void MacroAssembler::Move(Register dst, Register src) { ++ if (!dst.is(src)) { ++ mov(dst, src); ++ } ++} ++ ++ ++void MacroAssembler::Move(Register dst, const Immediate& x) { ++ if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) { ++ xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. ++ } else { ++ mov(dst, x); ++ } ++} ++ ++ ++void MacroAssembler::Move(const Operand& dst, const Immediate& x) { ++ mov(dst, x); ++} ++ ++ ++void MacroAssembler::Lzcnt(Register dst, const Operand& src) { ++ // TODO(intel): Add support for LZCNT (with ABM/BMI1). ++ Label not_zero_src; ++ bsr(dst, src); ++ j(not_zero, ¬_zero_src, Label::kNear); ++ Move(dst, Immediate(63)); // 63^31 == 32 ++ bind(¬_zero_src); ++ xor_(dst, Immediate(31)); // for x in [0..31], 31^x == 31-x. ++} ++ ++ ++void MacroAssembler::Tzcnt(Register dst, const Operand& src) { ++ // TODO(intel): Add support for TZCNT (with ABM/BMI1). ++ Label not_zero_src; ++ bsf(dst, src); ++ j(not_zero, ¬_zero_src, Label::kNear); ++ Move(dst, Immediate(32)); // The result of tzcnt is 32 if src = 0. ++ bind(¬_zero_src); ++} ++ ++ ++void MacroAssembler::Popcnt(Register dst, const Operand& src) { ++ // TODO(intel): Add support for POPCNT (with POPCNT) ++ // if (CpuFeatures::IsSupported(POPCNT)) { ++ // CpuFeatureScope scope(this, POPCNT); ++ // popcnt(dst, src); ++ // return; ++ // } ++ UNREACHABLE(); ++} ++ ++ ++void MacroAssembler::SetCounter(StatsCounter* counter, int value) { ++ if (FLAG_native_code_counters && counter->Enabled()) { ++ mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); ++ } ++} ++ ++ ++void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { ++ DCHECK(value > 0); ++ if (FLAG_native_code_counters && counter->Enabled()) { ++ Operand operand = Operand::StaticVariable(ExternalReference(counter)); ++ if (value == 1) { ++ inc(operand); ++ } else { ++ add(operand, Immediate(value)); ++ } ++ } ++} ++ ++ ++void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { ++ DCHECK(value > 0); ++ if (FLAG_native_code_counters && counter->Enabled()) { ++ Operand operand = Operand::StaticVariable(ExternalReference(counter)); ++ if (value == 1) { ++ dec(operand); ++ } else { ++ sub(operand, Immediate(value)); ++ } ++ } ++} ++ ++ ++void MacroAssembler::IncrementCounter(Condition cc, ++ StatsCounter* counter, ++ int value) { ++ DCHECK(value > 0); ++ if (FLAG_native_code_counters && counter->Enabled()) { ++ Label skip; ++ j(NegateCondition(cc), &skip); ++ pushfd(); ++ IncrementCounter(counter, value); ++ popfd(); ++ bind(&skip); ++ } ++} ++ ++ ++void MacroAssembler::DecrementCounter(Condition cc, ++ StatsCounter* counter, ++ int value) { ++ DCHECK(value > 0); ++ if (FLAG_native_code_counters && counter->Enabled()) { ++ Label skip; ++ j(NegateCondition(cc), &skip); ++ pushfd(); ++ DecrementCounter(counter, value); ++ popfd(); ++ bind(&skip); ++ } ++} ++ ++ ++void MacroAssembler::Assert(Condition cc, BailoutReason reason) { ++ if (emit_debug_code()) Check(cc, reason); ++} ++ ++ ++ ++void MacroAssembler::Check(Condition cc, BailoutReason reason) { ++ Label L; ++ j(cc, &L); ++ Abort(reason); ++ // will not return here ++ bind(&L); ++} ++ ++ ++void MacroAssembler::CheckStackAlignment() { ++ int frame_alignment = base::OS::ActivationFrameAlignment(); ++ int frame_alignment_mask = frame_alignment - 1; ++ if (frame_alignment > kPointerSize) { ++ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); ++ Label alignment_as_expected; ++ test(esp, Immediate(frame_alignment_mask)); ++ j(zero, &alignment_as_expected); ++ // Abort if stack is not aligned. ++ int3(); ++ bind(&alignment_as_expected); ++ } ++} ++ ++ ++void MacroAssembler::Abort(BailoutReason reason) { ++#ifdef DEBUG ++ const char* msg = GetBailoutReason(reason); ++ if (msg != NULL) { ++ RecordComment("Abort message: "); ++ RecordComment(msg); ++ } ++ ++ if (FLAG_trap_on_abort) { ++ int3(); ++ return; ++ } ++#endif ++ ++ // Check if Abort() has already been initialized. ++ DCHECK(isolate()->builtins()->Abort()->IsHeapObject()); ++ ++ Move(edx, Smi::FromInt(static_cast(reason))); ++ ++ // Disable stub call restrictions to always allow calls to abort. ++ if (!has_frame_) { ++ // We don't actually want to generate a pile of code for this, so just ++ // claim there is a stack frame, without generating one. ++ FrameScope scope(this, StackFrame::NONE); ++ Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); ++ } else { ++ Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET); ++ } ++ // will not return here ++ int3(); ++} ++ ++ ++void MacroAssembler::LoadInstanceDescriptors(Register map, ++ Register descriptors) { ++ mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset)); ++} ++ ++ ++void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) { ++ mov(dst, FieldOperand(map, Map::kBitField3Offset)); ++ DecodeField(dst); ++} ++ ++ ++void MacroAssembler::LoadAccessor(Register dst, Register holder, ++ int accessor_index, ++ AccessorComponent accessor) { ++ mov(dst, FieldOperand(holder, HeapObject::kMapOffset)); ++ LoadInstanceDescriptors(dst, dst); ++ mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index))); ++ int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset ++ : AccessorPair::kSetterOffset; ++ mov(dst, FieldOperand(dst, offset)); ++} ++ ++void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1, ++ Register object2, ++ Register scratch1, ++ Register scratch2, ++ Label* failure) { ++ // Check that both objects are not smis. ++ STATIC_ASSERT(kSmiTag == 0); ++ mov(scratch1, object1); ++ and_(scratch1, object2); ++ JumpIfSmi(scratch1, failure); ++ ++ // Load instance type for both strings. ++ mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset)); ++ mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset)); ++ movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); ++ movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); ++ ++ // Check that both are flat one-byte strings. ++ const int kFlatOneByteStringMask = ++ kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; ++ const int kFlatOneByteStringTag = ++ kStringTag | kOneByteStringTag | kSeqStringTag; ++ // Interleave bits from both instance types and compare them in one check. ++ const int kShift = 8; ++ DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << kShift)); ++ and_(scratch1, kFlatOneByteStringMask); ++ and_(scratch2, kFlatOneByteStringMask); ++ shl(scratch2, kShift); ++ or_(scratch1, scratch2); ++ cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << kShift)); ++ j(not_equal, failure); ++} ++ ++ ++void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand, ++ Label* not_unique_name, ++ Label::Distance distance) { ++ STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); ++ Label succeed; ++ test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); ++ j(zero, &succeed); ++ cmpb(operand, Immediate(SYMBOL_TYPE)); ++ j(not_equal, not_unique_name, distance); ++ ++ bind(&succeed); ++} ++ ++ ++void MacroAssembler::EmitSeqStringSetCharCheck(Register string, ++ Register index, ++ Register value, ++ uint32_t encoding_mask) { ++ Label is_object; ++ JumpIfNotSmi(string, &is_object, Label::kNear); ++ Abort(kNonObject); ++ bind(&is_object); ++ ++ push(value); ++ mov(value, FieldOperand(string, HeapObject::kMapOffset)); ++ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset)); ++ ++ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask)); ++ cmp(value, Immediate(encoding_mask)); ++ pop(value); ++ Check(equal, kUnexpectedStringType); ++ ++ // The index is assumed to be untagged coming in, tag it to compare with the ++ // string length without using a temp register, it is restored at the end of ++ // this function. ++ SmiTag(index); ++ Check(no_overflow, kIndexIsTooLarge); ++ ++ cmp(index, FieldOperand(string, String::kLengthOffset)); ++ Check(less, kIndexIsTooLarge); ++ ++ cmp(index, Immediate(Smi::kZero)); ++ Check(greater_equal, kIndexIsNegative); ++ ++ // Restore the index ++ SmiUntag(index); ++} ++ ++ ++void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { ++ int frame_alignment = base::OS::ActivationFrameAlignment(); ++ if (frame_alignment != 0) { ++ // Make stack end at alignment and make room for num_arguments words ++ // and the original value of esp. ++ mov(scratch, esp); ++ sub(esp, Immediate((num_arguments + 1) * kPointerSize)); ++ DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); ++ and_(esp, -frame_alignment); ++ mov(Operand(esp, num_arguments * kPointerSize), scratch); ++ } else { ++ sub(esp, Immediate(num_arguments * kPointerSize)); ++ } ++} ++ ++ ++void MacroAssembler::CallCFunction(ExternalReference function, ++ int num_arguments) { ++ // Trashing eax is ok as it will be the return value. ++ mov(eax, Immediate(function)); ++ CallCFunction(eax, num_arguments); ++} ++ ++ ++void MacroAssembler::CallCFunction(Register function, ++ int num_arguments) { ++ DCHECK(has_frame()); ++ // Check stack alignment. ++ if (emit_debug_code()) { ++ CheckStackAlignment(); ++ } ++ ++ call(function); ++ if (base::OS::ActivationFrameAlignment() != 0) { ++ mov(esp, Operand(esp, num_arguments * kPointerSize)); ++ } else { ++ add(esp, Immediate(num_arguments * kPointerSize)); ++ } ++} ++ ++ ++#ifdef DEBUG ++bool AreAliased(Register reg1, ++ Register reg2, ++ Register reg3, ++ Register reg4, ++ Register reg5, ++ Register reg6, ++ Register reg7, ++ Register reg8) { ++ int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + ++ reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() + ++ reg7.is_valid() + reg8.is_valid(); ++ ++ RegList regs = 0; ++ if (reg1.is_valid()) regs |= reg1.bit(); ++ if (reg2.is_valid()) regs |= reg2.bit(); ++ if (reg3.is_valid()) regs |= reg3.bit(); ++ if (reg4.is_valid()) regs |= reg4.bit(); ++ if (reg5.is_valid()) regs |= reg5.bit(); ++ if (reg6.is_valid()) regs |= reg6.bit(); ++ if (reg7.is_valid()) regs |= reg7.bit(); ++ if (reg8.is_valid()) regs |= reg8.bit(); ++ int n_of_non_aliasing_regs = NumRegs(regs); ++ ++ return n_of_valid_regs != n_of_non_aliasing_regs; ++} ++#endif ++ ++ ++CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size) ++ : address_(address), ++ size_(size), ++ masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) { ++ // Create a new macro assembler pointing to the address of the code to patch. ++ // The size is adjusted with kGap on order for the assembler to generate size ++ // bytes of instructions without failing with buffer size constraints. ++ DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); ++} ++ ++ ++CodePatcher::~CodePatcher() { ++ // Indicate that code has changed. ++ Assembler::FlushICache(masm_.isolate(), address_, size_); ++ ++ // Check that the code was patched as expected. ++ DCHECK(masm_.pc_ == address_ + size_); ++ DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); ++} ++ ++ ++void MacroAssembler::CheckPageFlag( ++ Register object, ++ Register scratch, ++ int mask, ++ Condition cc, ++ Label* condition_met, ++ Label::Distance condition_met_distance) { ++ DCHECK(cc == zero || cc == not_zero); ++ if (scratch.is(object)) { ++ and_(scratch, Immediate(~Page::kPageAlignmentMask)); ++ } else { ++ mov(scratch, Immediate(~Page::kPageAlignmentMask)); ++ and_(scratch, object); ++ } ++ if (mask < (1 << kBitsPerByte)) { ++ test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); ++ } else { ++ test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask)); ++ } ++ j(cc, condition_met, condition_met_distance); ++} ++ ++ ++void MacroAssembler::CheckPageFlagForMap( ++ Handle map, ++ int mask, ++ Condition cc, ++ Label* condition_met, ++ Label::Distance condition_met_distance) { ++ DCHECK(cc == zero || cc == not_zero); ++ Page* page = Page::FromAddress(map->address()); ++ DCHECK(!serializer_enabled()); // Serializer cannot match page_flags. ++ ExternalReference reference(ExternalReference::page_flags(page)); ++ // The inlined static address check of the page's flags relies ++ // on maps never being compacted. ++ DCHECK(!isolate()->heap()->mark_compact_collector()-> ++ IsOnEvacuationCandidate(*map)); ++ if (mask < (1 << kBitsPerByte)) { ++ test_b(Operand::StaticVariable(reference), Immediate(mask)); ++ } else { ++ test(Operand::StaticVariable(reference), Immediate(mask)); ++ } ++ j(cc, condition_met, condition_met_distance); ++} ++ ++ ++void MacroAssembler::JumpIfBlack(Register object, ++ Register scratch0, ++ Register scratch1, ++ Label* on_black, ++ Label::Distance on_black_near) { ++ HasColor(object, scratch0, scratch1, on_black, on_black_near, 1, ++ 1); // kBlackBitPattern. ++ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); ++} ++ ++ ++void MacroAssembler::HasColor(Register object, ++ Register bitmap_scratch, ++ Register mask_scratch, ++ Label* has_color, ++ Label::Distance has_color_distance, ++ int first_bit, ++ int second_bit) { ++ DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx)); ++ ++ GetMarkBits(object, bitmap_scratch, mask_scratch); ++ ++ Label other_color, word_boundary; ++ test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); ++ j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear); ++ add(mask_scratch, mask_scratch); // Shift left 1 by adding. ++ j(zero, &word_boundary, Label::kNear); ++ test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); ++ j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); ++ jmp(&other_color, Label::kNear); ++ ++ bind(&word_boundary); ++ test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), ++ Immediate(1)); ++ ++ j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance); ++ bind(&other_color); ++} ++ ++ ++void MacroAssembler::GetMarkBits(Register addr_reg, ++ Register bitmap_reg, ++ Register mask_reg) { ++ DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx)); ++ mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask)); ++ and_(bitmap_reg, addr_reg); ++ mov(ecx, addr_reg); ++ int shift = ++ Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2; ++ shr(ecx, shift); ++ and_(ecx, ++ (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1)); ++ ++ add(bitmap_reg, ecx); ++ mov(ecx, addr_reg); ++ shr(ecx, kPointerSizeLog2); ++ and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1); ++ mov(mask_reg, Immediate(1)); ++ shl_cl(mask_reg); ++} ++ ++ ++void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch, ++ Register mask_scratch, Label* value_is_white, ++ Label::Distance distance) { ++ DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx)); ++ GetMarkBits(value, bitmap_scratch, mask_scratch); ++ ++ // If the value is black or grey we don't need to do anything. ++ DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); ++ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); ++ DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); ++ DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); ++ ++ // Since both black and grey have a 1 in the first position and white does ++ // not have a 1 there we only need to check one bit. ++ test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize)); ++ j(zero, value_is_white, Label::kNear); ++} ++ ++ ++void MacroAssembler::EnumLength(Register dst, Register map) { ++ STATIC_ASSERT(Map::EnumLengthBits::kShift == 0); ++ mov(dst, FieldOperand(map, Map::kBitField3Offset)); ++ and_(dst, Immediate(Map::EnumLengthBits::kMask)); ++ SmiTag(dst); ++} ++ ++ ++void MacroAssembler::CheckEnumCache(Label* call_runtime) { ++ Label next, start; ++ mov(ecx, eax); ++ ++ // Check if the enum length field is properly initialized, indicating that ++ // there is an enum cache. ++ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); ++ ++ EnumLength(edx, ebx); ++ cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel))); ++ j(equal, call_runtime); ++ ++ jmp(&start); ++ ++ bind(&next); ++ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); ++ ++ // For all objects but the receiver, check that the cache is empty. ++ EnumLength(edx, ebx); ++ cmp(edx, Immediate(Smi::kZero)); ++ j(not_equal, call_runtime); ++ ++ bind(&start); ++ ++ // Check that there are no elements. Register rcx contains the current JS ++ // object we've reached through the prototype chain. ++ Label no_elements; ++ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); ++ cmp(ecx, isolate()->factory()->empty_fixed_array()); ++ j(equal, &no_elements); ++ ++ // Second chance, the object may be using the empty slow element dictionary. ++ cmp(ecx, isolate()->factory()->empty_slow_element_dictionary()); ++ j(not_equal, call_runtime); ++ ++ bind(&no_elements); ++ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); ++ cmp(ecx, isolate()->factory()->null_value()); ++ j(not_equal, &next); ++} ++ ++ ++void MacroAssembler::TestJSArrayForAllocationMemento( ++ Register receiver_reg, ++ Register scratch_reg, ++ Label* no_memento_found) { ++ Label map_check; ++ Label top_check; ++ ExternalReference new_space_allocation_top = ++ ExternalReference::new_space_allocation_top_address(isolate()); ++ const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag; ++ const int kMementoLastWordOffset = ++ kMementoMapOffset + AllocationMemento::kSize - kPointerSize; ++ ++ // Bail out if the object is not in new space. ++ JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found); ++ // If the object is in new space, we need to check whether it is on the same ++ // page as the current top. ++ lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); ++ xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); ++ test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); ++ j(zero, &top_check); ++ // The object is on a different page than allocation top. Bail out if the ++ // object sits on the page boundary as no memento can follow and we cannot ++ // touch the memory following it. ++ lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); ++ xor_(scratch_reg, receiver_reg); ++ test(scratch_reg, Immediate(~Page::kPageAlignmentMask)); ++ j(not_zero, no_memento_found); ++ // Continue with the actual map check. ++ jmp(&map_check); ++ // If top is on the same page as the current object, we need to check whether ++ // we are below top. ++ bind(&top_check); ++ lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset)); ++ cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top)); ++ j(greater_equal, no_memento_found); ++ // Memento map check. ++ bind(&map_check); ++ mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset)); ++ cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map())); ++} ++ ++void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) { ++ DCHECK(!dividend.is(eax)); ++ DCHECK(!dividend.is(edx)); ++ base::MagicNumbersForDivision mag = ++ base::SignedDivisionByConstant(static_cast(divisor)); ++ mov(eax, Immediate(mag.multiplier)); ++ imul(dividend); ++ bool neg = (mag.multiplier & (static_cast(1) << 31)) != 0; ++ if (divisor > 0 && neg) add(edx, dividend); ++ if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend); ++ if (mag.shift > 0) sar(edx, mag.shift); ++ mov(eax, dividend); ++ shr(eax, 31); ++ add(edx, eax); ++} ++ ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_TARGET_ARCH_X87 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/macro-assembler-x87.h 2017-12-25 17:42:57.224465515 +0100 +@@ -0,0 +1,906 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_X87_MACRO_ASSEMBLER_X87_H_ ++#define V8_X87_MACRO_ASSEMBLER_X87_H_ ++ ++#include "src/assembler.h" ++#include "src/bailout-reason.h" ++#include "src/frames.h" ++#include "src/globals.h" ++ ++namespace v8 { ++namespace internal { ++ ++// Give alias names to registers for calling conventions. ++const Register kReturnRegister0 = {Register::kCode_eax}; ++const Register kReturnRegister1 = {Register::kCode_edx}; ++const Register kReturnRegister2 = {Register::kCode_edi}; ++const Register kJSFunctionRegister = {Register::kCode_edi}; ++const Register kContextRegister = {Register::kCode_esi}; ++const Register kAllocateSizeRegister = {Register::kCode_edx}; ++const Register kInterpreterAccumulatorRegister = {Register::kCode_eax}; ++const Register kInterpreterBytecodeOffsetRegister = {Register::kCode_ecx}; ++const Register kInterpreterBytecodeArrayRegister = {Register::kCode_edi}; ++const Register kInterpreterDispatchTableRegister = {Register::kCode_esi}; ++const Register kJavaScriptCallArgCountRegister = {Register::kCode_eax}; ++const Register kJavaScriptCallNewTargetRegister = {Register::kCode_edx}; ++const Register kRuntimeCallFunctionRegister = {Register::kCode_ebx}; ++const Register kRuntimeCallArgCountRegister = {Register::kCode_eax}; ++ ++// Spill slots used by interpreter dispatch calling convention. ++const int kInterpreterDispatchTableSpillSlot = -1; ++ ++// Convenience for platform-independent signatures. We do not normally ++// distinguish memory operands from other operands on ia32. ++typedef Operand MemOperand; ++ ++enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET }; ++enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; ++enum PointersToHereCheck { ++ kPointersToHereMaybeInteresting, ++ kPointersToHereAreAlwaysInteresting ++}; ++ ++enum RegisterValueType { REGISTER_VALUE_IS_SMI, REGISTER_VALUE_IS_INT32 }; ++ ++enum class ReturnAddressState { kOnStack, kNotOnStack }; ++ ++#ifdef DEBUG ++bool AreAliased(Register reg1, Register reg2, Register reg3 = no_reg, ++ Register reg4 = no_reg, Register reg5 = no_reg, ++ Register reg6 = no_reg, Register reg7 = no_reg, ++ Register reg8 = no_reg); ++#endif ++ ++// MacroAssembler implements a collection of frequently used macros. ++class MacroAssembler: public Assembler { ++ public: ++ MacroAssembler(Isolate* isolate, void* buffer, int size, ++ CodeObjectRequired create_code_object); ++ ++ Isolate* isolate() const { return isolate_; } ++ ++ void Load(Register dst, const Operand& src, Representation r); ++ void Store(Register src, const Operand& dst, Representation r); ++ ++ // Load a register with a long value as efficiently as possible. ++ void Set(Register dst, int32_t x) { ++ if (x == 0) { ++ xor_(dst, dst); ++ } else { ++ mov(dst, Immediate(x)); ++ } ++ } ++ void Set(const Operand& dst, int32_t x) { mov(dst, Immediate(x)); } ++ ++ // Operations on roots in the root-array. ++ void LoadRoot(Register destination, Heap::RootListIndex index); ++ void StoreRoot(Register source, Register scratch, Heap::RootListIndex index); ++ void CompareRoot(Register with, Register scratch, Heap::RootListIndex index); ++ // These methods can only be used with constant roots (i.e. non-writable ++ // and not in new space). ++ void CompareRoot(Register with, Heap::RootListIndex index); ++ void CompareRoot(const Operand& with, Heap::RootListIndex index); ++ void PushRoot(Heap::RootListIndex index); ++ ++ // Compare the object in a register to a value and jump if they are equal. ++ void JumpIfRoot(Register with, Heap::RootListIndex index, Label* if_equal, ++ Label::Distance if_equal_distance = Label::kFar) { ++ CompareRoot(with, index); ++ j(equal, if_equal, if_equal_distance); ++ } ++ void JumpIfRoot(const Operand& with, Heap::RootListIndex index, ++ Label* if_equal, ++ Label::Distance if_equal_distance = Label::kFar) { ++ CompareRoot(with, index); ++ j(equal, if_equal, if_equal_distance); ++ } ++ ++ // Compare the object in a register to a value and jump if they are not equal. ++ void JumpIfNotRoot(Register with, Heap::RootListIndex index, ++ Label* if_not_equal, ++ Label::Distance if_not_equal_distance = Label::kFar) { ++ CompareRoot(with, index); ++ j(not_equal, if_not_equal, if_not_equal_distance); ++ } ++ void JumpIfNotRoot(const Operand& with, Heap::RootListIndex index, ++ Label* if_not_equal, ++ Label::Distance if_not_equal_distance = Label::kFar) { ++ CompareRoot(with, index); ++ j(not_equal, if_not_equal, if_not_equal_distance); ++ } ++ ++ // These functions do not arrange the registers in any particular order so ++ // they are not useful for calls that can cause a GC. The caller can ++ // exclude up to 3 registers that do not need to be saved and restored. ++ void PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, ++ Register exclusion2 = no_reg, ++ Register exclusion3 = no_reg); ++ void PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, ++ Register exclusion2 = no_reg, ++ Register exclusion3 = no_reg); ++ ++ // --------------------------------------------------------------------------- ++ // GC Support ++ enum RememberedSetFinalAction { kReturnAtEnd, kFallThroughAtEnd }; ++ ++ // Record in the remembered set the fact that we have a pointer to new space ++ // at the address pointed to by the addr register. Only works if addr is not ++ // in new space. ++ void RememberedSetHelper(Register object, // Used for debug code. ++ Register addr, Register scratch, ++ SaveFPRegsMode save_fp, ++ RememberedSetFinalAction and_then); ++ ++ void CheckPageFlag(Register object, Register scratch, int mask, Condition cc, ++ Label* condition_met, ++ Label::Distance condition_met_distance = Label::kFar); ++ ++ void CheckPageFlagForMap( ++ Handle map, int mask, Condition cc, Label* condition_met, ++ Label::Distance condition_met_distance = Label::kFar); ++ ++ // Check if object is in new space. Jumps if the object is not in new space. ++ // The register scratch can be object itself, but scratch will be clobbered. ++ void JumpIfNotInNewSpace(Register object, Register scratch, Label* branch, ++ Label::Distance distance = Label::kFar) { ++ InNewSpace(object, scratch, zero, branch, distance); ++ } ++ ++ // Check if object is in new space. Jumps if the object is in new space. ++ // The register scratch can be object itself, but it will be clobbered. ++ void JumpIfInNewSpace(Register object, Register scratch, Label* branch, ++ Label::Distance distance = Label::kFar) { ++ InNewSpace(object, scratch, not_zero, branch, distance); ++ } ++ ++ // Check if an object has a given incremental marking color. Also uses ecx! ++ void HasColor(Register object, Register scratch0, Register scratch1, ++ Label* has_color, Label::Distance has_color_distance, ++ int first_bit, int second_bit); ++ ++ void JumpIfBlack(Register object, Register scratch0, Register scratch1, ++ Label* on_black, ++ Label::Distance on_black_distance = Label::kFar); ++ ++ // Checks the color of an object. If the object is white we jump to the ++ // incremental marker. ++ void JumpIfWhite(Register value, Register scratch1, Register scratch2, ++ Label* value_is_white, Label::Distance distance); ++ ++ // Notify the garbage collector that we wrote a pointer into an object. ++ // |object| is the object being stored into, |value| is the object being ++ // stored. value and scratch registers are clobbered by the operation. ++ // The offset is the offset from the start of the object, not the offset from ++ // the tagged HeapObject pointer. For use with FieldOperand(reg, off). ++ void RecordWriteField( ++ Register object, int offset, Register value, Register scratch, ++ SaveFPRegsMode save_fp, ++ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, ++ SmiCheck smi_check = INLINE_SMI_CHECK, ++ PointersToHereCheck pointers_to_here_check_for_value = ++ kPointersToHereMaybeInteresting); ++ ++ // As above, but the offset has the tag presubtracted. For use with ++ // Operand(reg, off). ++ void RecordWriteContextSlot( ++ Register context, int offset, Register value, Register scratch, ++ SaveFPRegsMode save_fp, ++ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, ++ SmiCheck smi_check = INLINE_SMI_CHECK, ++ PointersToHereCheck pointers_to_here_check_for_value = ++ kPointersToHereMaybeInteresting) { ++ RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp, ++ remembered_set_action, smi_check, ++ pointers_to_here_check_for_value); ++ } ++ ++ // For page containing |object| mark region covering |address| ++ // dirty. |object| is the object being stored into, |value| is the ++ // object being stored. The address and value registers are clobbered by the ++ // operation. RecordWrite filters out smis so it does not update the ++ // write barrier if the value is a smi. ++ void RecordWrite( ++ Register object, Register address, Register value, SaveFPRegsMode save_fp, ++ RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET, ++ SmiCheck smi_check = INLINE_SMI_CHECK, ++ PointersToHereCheck pointers_to_here_check_for_value = ++ kPointersToHereMaybeInteresting); ++ ++ // Notify the garbage collector that we wrote a code entry into a ++ // JSFunction. Only scratch is clobbered by the operation. ++ void RecordWriteCodeEntryField(Register js_function, Register code_entry, ++ Register scratch); ++ ++ // For page containing |object| mark the region covering the object's map ++ // dirty. |object| is the object being stored into, |map| is the Map object ++ // that was stored. ++ void RecordWriteForMap(Register object, Handle map, Register scratch1, ++ Register scratch2, SaveFPRegsMode save_fp); ++ ++ // --------------------------------------------------------------------------- ++ // Debugger Support ++ ++ void DebugBreak(); ++ ++ // Generates function and stub prologue code. ++ void StubPrologue(StackFrame::Type type); ++ void Prologue(bool code_pre_aging); ++ ++ // Enter specific kind of exit frame. Expects the number of ++ // arguments in register eax and sets up the number of arguments in ++ // register edi and the pointer to the first argument in register ++ // esi. ++ void EnterExitFrame(int argc, bool save_doubles, StackFrame::Type frame_type); ++ ++ void EnterApiExitFrame(int argc); ++ ++ // Leave the current exit frame. Expects the return value in ++ // register eax:edx (untouched) and the pointer to the first ++ // argument in register esi (if pop_arguments == true). ++ void LeaveExitFrame(bool save_doubles, bool pop_arguments = true); ++ ++ // Leave the current exit frame. Expects the return value in ++ // register eax (untouched). ++ void LeaveApiExitFrame(bool restore_context); ++ ++ // Find the function context up the context chain. ++ void LoadContext(Register dst, int context_chain_length); ++ ++ // Load the global proxy from the current context. ++ void LoadGlobalProxy(Register dst); ++ ++ // Load the global function with the given index. ++ void LoadGlobalFunction(int index, Register function); ++ ++ // Load the initial map from the global function. The registers ++ // function and map can be the same. ++ void LoadGlobalFunctionInitialMap(Register function, Register map); ++ ++ // Push and pop the registers that can hold pointers. ++ void PushSafepointRegisters() { pushad(); } ++ void PopSafepointRegisters() { popad(); } ++ // Store the value in register/immediate src in the safepoint ++ // register stack slot for register dst. ++ void StoreToSafepointRegisterSlot(Register dst, Register src); ++ void StoreToSafepointRegisterSlot(Register dst, Immediate src); ++ void LoadFromSafepointRegisterSlot(Register dst, Register src); ++ ++ // Nop, because x87 does not have a root register. ++ void InitializeRootRegister() {} ++ ++ void LoadHeapObject(Register result, Handle object); ++ void CmpHeapObject(Register reg, Handle object); ++ void PushHeapObject(Handle object); ++ ++ void LoadObject(Register result, Handle object) { ++ AllowDeferredHandleDereference heap_object_check; ++ if (object->IsHeapObject()) { ++ LoadHeapObject(result, Handle::cast(object)); ++ } else { ++ Move(result, Immediate(object)); ++ } ++ } ++ ++ void CmpObject(Register reg, Handle object) { ++ AllowDeferredHandleDereference heap_object_check; ++ if (object->IsHeapObject()) { ++ CmpHeapObject(reg, Handle::cast(object)); ++ } else { ++ cmp(reg, Immediate(object)); ++ } ++ } ++ ++ void GetWeakValue(Register value, Handle cell); ++ void LoadWeakValue(Register value, Handle cell, Label* miss); ++ ++ // --------------------------------------------------------------------------- ++ // JavaScript invokes ++ ++ // Removes current frame and its arguments from the stack preserving ++ // the arguments and a return address pushed to the stack for the next call. ++ // |ra_state| defines whether return address is already pushed to stack or ++ // not. Both |callee_args_count| and |caller_args_count_reg| do not include ++ // receiver. |callee_args_count| is not modified, |caller_args_count_reg| ++ // is trashed. |number_of_temp_values_after_return_address| specifies ++ // the number of words pushed to the stack after the return address. This is ++ // to allow "allocation" of scratch registers that this function requires ++ // by saving their values on the stack. ++ void PrepareForTailCall(const ParameterCount& callee_args_count, ++ Register caller_args_count_reg, Register scratch0, ++ Register scratch1, ReturnAddressState ra_state, ++ int number_of_temp_values_after_return_address); ++ ++ // Invoke the JavaScript function code by either calling or jumping. ++ ++ void InvokeFunctionCode(Register function, Register new_target, ++ const ParameterCount& expected, ++ const ParameterCount& actual, InvokeFlag flag, ++ const CallWrapper& call_wrapper); ++ ++ // On function call, call into the debugger if necessary. ++ void CheckDebugHook(Register fun, Register new_target, ++ const ParameterCount& expected, ++ const ParameterCount& actual); ++ ++ // Invoke the JavaScript function in the given register. Changes the ++ // current context to the context in the function before invoking. ++ void InvokeFunction(Register function, Register new_target, ++ const ParameterCount& actual, InvokeFlag flag, ++ const CallWrapper& call_wrapper); ++ ++ void InvokeFunction(Register function, const ParameterCount& expected, ++ const ParameterCount& actual, InvokeFlag flag, ++ const CallWrapper& call_wrapper); ++ ++ void InvokeFunction(Handle function, ++ const ParameterCount& expected, ++ const ParameterCount& actual, InvokeFlag flag, ++ const CallWrapper& call_wrapper); ++ ++ void ShlPair(Register high, Register low, uint8_t imm8); ++ void ShlPair_cl(Register high, Register low); ++ void ShrPair(Register high, Register low, uint8_t imm8); ++ void ShrPair_cl(Register high, Register src); ++ void SarPair(Register high, Register low, uint8_t imm8); ++ void SarPair_cl(Register high, Register low); ++ ++ // Expression support ++ // Support for constant splitting. ++ bool IsUnsafeImmediate(const Immediate& x); ++ void SafeMove(Register dst, const Immediate& x); ++ void SafePush(const Immediate& x); ++ ++ // Compare object type for heap object. ++ // Incoming register is heap_object and outgoing register is map. ++ void CmpObjectType(Register heap_object, InstanceType type, Register map); ++ ++ // Compare instance type for map. ++ void CmpInstanceType(Register map, InstanceType type); ++ ++ // Compare an object's map with the specified map. ++ void CompareMap(Register obj, Handle map); ++ ++ // Check if the map of an object is equal to a specified map and branch to ++ // label if not. Skip the smi check if not required (object is known to be a ++ // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match ++ // against maps that are ElementsKind transition maps of the specified map. ++ void CheckMap(Register obj, Handle map, Label* fail, ++ SmiCheckType smi_check_type); ++ ++ // Check if the object in register heap_object is a string. Afterwards the ++ // register map contains the object map and the register instance_type ++ // contains the instance_type. The registers map and instance_type can be the ++ // same in which case it contains the instance type afterwards. Either of the ++ // registers map and instance_type can be the same as heap_object. ++ Condition IsObjectStringType(Register heap_object, Register map, ++ Register instance_type); ++ ++ // FCmp is similar to integer cmp, but requires unsigned ++ // jcc instructions (je, ja, jae, jb, jbe, je, and jz). ++ void FCmp(); ++ void FXamMinusZero(); ++ void FXamSign(); ++ void X87CheckIA(); ++ void X87SetRC(int rc); ++ void X87SetFPUCW(int cw); ++ ++ void ClampUint8(Register reg); ++ void ClampTOSToUint8(Register result_reg); ++ ++ void SlowTruncateToI(Register result_reg, Register input_reg, ++ int offset = HeapNumber::kValueOffset - kHeapObjectTag); ++ ++ void TruncateHeapNumberToI(Register result_reg, Register input_reg); ++ void TruncateX87TOSToI(Register result_reg); ++ ++ void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode, ++ Label* lost_precision, Label* is_nan, Label* minus_zero, ++ Label::Distance dst = Label::kFar); ++ ++ // Smi tagging support. ++ void SmiTag(Register reg) { ++ STATIC_ASSERT(kSmiTag == 0); ++ STATIC_ASSERT(kSmiTagSize == 1); ++ add(reg, reg); ++ } ++ void SmiUntag(Register reg) { ++ sar(reg, kSmiTagSize); ++ } ++ ++ // Modifies the register even if it does not contain a Smi! ++ void SmiUntag(Register reg, Label* is_smi) { ++ STATIC_ASSERT(kSmiTagSize == 1); ++ sar(reg, kSmiTagSize); ++ STATIC_ASSERT(kSmiTag == 0); ++ j(not_carry, is_smi); ++ } ++ ++ void LoadUint32NoSSE2(Register src) { ++ LoadUint32NoSSE2(Operand(src)); ++ } ++ void LoadUint32NoSSE2(const Operand& src); ++ ++ // Jump the register contains a smi. ++ inline void JumpIfSmi(Register value, Label* smi_label, ++ Label::Distance distance = Label::kFar) { ++ test(value, Immediate(kSmiTagMask)); ++ j(zero, smi_label, distance); ++ } ++ // Jump if the operand is a smi. ++ inline void JumpIfSmi(Operand value, Label* smi_label, ++ Label::Distance distance = Label::kFar) { ++ test(value, Immediate(kSmiTagMask)); ++ j(zero, smi_label, distance); ++ } ++ // Jump if register contain a non-smi. ++ inline void JumpIfNotSmi(Register value, Label* not_smi_label, ++ Label::Distance distance = Label::kFar) { ++ test(value, Immediate(kSmiTagMask)); ++ j(not_zero, not_smi_label, distance); ++ } ++ // Jump if the operand is not a smi. ++ inline void JumpIfNotSmi(Operand value, Label* smi_label, ++ Label::Distance distance = Label::kFar) { ++ test(value, Immediate(kSmiTagMask)); ++ j(not_zero, smi_label, distance); ++ } ++ // Jump if the value cannot be represented by a smi. ++ inline void JumpIfNotValidSmiValue(Register value, Register scratch, ++ Label* on_invalid, ++ Label::Distance distance = Label::kFar) { ++ mov(scratch, value); ++ add(scratch, Immediate(0x40000000U)); ++ j(sign, on_invalid, distance); ++ } ++ ++ // Jump if the unsigned integer value cannot be represented by a smi. ++ inline void JumpIfUIntNotValidSmiValue( ++ Register value, Label* on_invalid, ++ Label::Distance distance = Label::kFar) { ++ cmp(value, Immediate(0x40000000U)); ++ j(above_equal, on_invalid, distance); ++ } ++ ++ void LoadInstanceDescriptors(Register map, Register descriptors); ++ void EnumLength(Register dst, Register map); ++ void NumberOfOwnDescriptors(Register dst, Register map); ++ void LoadAccessor(Register dst, Register holder, int accessor_index, ++ AccessorComponent accessor); ++ ++ template ++ void DecodeField(Register reg) { ++ static const int shift = Field::kShift; ++ static const int mask = Field::kMask >> Field::kShift; ++ if (shift != 0) { ++ sar(reg, shift); ++ } ++ and_(reg, Immediate(mask)); ++ } ++ ++ template ++ void DecodeFieldToSmi(Register reg) { ++ static const int shift = Field::kShift; ++ static const int mask = (Field::kMask >> Field::kShift) << kSmiTagSize; ++ STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0); ++ STATIC_ASSERT(kSmiTag == 0); ++ if (shift < kSmiTagSize) { ++ shl(reg, kSmiTagSize - shift); ++ } else if (shift > kSmiTagSize) { ++ sar(reg, shift - kSmiTagSize); ++ } ++ and_(reg, Immediate(mask)); ++ } ++ ++ // Abort execution if argument is not a smi, enabled via --debug-code. ++ void AssertSmi(Register object); ++ ++ // Abort execution if argument is a smi, enabled via --debug-code. ++ void AssertNotSmi(Register object); ++ ++ // Abort execution if argument is not a JSFunction, enabled via --debug-code. ++ void AssertFunction(Register object); ++ ++ // Abort execution if argument is not a JSBoundFunction, ++ // enabled via --debug-code. ++ void AssertBoundFunction(Register object); ++ ++ // Abort execution if argument is not a JSGeneratorObject, ++ // enabled via --debug-code. ++ void AssertGeneratorObject(Register object); ++ ++ // Abort execution if argument is not undefined or an AllocationSite, enabled ++ // via --debug-code. ++ void AssertUndefinedOrAllocationSite(Register object); ++ ++ // --------------------------------------------------------------------------- ++ // Exception handling ++ ++ // Push a new stack handler and link it into stack handler chain. ++ void PushStackHandler(); ++ ++ // Unlink the stack handler on top of the stack from the stack handler chain. ++ void PopStackHandler(); ++ ++ // --------------------------------------------------------------------------- ++ // Inline caching support ++ ++ void GetNumberHash(Register r0, Register scratch); ++ ++ // --------------------------------------------------------------------------- ++ // Allocation support ++ ++ // Allocate an object in new space or old space. If the given space ++ // is exhausted control continues at the gc_required label. The allocated ++ // object is returned in result and end of the new object is returned in ++ // result_end. The register scratch can be passed as no_reg in which case ++ // an additional object reference will be added to the reloc info. The ++ // returned pointers in result and result_end have not yet been tagged as ++ // heap objects. If result_contains_top_on_entry is true the content of ++ // result is known to be the allocation top on entry (could be result_end ++ // from a previous call). If result_contains_top_on_entry is true scratch ++ // should be no_reg as it is never used. ++ void Allocate(int object_size, Register result, Register result_end, ++ Register scratch, Label* gc_required, AllocationFlags flags); ++ ++ void Allocate(int header_size, ScaleFactor element_size, ++ Register element_count, RegisterValueType element_count_type, ++ Register result, Register result_end, Register scratch, ++ Label* gc_required, AllocationFlags flags); ++ ++ void Allocate(Register object_size, Register result, Register result_end, ++ Register scratch, Label* gc_required, AllocationFlags flags); ++ ++ // Allocate a heap number in new space with undefined value. The ++ // register scratch2 can be passed as no_reg; the others must be ++ // valid registers. Returns tagged pointer in result register, or ++ // jumps to gc_required if new space is full. ++ void AllocateHeapNumber(Register result, Register scratch1, Register scratch2, ++ Label* gc_required, MutableMode mode = IMMUTABLE); ++ ++ // Allocate and initialize a JSValue wrapper with the specified {constructor} ++ // and {value}. ++ void AllocateJSValue(Register result, Register constructor, Register value, ++ Register scratch, Label* gc_required); ++ ++ // Initialize fields with filler values. Fields starting at |current_address| ++ // not including |end_address| are overwritten with the value in |filler|. At ++ // the end the loop, |current_address| takes the value of |end_address|. ++ void InitializeFieldsWithFiller(Register current_address, ++ Register end_address, Register filler); ++ ++ // --------------------------------------------------------------------------- ++ // Support functions. ++ ++ // Check a boolean-bit of a Smi field. ++ void BooleanBitTest(Register object, int field_offset, int bit_index); ++ ++ // Machine code version of Map::GetConstructor(). ++ // |temp| holds |result|'s map when done. ++ void GetMapConstructor(Register result, Register map, Register temp); ++ ++ // --------------------------------------------------------------------------- ++ // Runtime calls ++ ++ // Call a code stub. Generate the code if necessary. ++ void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None()); ++ ++ // Tail call a code stub (jump). Generate the code if necessary. ++ void TailCallStub(CodeStub* stub); ++ ++ // Call a runtime routine. ++ void CallRuntime(const Runtime::Function* f, int num_arguments, ++ SaveFPRegsMode save_doubles = kDontSaveFPRegs); ++ void CallRuntimeSaveDoubles(Runtime::FunctionId fid) { ++ const Runtime::Function* function = Runtime::FunctionForId(fid); ++ CallRuntime(function, function->nargs, kSaveFPRegs); ++ } ++ ++ // Convenience function: Same as above, but takes the fid instead. ++ void CallRuntime(Runtime::FunctionId fid, ++ SaveFPRegsMode save_doubles = kDontSaveFPRegs) { ++ const Runtime::Function* function = Runtime::FunctionForId(fid); ++ CallRuntime(function, function->nargs, save_doubles); ++ } ++ ++ // Convenience function: Same as above, but takes the fid instead. ++ void CallRuntime(Runtime::FunctionId fid, int num_arguments, ++ SaveFPRegsMode save_doubles = kDontSaveFPRegs) { ++ CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); ++ } ++ ++ // Convenience function: call an external reference. ++ void CallExternalReference(ExternalReference ref, int num_arguments); ++ ++ // Convenience function: tail call a runtime routine (jump). ++ void TailCallRuntime(Runtime::FunctionId fid); ++ ++ // Before calling a C-function from generated code, align arguments on stack. ++ // After aligning the frame, arguments must be stored in esp[0], esp[4], ++ // etc., not pushed. The argument count assumes all arguments are word sized. ++ // Some compilers/platforms require the stack to be aligned when calling ++ // C++ code. ++ // Needs a scratch register to do some arithmetic. This register will be ++ // trashed. ++ void PrepareCallCFunction(int num_arguments, Register scratch); ++ ++ // Calls a C function and cleans up the space for arguments allocated ++ // by PrepareCallCFunction. The called function is not allowed to trigger a ++ // garbage collection, since that might move the code and invalidate the ++ // return address (unless this is somehow accounted for by the called ++ // function). ++ void CallCFunction(ExternalReference function, int num_arguments); ++ void CallCFunction(Register function, int num_arguments); ++ ++ // Jump to a runtime routine. ++ void JumpToExternalReference(const ExternalReference& ext, ++ bool builtin_exit_frame = false); ++ ++ // --------------------------------------------------------------------------- ++ // Utilities ++ ++ void Ret(); ++ ++ // Return and drop arguments from stack, where the number of arguments ++ // may be bigger than 2^16 - 1. Requires a scratch register. ++ void Ret(int bytes_dropped, Register scratch); ++ ++ // Emit code that loads |parameter_index|'th parameter from the stack to ++ // the register according to the CallInterfaceDescriptor definition. ++ // |sp_to_caller_sp_offset_in_words| specifies the number of words pushed ++ // below the caller's sp (on x87 it's at least return address). ++ template ++ void LoadParameterFromStack( ++ Register reg, typename Descriptor::ParameterIndices parameter_index, ++ int sp_to_ra_offset_in_words = 1) { ++ DCHECK(Descriptor::kPassLastArgsOnStack); ++ DCHECK_LT(parameter_index, Descriptor::kParameterCount); ++ DCHECK_LE(Descriptor::kParameterCount - Descriptor::kStackArgumentsCount, ++ parameter_index); ++ int offset = (Descriptor::kParameterCount - parameter_index - 1 + ++ sp_to_ra_offset_in_words) * ++ kPointerSize; ++ mov(reg, Operand(esp, offset)); ++ } ++ ++ // Emit code to discard a non-negative number of pointer-sized elements ++ // from the stack, clobbering only the esp register. ++ void Drop(int element_count); ++ ++ void Call(Label* target) { call(target); } ++ void Call(Handle target, RelocInfo::Mode rmode, ++ TypeFeedbackId id = TypeFeedbackId::None()) { ++ call(target, rmode, id); ++ } ++ void Jump(Handle target, RelocInfo::Mode rmode) { jmp(target, rmode); } ++ void Push(Register src) { push(src); } ++ void Push(const Operand& src) { push(src); } ++ void Push(Immediate value) { push(value); } ++ void Pop(Register dst) { pop(dst); } ++ void Pop(const Operand& dst) { pop(dst); } ++ void PushReturnAddressFrom(Register src) { push(src); } ++ void PopReturnAddressTo(Register dst) { pop(dst); } ++ ++ void Lzcnt(Register dst, Register src) { Lzcnt(dst, Operand(src)); } ++ void Lzcnt(Register dst, const Operand& src); ++ ++ void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); } ++ void Tzcnt(Register dst, const Operand& src); ++ ++ void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); } ++ void Popcnt(Register dst, const Operand& src); ++ ++ // Move if the registers are not identical. ++ void Move(Register target, Register source); ++ ++ // Move a constant into a destination using the most efficient encoding. ++ void Move(Register dst, const Immediate& x); ++ void Move(const Operand& dst, const Immediate& x); ++ ++ void Move(Register dst, Handle handle) { LoadObject(dst, handle); } ++ void Move(Register dst, Smi* source) { Move(dst, Immediate(source)); } ++ ++ // Push a handle value. ++ void Push(Handle handle) { push(Immediate(handle)); } ++ void Push(Smi* smi) { Push(Immediate(smi)); } ++ ++ Handle CodeObject() { ++ DCHECK(!code_object_.is_null()); ++ return code_object_; ++ } ++ ++ // Insert code to verify that the x87 stack has the specified depth (0-7) ++ void VerifyX87StackDepth(uint32_t depth); ++ ++ // Emit code for a truncating division by a constant. The dividend register is ++ // unchanged, the result is in edx, and eax gets clobbered. ++ void TruncatingDiv(Register dividend, int32_t divisor); ++ ++ // --------------------------------------------------------------------------- ++ // StatsCounter support ++ ++ void SetCounter(StatsCounter* counter, int value); ++ void IncrementCounter(StatsCounter* counter, int value); ++ void DecrementCounter(StatsCounter* counter, int value); ++ void IncrementCounter(Condition cc, StatsCounter* counter, int value); ++ void DecrementCounter(Condition cc, StatsCounter* counter, int value); ++ ++ // --------------------------------------------------------------------------- ++ // Debugging ++ ++ // Calls Abort(msg) if the condition cc is not satisfied. ++ // Use --debug_code to enable. ++ void Assert(Condition cc, BailoutReason reason); ++ ++ // Like Assert(), but always enabled. ++ void Check(Condition cc, BailoutReason reason); ++ ++ // Print a message to stdout and abort execution. ++ void Abort(BailoutReason reason); ++ ++ // Check that the stack is aligned. ++ void CheckStackAlignment(); ++ ++ // Verify restrictions about code generated in stubs. ++ void set_generating_stub(bool value) { generating_stub_ = value; } ++ bool generating_stub() { return generating_stub_; } ++ void set_has_frame(bool value) { has_frame_ = value; } ++ bool has_frame() { return has_frame_; } ++ inline bool AllowThisStubCall(CodeStub* stub); ++ ++ // --------------------------------------------------------------------------- ++ // String utilities. ++ ++ // Checks if both objects are sequential one-byte strings, and jumps to label ++ // if either is not. ++ void JumpIfNotBothSequentialOneByteStrings( ++ Register object1, Register object2, Register scratch1, Register scratch2, ++ Label* on_not_flat_one_byte_strings); ++ ++ // Checks if the given register or operand is a unique name ++ void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name, ++ Label::Distance distance = Label::kFar) { ++ JumpIfNotUniqueNameInstanceType(Operand(reg), not_unique_name, distance); ++ } ++ ++ void JumpIfNotUniqueNameInstanceType(Operand operand, Label* not_unique_name, ++ Label::Distance distance = Label::kFar); ++ ++ void EmitSeqStringSetCharCheck(Register string, Register index, ++ Register value, uint32_t encoding_mask); ++ ++ static int SafepointRegisterStackIndex(Register reg) { ++ return SafepointRegisterStackIndex(reg.code()); ++ } ++ ++ // Load the type feedback vector from a JavaScript frame. ++ void EmitLoadFeedbackVector(Register vector); ++ ++ // Activation support. ++ void EnterFrame(StackFrame::Type type); ++ void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg); ++ void LeaveFrame(StackFrame::Type type); ++ ++ void EnterBuiltinFrame(Register context, Register target, Register argc); ++ void LeaveBuiltinFrame(Register context, Register target, Register argc); ++ ++ // Expects object in eax and returns map with validated enum cache ++ // in eax. Assumes that any other register can be used as a scratch. ++ void CheckEnumCache(Label* call_runtime); ++ ++ // AllocationMemento support. Arrays may have an associated ++ // AllocationMemento object that can be checked for in order to pretransition ++ // to another type. ++ // On entry, receiver_reg should point to the array object. ++ // scratch_reg gets clobbered. ++ // If allocation info is present, conditional code is set to equal. ++ void TestJSArrayForAllocationMemento(Register receiver_reg, ++ Register scratch_reg, ++ Label* no_memento_found); ++ ++ private: ++ bool generating_stub_; ++ bool has_frame_; ++ Isolate* isolate_; ++ // This handle will be patched with the code object on installation. ++ Handle code_object_; ++ ++ // Helper functions for generating invokes. ++ void InvokePrologue(const ParameterCount& expected, ++ const ParameterCount& actual, Label* done, ++ bool* definitely_mismatches, InvokeFlag flag, ++ Label::Distance done_distance, ++ const CallWrapper& call_wrapper); ++ ++ void EnterExitFramePrologue(StackFrame::Type frame_type); ++ void EnterExitFrameEpilogue(int argc, bool save_doubles); ++ ++ void LeaveExitFrameEpilogue(bool restore_context); ++ ++ // Allocation support helpers. ++ void LoadAllocationTopHelper(Register result, Register scratch, ++ AllocationFlags flags); ++ ++ void UpdateAllocationTopHelper(Register result_end, Register scratch, ++ AllocationFlags flags); ++ ++ // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace. ++ void InNewSpace(Register object, Register scratch, Condition cc, ++ Label* condition_met, ++ Label::Distance condition_met_distance = Label::kFar); ++ ++ // Helper for finding the mark bits for an address. Afterwards, the ++ // bitmap register points at the word with the mark bits and the mask ++ // the position of the first bit. Uses ecx as scratch and leaves addr_reg ++ // unchanged. ++ inline void GetMarkBits(Register addr_reg, Register bitmap_reg, ++ Register mask_reg); ++ ++ // Compute memory operands for safepoint stack slots. ++ Operand SafepointRegisterSlot(Register reg); ++ static int SafepointRegisterStackIndex(int reg_code); ++ ++ // Needs access to SafepointRegisterStackIndex for compiled frame ++ // traversal. ++ friend class StandardFrame; ++}; ++ ++// The code patcher is used to patch (typically) small parts of code e.g. for ++// debugging and other types of instrumentation. When using the code patcher ++// the exact number of bytes specified must be emitted. Is not legal to emit ++// relocation information. If any of these constraints are violated it causes ++// an assertion. ++class CodePatcher { ++ public: ++ CodePatcher(Isolate* isolate, byte* address, int size); ++ ~CodePatcher(); ++ ++ // Macro assembler to emit code. ++ MacroAssembler* masm() { return &masm_; } ++ ++ private: ++ byte* address_; // The address of the code being patched. ++ int size_; // Number of bytes of the expected patch size. ++ MacroAssembler masm_; // Macro assembler used to generate the code. ++}; ++ ++// ----------------------------------------------------------------------------- ++// Static helper functions. ++ ++// Generate an Operand for loading a field from an object. ++inline Operand FieldOperand(Register object, int offset) { ++ return Operand(object, offset - kHeapObjectTag); ++} ++ ++// Generate an Operand for loading an indexed field from an object. ++inline Operand FieldOperand(Register object, Register index, ScaleFactor scale, ++ int offset) { ++ return Operand(object, index, scale, offset - kHeapObjectTag); ++} ++ ++inline Operand FixedArrayElementOperand(Register array, Register index_as_smi, ++ int additional_offset = 0) { ++ int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize; ++ return FieldOperand(array, index_as_smi, times_half_pointer_size, offset); ++} ++ ++inline Operand ContextOperand(Register context, int index) { ++ return Operand(context, Context::SlotOffset(index)); ++} ++ ++inline Operand ContextOperand(Register context, Register index) { ++ return Operand(context, index, times_pointer_size, Context::SlotOffset(0)); ++} ++ ++inline Operand NativeContextOperand() { ++ return ContextOperand(esi, Context::NATIVE_CONTEXT_INDEX); ++} ++ ++#define ACCESS_MASM(masm) masm-> ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_MACRO_ASSEMBLER_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/OWNERS qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/OWNERS +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/OWNERS 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/OWNERS 2017-12-25 17:42:57.218465603 +0100 +@@ -0,0 +1,2 @@ ++weiliang.lin@intel.com ++chunyang.dai@intel.com +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/simulator-x87.cc qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/simulator-x87.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/simulator-x87.cc 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/simulator-x87.cc 2017-12-25 17:42:57.224465515 +0100 +@@ -0,0 +1,7 @@ ++// Copyright 2008 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "src/x87/simulator-x87.h" ++ ++// Since there is no simulator for the ia32 architecture this file is empty. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/simulator-x87.h qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/simulator-x87.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/src/x87/simulator-x87.h 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/src/x87/simulator-x87.h 2017-12-25 17:42:57.224465515 +0100 +@@ -0,0 +1,52 @@ ++// Copyright 2012 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef V8_X87_SIMULATOR_X87_H_ ++#define V8_X87_SIMULATOR_X87_H_ ++ ++#include "src/allocation.h" ++ ++namespace v8 { ++namespace internal { ++ ++// Since there is no simulator for the ia32 architecture the only thing we can ++// do is to call the entry directly. ++#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ ++ (entry(p0, p1, p2, p3, p4)) ++ ++ ++typedef int (*regexp_matcher)(String*, int, const byte*, ++ const byte*, int*, int, Address, int, Isolate*); ++ ++// Call the generated regexp code directly. The code at the entry address should ++// expect eight int/pointer sized arguments and return an int. ++#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \ ++ p7, p8) \ ++ (FUNCTION_CAST(entry)(p0, p1, p2, p3, p4, p5, p6, p7, p8)) ++ ++ ++// The stack limit beyond which we will throw stack overflow errors in ++// generated code. Because generated code on ia32 uses the C stack, we ++// just use the C stack limit. ++class SimulatorStack : public v8::internal::AllStatic { ++ public: ++ static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, ++ uintptr_t c_limit) { ++ USE(isolate); ++ return c_limit; ++ } ++ ++ static inline uintptr_t RegisterCTryCatch(Isolate* isolate, ++ uintptr_t try_catch_address) { ++ USE(isolate); ++ return try_catch_address; ++ } ++ ++ static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); } ++}; ++ ++} // namespace internal ++} // namespace v8 ++ ++#endif // V8_X87_SIMULATOR_X87_H_ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/test/cctest/BUILD.gn qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/test/cctest/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/test/cctest/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/test/cctest/BUILD.gn 2017-12-25 17:42:57.224465515 +0100 +@@ -287,6 +287,17 @@ + "test-macro-assembler-x64.cc", + "test-run-wasm-relocation-x64.cc", + ] ++ } else if (v8_current_cpu == "x87") { ++ sources += [ ### gcmole(arch:x87) ### ++ "test-assembler-x87.cc", ++ "test-code-stubs-x87.cc", ++ "test-code-stubs.cc", ++ "test-code-stubs.h", ++ "test-disasm-x87.cc", ++ "test-log-stack-tracer.cc", ++ "test-macro-assembler-x87.cc", ++ "test-run-wasm-relocation-x87.cc", ++ ] + } else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") { + sources += [ ### gcmole(arch:ppc) ### + "test-assembler-ppc.cc", +@@ -332,7 +343,7 @@ + + defines = [] + +- if (is_component_build) { ++ if (is_component_build || v8_build_shared) { + # cctest can't be built against a shared library, so we + # need to depend on the underlying static target in that case. + deps += [ "../..:v8_maybe_snapshot" ] +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/test/cctest/cctest.gyp qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/test/cctest/cctest.gyp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/test/cctest/cctest.gyp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/test/cctest/cctest.gyp 2017-12-25 17:43:10.318273560 +0100 +@@ -308,6 +308,16 @@ + 'test-disasm-mips64.cc', + 'test-macro-assembler-mips64.cc', + ], ++ 'cctest_sources_x87': [ ### gcmole(arch:x87) ### ++ 'test-assembler-x87.cc', ++ 'test-code-stubs.cc', ++ 'test-code-stubs.h', ++ 'test-code-stubs-x87.cc', ++ 'test-disasm-x87.cc', ++ 'test-macro-assembler-x87.cc', ++ 'test-log-stack-tracer.cc', ++ 'test-run-wasm-relocation-x87.cc', ++ ], + }, + 'includes': ['../../gypfiles/toolchain.gypi', '../../gypfiles/features.gypi'], + 'targets': [ +@@ -392,6 +402,11 @@ + '<@(cctest_sources_mips64el)', + ], + }], ++ ['v8_target_arch=="x87"', { ++ 'sources': [ ++ '<@(cctest_sources_x87)', ++ ], ++ }], + [ 'OS=="linux" or OS=="qnx"', { + 'sources': [ + 'test-platform-linux.cc', +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/dev/gen-tags.py qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/dev/gen-tags.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/dev/gen-tags.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/dev/gen-tags.py 2017-12-25 17:43:15.534197094 +0100 +@@ -20,7 +20,7 @@ + import sys + + # All arches that this script understands. +-ARCHES = ["ia32", "x64", "arm", "arm64", "mips", "mips64", "ppc", "s390"] ++ARCHES = ["ia32", "x64", "arm", "arm64", "mips", "mips64", "ppc", "s390", "x87"] + + def PrintHelpAndExit(): + print(__doc__) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/dev/gm.py qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/dev/gm.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/dev/gm.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/dev/gm.py 2017-12-25 17:43:15.534197094 +0100 +@@ -33,7 +33,7 @@ + + # All arches that this script understands. + ARCHES = ["ia32", "x64", "arm", "arm64", "mipsel", "mips64el", "ppc", "ppc64", +- "s390", "s390x"] ++ "s390", "s390x", "x87"] + # Arches that get built/run when you don't specify any. + DEFAULT_ARCHES = ["ia32", "x64", "arm", "arm64"] + # Modes that this script understands. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/run-tests.py qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/run-tests.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/run-tests.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/run-tests.py 2017-12-25 17:43:15.534197094 +0100 +@@ -187,6 +187,7 @@ + "android_x64", + "arm", + "ia32", ++ "x87", + "mips", + "mipsel", + "mips64", +@@ -210,6 +211,7 @@ + "mips64el", + "s390", + "s390x", ++ "x87", + "arm64"] + + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/testrunner/local/statusfile.py qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/testrunner/local/statusfile.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/testrunner/local/statusfile.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/testrunner/local/statusfile.py 2017-12-25 17:43:15.534197094 +0100 +@@ -59,10 +59,10 @@ + # Support arches, modes to be written as keywords instead of strings. + VARIABLES = {ALWAYS: True} + for var in ["debug", "release", "big", "little", +- "android_arm", "android_arm64", "android_ia32", "android_x64", +- "arm", "arm64", "ia32", "mips", "mipsel", "mips64", "mips64el", +- "x64", "ppc", "ppc64", "s390", "s390x", "macos", "windows", +- "linux", "aix"]: ++ "android_arm", "android_arm64", "android_ia32", "android_x87", ++ "android_x64", "arm", "arm64", "ia32", "mips", "mipsel", "mips64", ++ "mips64el", "x64", "x87", "ppc", "ppc64", "s390", "s390x", "macos", ++ "windows", "linux", "aix"]: + VARIABLES[var] = var + + # Allow using variants as keywords. +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/verify_source_deps.py qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/verify_source_deps.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/v8/tools/verify_source_deps.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/3rdparty/chromium/v8/tools/verify_source_deps.py 2017-12-25 17:43:15.535197080 +0100 +@@ -82,6 +82,7 @@ + 'solaris', + 'vtune', + 'v8-version.h', ++ 'x87', + ] + + ALL_GN_PREFIXES = [ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/core/core_module.pro qtwebengine-everywhere-src-5.10.0-no-sse2/src/core/core_module.pro +--- qtwebengine-everywhere-src-5.10.0/src/core/core_module.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/core/core_module.pro 2017-12-25 13:05:24.093938639 +0100 +@@ -44,6 +44,31 @@ + else: QMAKE_LFLAGS += $$NINJA_LFLAGS + POST_TARGETDEPS += $$NINJA_TARGETDEPS + ++# go through the shared libraries that GN wants to link to ++# ignore the dummy convert_dict shared library used only to get a .pri file ++# add the ones NOT in lib/sse2 to LIBS_PRIVATE ++# don't add those in lib/sse2 that are only replacements for the normal ones ++# collect all shared libraries, non-SSE2 and SSE2, so they can be installed ++for(shlib, NINJA_SOLIBS) { ++ !contains(shlib, .*convert_dict.*) { ++ contains(shlib, .*/lib/sse2/.*) { ++ shlibs_sse2 += $$shlib ++ } else { ++ LIBS_PRIVATE += $$shlib ++ shlibs += $$shlib ++ } ++ } ++} ++ ++# set the shared libraries to be installed ++# add an rpath to their installation location ++shlib_install_path = $$[QT_INSTALL_LIBS]/qtwebengine ++!isEmpty(shlibs) { ++ shlibs.files += $$shlibs ++ shlibs_sse2.files += $$shlibs_sse2 ++ LIBS_PRIVATE += -Wl,--rpath,$$shlib_install_path ++} ++ + + LIBS_PRIVATE += -L$$api_library_path + CONFIG *= no_smart_library_merge +@@ -113,7 +138,12 @@ + locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales + resources.CONFIG += no_check_exist + resources.path = $$[QT_INSTALL_DATA]/resources +- INSTALLS += locales resources ++ # install the shared libraries ++ shlibs.CONFIG += no_check_exist ++ shlibs.path = $$shlib_install_path ++ shlibs_sse2.CONFIG += no_check_exist ++ shlibs_sse2.path = $$shlib_install_path/sse2 ++ INSTALLS += locales resources shlibs shlibs_sse2 + + !qtConfig(webengine-system-icu) { + icu.CONFIG += no_check_exist +diff -Nur qtwebengine-everywhere-src-5.10.0/src/process/process.pro qtwebengine-everywhere-src-5.10.0-no-sse2/src/process/process.pro +--- qtwebengine-everywhere-src-5.10.0/src/process/process.pro 2017-11-29 09:42:29.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-no-sse2/src/process/process.pro 2017-12-25 13:05:24.093938639 +0100 +@@ -9,6 +9,8 @@ + + SOURCES = main.cpp + ++QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../core/Release ++ + win32 { + SOURCES += \ + support_win.cpp diff --git a/qtwebengine-opensource-src-5.9.0-skia-neon.patch b/qtwebengine-everywhere-src-5.10.0-skia-neon.patch similarity index 62% rename from qtwebengine-opensource-src-5.9.0-skia-neon.patch rename to qtwebengine-everywhere-src-5.10.0-skia-neon.patch index 3506533..82ef406 100644 --- a/qtwebengine-opensource-src-5.9.0-skia-neon.patch +++ b/qtwebengine-everywhere-src-5.10.0-skia-neon.patch @@ -1,32 +1,32 @@ -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/skia/BUILD.gn qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/skia/BUILD.gn ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/skia/BUILD.gn 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/skia/BUILD.gn 2017-06-12 12:59:26.707922417 +0200 -@@ -486,6 +486,24 @@ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/BUILD.gn qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/skia/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/skia/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/skia/BUILD.gn 2017-12-25 18:31:12.288797893 +0100 +@@ -508,6 +508,24 @@ + } # Separated out so it can be compiled with different flags for SSE. - if (!skia_build_no_opts) { -+ if (current_cpu == "arm" && (arm_use_neon || arm_optionally_use_neon)) { -+ source_set("skia_opts_neon") { -+ sources = skia_opts.neon_sources -+ # Root build config sets -mfpu=$arm_fpu, which we expect to be neon -+ # when running this. -+ if (!arm_use_neon) { -+ configs -= [ "//build/config/compiler:compiler_arm_fpu" ] -+ cflags = [ "-mfpu=neon" ] -+ } -+ visibility = [ ":skia_opts" ] -+ configs -= [ "//build/config/compiler:chromium_code" ] -+ configs += [ -+ ":skia_config", -+ ":skia_library_config", -+ "//build/config/compiler:no_chromium_code", -+ ] ++if (current_cpu == "arm" && (arm_use_neon || arm_optionally_use_neon)) { ++ source_set("skia_opts_neon") { ++ sources = skia_opts.neon_sources ++ # Root build config sets -mfpu=$arm_fpu, which we expect to be neon ++ # when running this. ++ if (!arm_use_neon) { ++ configs -= [ "//build/config/compiler:compiler_arm_fpu" ] ++ cflags = [ "-mfpu=neon" ] + } ++ visibility = [ ":skia_opts" ] ++ configs -= [ "//build/config/compiler:chromium_code" ] ++ configs += [ ++ ":skia_config", ++ ":skia_library_config", ++ "//build/config/compiler:no_chromium_code", ++ ] + } - if (current_cpu == "arm64") { - source_set("skia_opts_crc32") { - sources = skia_opts.crc32_sources -@@ -624,14 +642,7 @@ ++} + if (current_cpu == "arm64") { + source_set("skia_opts_crc32") { + sources = skia_opts.crc32_sources +@@ -644,14 +662,7 @@ if (arm_version >= 7) { sources = skia_opts.armv7_sources if (arm_use_neon || arm_optionally_use_neon) { @@ -42,9 +42,9 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/skia/BUILD.gn q } } else { sources = skia_opts.none_sources -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/gn/opts.gni qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/gn/opts.gni ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/gn/opts.gni 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/gn/opts.gni 2017-06-12 12:20:30.277109309 +0200 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/gn/opts.gni qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/gn/opts.gni +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/gn/opts.gni 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/gn/opts.gni 2017-12-25 18:29:15.083480322 +0100 @@ -23,6 +23,7 @@ "$_src/opts/SkBitmapProcState_matrixProcs_neon.cpp", "$_src/opts/SkBlitMask_opts_arm_neon.cpp", @@ -61,10 +61,10 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski ] crc32 = [ "$_src/opts/SkOpts_crc32.cpp" ] -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp 2017-06-12 12:20:30.382107811 +0200 -@@ -19,7 +19,7 @@ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState.cpp 2017-12-25 18:29:22.449374588 +0100 +@@ -17,7 +17,7 @@ #include "SkImageEncoder.h" #include "SkResourceCache.h" @@ -72,9 +72,9 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski +#if !SK_ARM_NEON_IS_NONE // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; - extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); -@@ -280,7 +280,7 @@ - return false; + #endif +@@ -212,7 +212,7 @@ + index |= 4; } -#if !defined(SK_ARM_HAS_NEON) @@ -82,10 +82,10 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski static const SampleProc32 gSkBitmapProcStateSample32[] = { S32_opaque_D32_nofilter_DXDY, S32_alpha_D32_nofilter_DXDY, -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp 2017-06-12 12:20:30.448106869 +0200 -@@ -47,16 +47,16 @@ +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp 2017-12-25 18:34:09.229257992 +0100 +@@ -46,16 +46,16 @@ /////////////////////////////////////////////////////////////////////////////// // Compile neon code paths if needed @@ -102,52 +102,13 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski // Compile non-neon code path if needed -#if !defined(SK_ARM_HAS_NEON) +#if !SK_ARM_NEON_IS_ALWAYS - #define MAKENAME(suffix) ClampX_ClampY ## suffix - #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) - #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBlitter_RGB16.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBlitter_RGB16.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkBlitter_RGB16.cpp 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkBlitter_RGB16.cpp 2017-06-12 12:20:30.449106855 +0200 -@@ -20,7 +20,7 @@ - uint32_t expanded32, unsigned maskRB); - #endif - --#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) -+#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) - #include - extern void SkRGB16BlitterBlitV_neon(uint16_t* device, - int height, -@@ -381,7 +381,7 @@ - unsigned maskRB = mask.fRowBytes - width; - uint32_t expanded32 = fExpandedRaw16; - --#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) -+#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) - #define UNROLL 8 - do { - int w = width; -@@ -475,7 +475,7 @@ - unsigned scale5 = SkAlpha255To256(alpha) >> 3; - uint32_t src32 = fExpandedRaw16 * scale5; - scale5 = 32 - scale5; --#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) -+#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) - SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32); - #else - do { -@@ -654,7 +654,7 @@ - unsigned scale5 = SkAlpha255To256(alpha) * fScale >> (8 + 3); - uint32_t src32 = fExpandedRaw16 * scale5; - scale5 = 32 - scale5; --#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) -+#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) - SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32); - #else - do { -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp 2017-06-12 12:20:30.449106855 +0200 -@@ -73,6 +73,124 @@ + #define MAKENAME(suffix) ClampX_ClampY ## suffix + #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) + #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkCpu.cpp 2017-12-25 18:37:45.974144769 +0100 +@@ -74,6 +74,124 @@ return features; } @@ -269,23 +230,23 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski + return features; + } + - #elif defined(SK_CPU_ARM64) && \ - defined(SK_BUILD_FOR_ANDROID) && \ - !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp 2017-06-12 12:20:30.449106855 +0200 -@@ -99,6 +99,7 @@ + #elif defined(SK_CPU_ARM64) && __has_include() + #include + +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkOpts.cpp 2017-12-25 18:34:52.777632875 +0100 +@@ -95,6 +95,7 @@ + void Init_sse42(); void Init_avx(); - void Init_hsw(); void Init_crc32(); + void Init_neon(); static void init() { #if !defined(SK_BUILD_NO_OPTS) -@@ -109,6 +110,9 @@ +@@ -104,6 +105,9 @@ + if (SkCpu::Supports(SkCpu::SSE42)) { Init_sse42(); } if (SkCpu::Supports(SkCpu::AVX )) { Init_avx(); } - if (SkCpu::Supports(SkCpu::HSW )) { Init_hsw(); } + #elif defined(SK_CPU_ARM32) + if (SkCpu::Supports(SkCpu::NEON)) { Init_neon(); } @@ -293,9 +254,9 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski #elif defined(SK_CPU_ARM64) if (SkCpu::Supports(SkCpu::CRC32)) { Init_crc32(); } -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h 2017-06-12 12:20:30.450106841 +0200 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/core/SkUtilsArm.h 2017-12-25 18:34:52.777632875 +0100 @@ -8,12 +8,75 @@ #ifndef SkUtilsArm_DEFINED #define SkUtilsArm_DEFINED @@ -376,9 +337,9 @@ diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/ski #endif #endif // SkUtilsArm_DEFINED -diff -Nur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp 2017-06-12 12:20:30.450106841 +0200 +diff -Nur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-skia-neon/src/3rdparty/chromium/third_party/skia/src/opts/SkOpts_neon.cpp 2017-12-25 18:34:52.850631826 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Google Inc. diff --git a/qtwebengine-opensource-src-5.9.0-system-icu-utf.patch b/qtwebengine-everywhere-src-5.10.0-system-icu-utf.patch similarity index 51% rename from qtwebengine-opensource-src-5.9.0-system-icu-utf.patch rename to qtwebengine-everywhere-src-5.10.0-system-icu-utf.patch index 1c905e4..e645de8 100644 --- a/qtwebengine-opensource-src-5.9.0-system-icu-utf.patch +++ b/qtwebengine-everywhere-src-5.10.0-system-icu-utf.patch @@ -1,18 +1,18 @@ -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/BUILD.gn ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn 2017-06-08 10:52:51.565409865 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/BUILD.gn 2017-06-08 11:13:47.297983554 +0200 -@@ -834,8 +834,6 @@ +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn 2017-12-25 12:16:23.250517752 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/BUILD.gn 2017-12-25 12:26:21.502411527 +0100 +@@ -859,8 +859,6 @@ "third_party/dmg_fp/dmg_fp.h", "third_party/dmg_fp/dtoa_wrapper.cc", "third_party/dmg_fp/g_fmt.cc", - "third_party/icu/icu_utf.cc", - "third_party/icu/icu_utf.h", "third_party/superfasthash/superfasthash.c", - "threading/non_thread_safe.h", - "threading/non_thread_safe_impl.cc", -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/files/file_path.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/files/file_path.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/files/file_path.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/files/file_path.cc 2017-06-08 11:02:19.933803953 +0200 + "third_party/valgrind/memcheck.h", + "threading/platform_thread.h", +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/files/file_path.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/files/file_path.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/files/file_path.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/files/file_path.cc 2017-12-25 12:26:21.503411511 +0100 @@ -18,7 +18,7 @@ #if defined(OS_MACOSX) @@ -22,7 +22,7 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi #endif #if defined(OS_WIN) -@@ -1156,9 +1156,9 @@ +@@ -1163,9 +1163,9 @@ int* index) { int codepoint = 0; while (*index < length && codepoint == 0) { @@ -34,9 +34,9 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi DCHECK_GT(codepoint, 0); if (codepoint > 0) { // Check if there is a subtable for this upper byte. -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/json/json_parser.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/json/json_parser.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/json/json_parser.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/json/json_parser.cc 2017-06-08 11:05:52.045814002 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/json/json_parser.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/json/json_parser.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/json/json_parser.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/json/json_parser.cc 2017-12-25 12:29:56.210138445 +0100 @@ -16,7 +16,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversion_utils.h" @@ -46,9 +46,9 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi #include "base/values.h" namespace base { -@@ -630,21 +630,21 @@ - - while (CanConsume(1)) { +@@ -482,14 +482,14 @@ + // string character and the terminating closing quote. + while (CanConsume(2)) { int start_index = index_; - pos_ = start_pos_ + index_; // CBU8_NEXT is postcrement. - CBU8_NEXT(start_pos_, index_, length, next_char); @@ -62,17 +62,18 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi - CBU8_NEXT(start_pos_, start_index, length, next_char); + U8_NEXT(start_pos_, start_index, length, next_char); string.Convert(); - string.AppendString(kUnicodeReplacementString); - continue; + string.AppendString(kUnicodeReplacementString, + arraysize(kUnicodeReplacementString) - 1); +@@ -497,7 +497,7 @@ } if (next_char == '"') { - --index_; // Rewind by one because of CBU8_NEXT. + --index_; // Rewind by one because of U8_NEXT. - out->Swap(&string); + *out = std::move(string); return true; } -@@ -774,10 +774,10 @@ +@@ -633,10 +633,10 @@ // If this is a high surrogate, consume the next code unit to get the // low surrogate. @@ -85,7 +86,7 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi return false; // Make sure that the token has more characters to consume the -@@ -794,24 +794,24 @@ +@@ -653,20 +653,20 @@ NextNChars(3); @@ -107,15 +108,19 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi // Not a surrogate. - DCHECK(CBU16_IS_SINGLE(code_unit16_high)); + DCHECK(U16_IS_SINGLE(code_unit16_high)); - if (!IsValidCharacter(code_unit16_high)) - return false; + if (!IsValidCharacter(code_unit16_high)) { + if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { + return false; +@@ -675,7 +675,7 @@ + return true; + } - CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high); + U8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high); } - dest_string->append(code_unit8); -@@ -828,9 +828,9 @@ + dest_string->append(code_unit8, offset); +@@ -692,9 +692,9 @@ } else { char utf8_units[4] = { 0 }; int offset = 0; @@ -125,11 +130,11 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi - // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be + // U8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be // zero terminated at this point. |offset| contains the correct length. - dest->AppendString(std::string(utf8_units, offset)); + dest->AppendString(utf8_units, offset); } -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/json/string_escape.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/json/string_escape.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/json/string_escape.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/json/string_escape.cc 2017-06-08 11:02:19.934803939 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/json/string_escape.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/json/string_escape.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/json/string_escape.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/json/string_escape.cc 2017-12-25 12:36:34.186118210 +0100 @@ -14,7 +14,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversion_utils.h" @@ -139,9 +144,18 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi namespace base { -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/pattern.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/pattern.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/pattern.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/pattern.cc 2017-06-08 11:02:21.774778002 +0200 +@@ -92,7 +92,7 @@ + for (int32_t i = 0; i < length; ++i) { + uint32_t code_point; + if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point) || +- code_point == static_cast(CBU_SENTINEL) || ++ code_point == static_cast(U_SENTINEL) || + !IsValidCharacter(code_point)) { + code_point = kReplacementCodePoint; + did_replacement = true; +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/pattern.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/pattern.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/pattern.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/pattern.cc 2017-12-25 12:26:21.545410871 +0100 @@ -4,13 +4,13 @@ #include "base/strings/pattern.h" @@ -197,9 +211,9 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi *p += offset; return c; } -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_split.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_split.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_split.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_split.cc 2017-06-08 11:02:21.774778002 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_split.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_split.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_split.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_split.cc 2017-12-25 12:26:21.545410871 +0100 @@ -8,7 +8,7 @@ #include "base/logging.h" @@ -209,9 +223,9 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi namespace base { -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_util.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_util.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_util.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_util.cc 2017-06-08 11:02:21.775777988 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_util.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_util.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/string_util.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/string_util.cc 2017-12-25 12:26:21.546410856 +0100 @@ -25,7 +25,7 @@ #include "base/memory/singleton.h" #include "base/strings/utf_string_conversion_utils.h" @@ -221,7 +235,7 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi #include "build/build_config.h" namespace base { -@@ -357,19 +357,19 @@ +@@ -372,19 +372,19 @@ } DCHECK_LE(byte_size, static_cast(std::numeric_limits::max())); @@ -245,7 +259,7 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi if (!IsValidCharacter(code_point) || !IsValidCodepoint(code_point)) { char_index = prev - 1; -@@ -522,7 +522,7 @@ +@@ -537,7 +537,7 @@ while (char_index < src_len) { int32_t code_point; @@ -254,9 +268,9 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi if (!IsValidCharacter(code_point)) return false; } -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc 2017-06-08 11:02:21.775777988 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/base/strings/utf_string_conversion_utils.cc 2017-12-25 12:26:21.546410856 +0100 @@ -4,7 +4,7 @@ #include "base/strings/utf_string_conversion_utils.h" @@ -335,30 +349,81 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi } // Generalized Unicode converter ----------------------------------------------- -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-06-08 10:55:05.945934291 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-06-08 11:14:16.956570568 +0200 -@@ -472,7 +472,6 @@ +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/content/browser/devtools/devtools_io_context.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/content/browser/devtools/devtools_io_context.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/content/browser/devtools/devtools_io_context.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/content/browser/devtools/devtools_io_context.cc 2017-12-25 12:37:08.791629561 +0100 +@@ -10,7 +10,7 @@ + #include "base/strings/string_number_conversions.h" + #include "base/strings/string_util.h" + #include "base/task_scheduler/post_task.h" +-#include "base/third_party/icu/icu_utf.h" ++#include + #include "base/threading/thread_restrictions.h" + #include "content/public/browser/browser_thread.h" + +@@ -92,7 +92,7 @@ + } else { + // Provided client has requested sufficient large block, make their + // life easier by not truncating in the middle of a UTF-8 character. +- if (size_got > 6 && !CBU8_IS_SINGLE(buffer[size_got - 1])) { ++ if (size_got > 6 && !U8_IS_SINGLE(buffer[size_got - 1])) { + base::TruncateUTF8ToByteSize(buffer, size_got, &buffer); + size_got = buffer.size(); + } else { +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/net/cert/internal/parse_name.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/net/cert/internal/parse_name.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/net/cert/internal/parse_name.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/net/cert/internal/parse_name.cc 2017-12-25 12:34:58.610528544 +0100 +@@ -9,7 +9,7 @@ + #include "base/strings/utf_string_conversion_utils.h" + #include "base/strings/utf_string_conversions.h" + #include "base/sys_byteorder.h" +-#include "base/third_party/icu/icu_utf.h" ++#include + + #if !defined(OS_NACL) + #include "net/base/net_string_util.h" +@@ -38,7 +38,7 @@ + + // BMPString only supports codepoints in the Basic Multilingual Plane; + // surrogates are not allowed. +- if (CBU_IS_SURROGATE(c)) ++ if (U_IS_SURROGATE(c)) + return false; + } + return base::UTF16ToUTF8(in_16bit.data(), in_16bit.size(), out); +@@ -58,7 +58,7 @@ + for (const uint32_t c : in_32bit) { + // UniversalString is UCS-4 in big-endian order. + uint32_t codepoint = base::NetToHost32(c); +- if (!CBU_IS_UNICODE_CHAR(codepoint)) ++ if (!U_IS_UNICODE_CHAR(codepoint)) + return false; + + base::WriteUnicodeCharacter(codepoint, out); +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-12-25 12:20:43.585562853 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-12-25 12:41:57.071558915 +0100 +@@ -526,7 +526,6 @@ 'base/task_scheduler/task_traits.cc', 'base/third_party/dmg_fp/dtoa_wrapper.cc', 'base/third_party/dmg_fp/g_fmt.cc', - 'base/third_party/icu/icu_utf.cc', - 'base/threading/non_thread_safe_impl.cc', 'base/threading/post_task_and_reply_impl.cc', + 'base/threading/sequence_local_storage_map.cc', 'base/threading/sequenced_task_runner_handle.cc', -@@ -574,7 +573,7 @@ - } - - if is_linux: -- libs.extend(['-lrt', '-lnspr4']) -+ libs.extend(['-lrt', '-lnspr4', '-licuuc']) - ldflags.extend(['-pthread']) - - static_libraries['xdg_user_dirs'] = { -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/tools/gn/BUILD.gn ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-06-10 22:18:26.863178931 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-06-10 22:18:30.168114045 +0200 -@@ -277,6 +277,7 @@ +@@ -679,7 +678,7 @@ + 'base/allocator/allocator_shim.cc', + 'base/allocator/allocator_shim_default_dispatch_to_glibc.cc', + ]) +- libs.extend(['-lrt', '-lnspr4']) ++ libs.extend(['-lrt', '-lnspr4', '-licuuc']) + static_libraries['libevent']['include_dirs'].extend([ + os.path.join(SRC_ROOT, 'base', 'third_party', 'libevent', 'linux') + ]) +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/tools/gn/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-12-25 12:16:48.744131902 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-12-25 12:26:21.547410841 +0100 +@@ -278,6 +278,7 @@ libs = [ "nspr4", @@ -366,9 +431,20 @@ diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromi ] } -diff -ur qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc ---- qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-icu-utf/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc 2017-06-08 11:02:21.776777974 +0200 +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/ui/base/ime/input_method_chromeos.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/ui/base/ime/input_method_chromeos.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/ui/base/ime/input_method_chromeos.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/ui/base/ime/input_method_chromeos.cc 2017-12-25 12:40:50.356500963 +0100 +@@ -17,7 +17,6 @@ + #include "base/logging.h" + #include "base/strings/string_util.h" + #include "base/strings/utf_string_conversions.h" +-#include "base/third_party/icu/icu_utf.h" + #include "chromeos/system/devicemode.h" + #include "ui/base/ime/chromeos/ime_keyboard.h" + #include "ui/base/ime/chromeos/input_method_manager.h" +diff -ur qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc +--- qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-icu-utf/src/3rdparty/chromium/ui/gfx/utf16_indexing.cc 2017-12-25 12:26:21.547410841 +0100 @@ -5,13 +5,13 @@ #include "ui/gfx/utf16_indexing.h" diff --git a/qtwebengine-everywhere-src-5.10.0-system-nspr-prtime.patch b/qtwebengine-everywhere-src-5.10.0-system-nspr-prtime.patch new file mode 100644 index 0000000..ec4dce8 --- /dev/null +++ b/qtwebengine-everywhere-src-5.10.0-system-nspr-prtime.patch @@ -0,0 +1,80 @@ +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/BUILD.gn qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn 2017-12-25 12:16:23.250517752 +0100 +@@ -53,6 +53,9 @@ + "-Wno-char-subscripts", + ] + } ++ ldflags = [ ++ "-lnspr4", ++ ] + } + + config("base_implementation") { +@@ -858,8 +861,6 @@ + "third_party/dmg_fp/g_fmt.cc", + "third_party/icu/icu_utf.cc", + "third_party/icu/icu_utf.h", +- "third_party/nspr/prtime.cc", +- "third_party/nspr/prtime.h", + "third_party/superfasthash/superfasthash.c", + "third_party/valgrind/memcheck.h", + "threading/platform_thread.h", +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/time/pr_time_unittest.cc qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/time/pr_time_unittest.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/time/pr_time_unittest.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/time/pr_time_unittest.cc 2017-12-25 12:16:23.250517752 +0100 +@@ -7,7 +7,7 @@ + + #include "base/compiler_specific.h" + #include "base/macros.h" +-#include "base/third_party/nspr/prtime.h" ++#include + #include "base/time/time.h" + #include "build/build_config.h" + #include "testing/gtest/include/gtest/gtest.h" +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/time/time.cc qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/time/time.cc +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/base/time/time.cc 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/base/time/time.cc 2017-12-25 12:16:48.710132416 +0100 +@@ -14,7 +14,7 @@ + #include "base/logging.h" + #include "base/macros.h" + #include "base/strings/stringprintf.h" +-#include "base/third_party/nspr/prtime.h" ++#include + #include "build/build_config.h" + + namespace base { +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-12-25 12:20:43.585562853 +0100 +@@ -527,7 +527,6 @@ + 'base/third_party/dmg_fp/dtoa_wrapper.cc', + 'base/third_party/dmg_fp/g_fmt.cc', + 'base/third_party/icu/icu_utf.cc', +- 'base/third_party/nspr/prtime.cc', + 'base/threading/post_task_and_reply_impl.cc', + 'base/threading/sequence_local_storage_map.cc', + 'base/threading/sequenced_task_runner_handle.cc', +@@ -680,7 +679,7 @@ + 'base/allocator/allocator_shim.cc', + 'base/allocator/allocator_shim_default_dispatch_to_glibc.cc', + ]) +- libs.extend(['-lrt']) ++ libs.extend(['-lrt', '-lnspr4']) + static_libraries['libevent']['include_dirs'].extend([ + os.path.join(SRC_ROOT, 'base', 'third_party', 'libevent', 'linux') + ]) +diff -ur qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/tools/gn/BUILD.gn qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn +--- qtwebengine-everywhere-src-5.10.0/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-11-28 14:06:53.000000000 +0100 ++++ qtwebengine-everywhere-src-5.10.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-12-25 12:16:48.744131902 +0100 +@@ -275,6 +275,10 @@ + "//build/config:exe_and_shlib_deps", + "//build/win:default_exe_manifest", + ] ++ ++ libs = [ ++ "nspr4", ++ ] + } + + test("gn_unittests") { diff --git a/qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose.patch b/qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose.patch deleted file mode 100644 index 87b5beb..0000000 --- a/qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -ur qtwebengine-opensource-src-5.9.0/src/buildtools/gn.pro qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose/src/buildtools/gn.pro ---- qtwebengine-opensource-src-5.9.0/src/buildtools/gn.pro 2017-05-19 06:22:04.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-gn-bootstrap-verbose/src/buildtools/gn.pro 2017-06-10 15:24:55.426814326 +0200 -@@ -20,7 +20,7 @@ - src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT") - gn_bootstrap = $$system_path($$absolute_path(chromium/tools/gn/bootstrap/bootstrap.py, $$src_3rd_party_dir)) - gn_args = $$system_quote($$gn_args) -- gn_configure = $$system_quote($$gn_bootstrap) --shadow --gn-gen-args=$$gn_args $$ninja_path -+ gn_configure = $$system_quote($$gn_bootstrap) --verbose --shadow --gn-gen-args=$$gn_args $$ninja_path - !system("cd $$system_quote($$system_path($$dirname(out))) && $$pythonPathForSystem() $$gn_configure") { - error("GN build error!") - } diff --git a/qtwebengine-opensource-src-5.9.0-system-nspr-prtime.patch b/qtwebengine-opensource-src-5.9.0-system-nspr-prtime.patch deleted file mode 100644 index ab14cb9..0000000 --- a/qtwebengine-opensource-src-5.9.0-system-nspr-prtime.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff -ur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/BUILD.gn qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/BUILD.gn 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/BUILD.gn 2017-06-08 10:52:51.565409865 +0200 -@@ -49,6 +49,9 @@ - "-Wno-char-subscripts", - ] - } -+ ldflags = [ -+ "-lnspr4", -+ ] - } - - config("base_implementation") { -@@ -833,8 +836,6 @@ - "third_party/dmg_fp/g_fmt.cc", - "third_party/icu/icu_utf.cc", - "third_party/icu/icu_utf.h", -- "third_party/nspr/prtime.cc", -- "third_party/nspr/prtime.h", - "third_party/superfasthash/superfasthash.c", - "threading/non_thread_safe.h", - "threading/non_thread_safe_impl.cc", -diff -ur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/time/pr_time_unittest.cc qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/time/pr_time_unittest.cc ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/time/pr_time_unittest.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/time/pr_time_unittest.cc 2017-06-08 10:58:06.743413247 +0200 -@@ -7,7 +7,7 @@ - - #include "base/compiler_specific.h" - #include "base/macros.h" --#include "base/third_party/nspr/prtime.h" -+#include - #include "base/time/time.h" - #include "build/build_config.h" - #include "testing/gtest/include/gtest/gtest.h" -diff -ur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/time/time.cc qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/time/time.cc ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/base/time/time.cc 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/base/time/time.cc 2017-06-08 10:58:09.557373071 +0200 -@@ -14,7 +14,7 @@ - #include "base/logging.h" - #include "base/macros.h" - #include "base/strings/stringprintf.h" --#include "base/third_party/nspr/prtime.h" -+#include - #include "build/build_config.h" - - namespace base { -diff -ur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/bootstrap/bootstrap.py 2017-06-08 10:55:05.945934291 +0200 -@@ -473,7 +473,6 @@ - 'base/third_party/dmg_fp/dtoa_wrapper.cc', - 'base/third_party/dmg_fp/g_fmt.cc', - 'base/third_party/icu/icu_utf.cc', -- 'base/third_party/nspr/prtime.cc', - 'base/threading/non_thread_safe_impl.cc', - 'base/threading/post_task_and_reply_impl.cc', - 'base/threading/sequenced_task_runner_handle.cc', -@@ -575,7 +574,7 @@ - } - - if is_linux: -- libs.extend(['-lrt']) -+ libs.extend(['-lrt', '-lnspr4']) - ldflags.extend(['-pthread']) - - static_libraries['xdg_user_dirs'] = { -diff -ur qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/tools/gn/BUILD.gn qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn ---- qtwebengine-opensource-src-5.9.0/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-05-18 16:51:44.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.0-system-nspr-prtime/src/3rdparty/chromium/tools/gn/BUILD.gn 2017-06-10 22:18:26.863178931 +0200 -@@ -274,6 +274,10 @@ - "//build/config/sanitizers:deps", - "//build/win:default_exe_manifest", - ] -+ -+ libs = [ -+ "nspr4", -+ ] - } - - test("gn_unittests") { diff --git a/qtwebengine-opensource-src-5.9.1-no-sse2.patch b/qtwebengine-opensource-src-5.9.1-no-sse2.patch deleted file mode 100644 index 086349a..0000000 --- a/qtwebengine-opensource-src-5.9.1-no-sse2.patch +++ /dev/null @@ -1,3132 +0,0 @@ -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webengine/customdialogs/customdialogs.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/customdialogs/customdialogs.pro ---- qtwebengine-opensource-src-5.9.1/examples/webengine/customdialogs/customdialogs.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/customdialogs/customdialogs.pro 2017-07-01 03:36:34.349977335 +0200 -@@ -1,5 +1,7 @@ - QT += webengine - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - server.h - -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webengine/minimal/minimal.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/minimal/minimal.pro ---- qtwebengine-opensource-src-5.9.1/examples/webengine/minimal/minimal.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/minimal/minimal.pro 2017-07-01 03:36:34.439976022 +0200 -@@ -2,6 +2,8 @@ - - QT += webengine - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - SOURCES += main.cpp - - RESOURCES += qml.qrc -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webengine/quicknanobrowser/quicknanobrowser.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/quicknanobrowser/quicknanobrowser.pro ---- qtwebengine-opensource-src-5.9.1/examples/webengine/quicknanobrowser/quicknanobrowser.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/quicknanobrowser/quicknanobrowser.pro 2017-07-01 03:36:34.440976008 +0200 -@@ -20,5 +20,7 @@ - QT += widgets # QApplication is required to get native styling with QtQuickControls - } - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - target.path = $$[QT_INSTALL_EXAMPLES]/webengine/quicknanobrowser - INSTALLS += target -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webengine/recipebrowser/recipebrowser.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/recipebrowser/recipebrowser.pro ---- qtwebengine-opensource-src-5.9.1/examples/webengine/recipebrowser/recipebrowser.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webengine/recipebrowser/recipebrowser.pro 2017-07-01 03:36:34.497975177 +0200 -@@ -2,6 +2,8 @@ - - QT += quick qml quickcontrols2 webengine - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - cross_compile { - posix|qnx|linux: DEFINES += QTWEBENGINE_RECIPE_BROWSER_EMBEDDED - } -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/contentmanipulation/contentmanipulation.pro 2017-07-01 03:36:34.556974316 +0200 -@@ -1,5 +1,7 @@ - QT += webenginewidgets - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS = mainwindow.h - SOURCES = main.cpp \ - mainwindow.cpp -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro 2017-07-01 03:36:34.614973470 +0200 -@@ -3,6 +3,8 @@ - TEMPLATE = app - CONFIG += c++11 - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - SOURCES += \ - main.cpp\ - mainwindow.cpp -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/demobrowser/demobrowser.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/demobrowser/demobrowser.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/demobrowser/demobrowser.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/demobrowser/demobrowser.pro 2017-07-01 03:36:34.673972609 +0200 -@@ -3,6 +3,8 @@ - QT += webenginewidgets network widgets printsupport - CONFIG += c++11 - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - qtHaveModule(uitools):!embedded: QT += uitools - else: DEFINES += QT_NO_UITOOLS - -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/html2pdf/html2pdf.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/html2pdf/html2pdf.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/html2pdf/html2pdf.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/html2pdf/html2pdf.pro 2017-07-01 03:39:53.946070116 +0200 -@@ -2,6 +2,8 @@ - - QT += webenginewidgets - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - SOURCES += html2pdf.cpp - - target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/html2pdf -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/maps/maps.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/maps/maps.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/maps/maps.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/maps/maps.pro 2017-07-01 03:40:09.747841163 +0200 -@@ -2,6 +2,8 @@ - - QT += webenginewidgets - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - mainwindow.h - -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/markdowneditor/markdowneditor.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/markdowneditor/markdowneditor.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/markdowneditor/markdowneditor.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/markdowneditor/markdowneditor.pro 2017-07-01 03:36:34.731971763 +0200 -@@ -3,6 +3,8 @@ - QT += webenginewidgets webchannel - CONFIG += c++11 - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - mainwindow.h \ - previewpage.h \ -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/minimal/minimal.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/minimal/minimal.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/minimal/minimal.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/minimal/minimal.pro 2017-07-01 03:36:34.789970917 +0200 -@@ -2,6 +2,8 @@ - - QT += webenginewidgets - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - SOURCES += main.cpp - - target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/minimal -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/simplebrowser/simplebrowser.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/simplebrowser/simplebrowser.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/simplebrowser/simplebrowser.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/simplebrowser/simplebrowser.pro 2017-07-01 03:36:34.850970027 +0200 -@@ -3,6 +3,8 @@ - QT += webenginewidgets - CONFIG += c++11 - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - browser.h \ - browserwindow.h \ -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/spellchecker/spellchecker.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/spellchecker/spellchecker.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/spellchecker/spellchecker.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/spellchecker/spellchecker.pro 2017-07-01 03:36:34.851970013 +0200 -@@ -7,6 +7,8 @@ - error("Spellcheck example can not be built when using native OS dictionaries.") - } - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - webview.h - -diff -Nur qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/videoplayer/videoplayer.pro qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/videoplayer/videoplayer.pro ---- qtwebengine-opensource-src-5.9.1/examples/webenginewidgets/videoplayer/videoplayer.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/examples/webenginewidgets/videoplayer/videoplayer.pro 2017-07-01 03:36:34.851970013 +0200 -@@ -2,6 +2,8 @@ - - QT += webenginewidgets - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../../../src/core/Release -+ - HEADERS += \ - mainwindow.h \ - fullscreenwindow.h \ -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/config/compiler/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/config/compiler/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/config/compiler/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/config/compiler/BUILD.gn 2017-07-01 03:36:34.851970013 +0200 -@@ -533,13 +533,6 @@ - } else if (current_cpu == "x86") { - cflags += [ "-m32" ] - ldflags += [ "-m32" ] -- if (!is_nacl) { -- cflags += [ -- "-msse2", -- "-mfpmath=sse", -- "-mmmx", -- ] -- } - } else if (current_cpu == "arm") { - if (is_clang && !is_android && !is_nacl) { - cflags += [ "--target=arm-linux-gnueabihf" ] -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/config/v8_target_cpu.gni qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/config/v8_target_cpu.gni ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/config/v8_target_cpu.gni 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/config/v8_target_cpu.gni 2017-07-01 03:36:34.928968889 +0200 -@@ -59,3 +59,11 @@ - # It should never be explicitly set by the user. - v8_current_cpu = v8_target_cpu - } -+ -+if (v8_current_cpu == "x86") { -+ # If we are not building for the x86_sse2 toolchain, we actually want to build -+ # the "x87" backend instead. -+ if (current_toolchain != "//build/toolchain/linux:x86_sse2") { -+ v8_current_cpu = "x87" -+ } -+} -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/toolchain/gcc_toolchain.gni 2017-07-01 03:36:34.929968875 +0200 -@@ -213,6 +213,10 @@ - extra_ldflags = "" - } - -+ if (defined(invoker.shlib_subdir)) { -+ shlib_subdir = invoker.shlib_subdir -+ } -+ - # These library switches can apply to all tools below. - lib_switch = "-l" - lib_dir_switch = "-L" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/build/toolchain/linux/BUILD.gn 2017-07-01 03:36:34.929968875 +0200 -@@ -96,6 +96,26 @@ - } - } - -+gcc_toolchain("x86_sse2") { -+ cc = "gcc" -+ cxx = "g++" -+ -+ readelf = "readelf" -+ nm = "nm" -+ ar = "ar" -+ ld = cxx -+ -+ extra_cflags = "-msse2 -mfpmath=sse" -+ extra_cxxflags = "-msse2 -mfpmath=sse" -+ shlib_subdir = "lib/sse2" -+ -+ toolchain_args = { -+ current_cpu = "x86" -+ current_os = "linux" -+ is_clang = false -+ } -+} -+ - clang_toolchain("clang_x64") { - toolchain_args = { - current_cpu = "x64" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/cc/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/cc/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/cc/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/cc/BUILD.gn 2017-07-01 03:36:34.929968875 +0200 -@@ -567,13 +567,6 @@ - "trees/tree_synchronizer.h", - ] - -- if (current_cpu == "x86" || current_cpu == "x64") { -- sources += [ -- "raster/texture_compressor_etc1_sse.cc", -- "raster/texture_compressor_etc1_sse.h", -- ] -- } -- - configs += [ "//build/config:precompiled_headers" ] - - public_deps = [ -@@ -583,6 +576,7 @@ - deps = [ - "//base", - "//base/third_party/dynamic_annotations", -+ "//cc:cc_opts", - "//cc/proto", - "//cc/surfaces:surface_id", - "//gpu", -@@ -612,6 +606,36 @@ - } - } - -+source_set("cc_opts") { -+ public_deps = [ -+ "//cc:cc_opts_sse", -+ ] -+} -+ -+source_set("cc_opts_sse") { -+ if (current_cpu == "x86" || current_cpu == "x64") { -+ deps = [ -+ "//base", -+ ] -+ -+ defines = [ "CC_IMPLEMENTATION=1" ] -+ -+ if (!is_debug && (is_win || is_android)) { -+ configs -= [ "//build/config/compiler:optimize" ] -+ configs += [ "//build/config/compiler:optimize_max" ] -+ } -+ -+ sources = [ -+ "raster/texture_compressor.h", -+ "raster/texture_compressor_etc1.h", -+ "raster/texture_compressor_etc1_sse.cc", -+ "raster/texture_compressor_etc1_sse.h", -+ ] -+ -+ cflags = [ "-msse2" ] -+ } -+} -+ - static_library("test_support") { - testonly = true - sources = [ -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/content/renderer/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/content/renderer/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/content/renderer/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/content/renderer/BUILD.gn 2017-07-01 03:36:34.998967868 +0200 -@@ -468,6 +468,13 @@ - "//ui/surface", - "//v8", - ] -+ -+ if (current_cpu == "x86") { -+ deps += [ -+ "//v8(//build/toolchain/linux:x86_sse2)", -+ ] -+ } -+ - allow_circular_includes_from = [] - - if (use_aura && !use_qt) { -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/BUILD.gn 2017-07-01 03:36:35.073966774 +0200 -@@ -336,13 +336,13 @@ - } - - if (current_cpu == "x86" || current_cpu == "x64") { -- sources += [ -- "simd/convert_rgb_to_yuv_sse2.cc", -- "simd/convert_rgb_to_yuv_ssse3.cc", -- "simd/convert_yuv_to_rgb_x86.cc", -- "simd/filter_yuv_sse2.cc", -+ sources += [ "simd/convert_yuv_to_rgb_x86.cc" ] -+ deps += [ -+ ":media_yasm", -+ ":media_mmx", -+ ":media_sse", -+ ":media_sse2", - ] -- deps += [ ":media_yasm" ] - } - - if (is_linux || is_win) { -@@ -539,10 +539,47 @@ - } - - if (current_cpu == "x86" || current_cpu == "x64") { -+ source_set("media_mmx") { -+ sources = [ "simd/filter_yuv_mmx.cc" ] -+ configs += [ "//media:media_config" ] -+ if (!is_win) { -+ cflags = [ "-mmmx" ] -+ } -+ } -+ -+ source_set("media_sse") { -+ sources = [ -+ "simd/sinc_resampler_sse.cc", -+ ] -+ configs += [ -+ "//media:media_config", -+ "//media:media_implementation", -+ ] -+ if (!is_win) { -+ cflags = [ "-msse" ] -+ } -+ } -+ -+ source_set("media_sse2") { -+ sources = [ -+ "simd/convert_rgb_to_yuv_sse2.cc", -+ "simd/convert_rgb_to_yuv_ssse3.cc", -+ "simd/filter_yuv_sse2.cc", -+ ] -+ configs += [ -+ "//media:media_config", -+ "//media:media_implementation", -+ ] -+ if (!is_win) { -+ cflags = [ "-msse2" ] -+ } -+ } -+ - import("//third_party/yasm/yasm_assemble.gni") - yasm_assemble("media_yasm") { - sources = [ - "simd/convert_rgb_to_yuv_ssse3.asm", -+ "simd/convert_yuv_to_rgb_mmx.asm", - "simd/convert_yuv_to_rgb_sse.asm", - "simd/convert_yuva_to_argb_mmx.asm", - "simd/empty_register_state_mmx.asm", -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/media.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/media.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/media.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/media.cc 2017-07-01 03:36:35.131965928 +0200 -@@ -10,6 +10,8 @@ - #include "base/metrics/field_trial.h" - #include "base/trace_event/trace_event.h" - #include "media/base/media_switches.h" -+#include "media/base/sinc_resampler.h" -+#include "media/base/vector_math.h" - #include "media/base/yuv_convert.h" - - #if defined(OS_ANDROID) -@@ -40,6 +42,8 @@ - TRACE_EVENT_WARMUP_CATEGORY("media"); - - // Perform initialization of libraries which require runtime CPU detection. -+ vector_math::Initialize(); -+ SincResampler::InitializeCPUSpecificFeatures(); - InitializeCPUSpecificYUVConversions(); - - #if !defined(MEDIA_DISABLE_FFMPEG) -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb.h 2017-07-01 03:36:35.131965928 +0200 -@@ -65,6 +65,17 @@ - int rgbstride, - YUVType yuv_type); - -+MEDIA_EXPORT void ConvertYUVToRGB32_MMX(const uint8_t* yplane, -+ const uint8_t* uplane, -+ const uint8_t* vplane, -+ uint8_t* rgbframe, -+ int width, -+ int height, -+ int ystride, -+ int uvstride, -+ int rgbstride, -+ YUVType yuv_type); -+ - MEDIA_EXPORT void ConvertYUVAToARGB_MMX(const uint8_t* yplane, - const uint8_t* uplane, - const uint8_t* vplane, -@@ -124,6 +135,13 @@ - ptrdiff_t width, - const int16_t* convert_table); - -+MEDIA_EXPORT void ConvertYUVToRGB32Row_MMX(const uint8_t* yplane, -+ const uint8_t* uplane, -+ const uint8_t* vplane, -+ uint8_t* rgbframe, -+ ptrdiff_t width, -+ const int16_t* convert_table); -+ - MEDIA_EXPORT void ConvertYUVToRGB32Row_SSE(const uint8_t* yplane, - const uint8_t* uplane, - const uint8_t* vplane, -@@ -131,6 +149,14 @@ - ptrdiff_t width, - const int16_t* convert_table); - -+MEDIA_EXPORT void ScaleYUVToRGB32Row_MMX(const uint8_t* y_buf, -+ const uint8_t* u_buf, -+ const uint8_t* v_buf, -+ uint8_t* rgb_buf, -+ ptrdiff_t width, -+ ptrdiff_t source_dx, -+ const int16_t* convert_table); -+ - MEDIA_EXPORT void ScaleYUVToRGB32Row_SSE(const uint8_t* y_buf, - const uint8_t* u_buf, - const uint8_t* v_buf, -@@ -147,6 +173,14 @@ - ptrdiff_t source_dx, - const int16_t* convert_table); - -+MEDIA_EXPORT void LinearScaleYUVToRGB32Row_MMX(const uint8_t* y_buf, -+ const uint8_t* u_buf, -+ const uint8_t* v_buf, -+ uint8_t* rgb_buf, -+ ptrdiff_t width, -+ ptrdiff_t source_dx, -+ const int16_t* convert_table); -+ - MEDIA_EXPORT void LinearScaleYUVToRGB32Row_SSE(const uint8_t* y_buf, - const uint8_t* u_buf, - const uint8_t* v_buf, -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_mmx.asm qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_mmx.asm ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_mmx.asm 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_mmx.asm 2017-07-01 03:36:35.132965913 +0200 -@@ -0,0 +1,23 @@ -+; Copyright (c) 2011 The Chromium Authors. All rights reserved. -+; Use of this source code is governed by a BSD-style license that can be -+; found in the LICENSE file. -+ -+%include "third_party/x86inc/x86inc.asm" -+ -+; -+; This file uses MMX instructions. -+; -+ SECTION_TEXT -+ CPU MMX -+ -+; Use movq to save the output. -+%define MOVQ movq -+ -+; extern "C" void ConvertYUVToRGB32Row_MMX(const uint8* y_buf, -+; const uint8* u_buf, -+; const uint8* v_buf, -+; uint8* rgb_buf, -+; ptrdiff_t width, -+; const int16* convert_table); -+%define SYMBOL ConvertYUVToRGB32Row_MMX -+%include "convert_yuv_to_rgb_mmx.inc" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_x86.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_x86.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_x86.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/convert_yuv_to_rgb_x86.cc 2017-07-01 03:36:35.132965913 +0200 -@@ -47,6 +47,34 @@ - EmptyRegisterState(); - } - -+void ConvertYUVToRGB32_MMX(const uint8_t* yplane, -+ const uint8_t* uplane, -+ const uint8_t* vplane, -+ uint8_t* rgbframe, -+ int width, -+ int height, -+ int ystride, -+ int uvstride, -+ int rgbstride, -+ YUVType yuv_type) { -+ unsigned int y_shift = GetVerticalShift(yuv_type); -+ for (int y = 0; y < height; ++y) { -+ uint8_t* rgb_row = rgbframe + y * rgbstride; -+ const uint8_t* y_ptr = yplane + y * ystride; -+ const uint8_t* u_ptr = uplane + (y >> y_shift) * uvstride; -+ const uint8_t* v_ptr = vplane + (y >> y_shift) * uvstride; -+ -+ ConvertYUVToRGB32Row_MMX(y_ptr, -+ u_ptr, -+ v_ptr, -+ rgb_row, -+ width, -+ GetLookupTable(yuv_type)); -+ } -+ -+ EmptyRegisterState(); -+} -+ - void ConvertYUVToRGB32_SSE(const uint8_t* yplane, - const uint8_t* uplane, - const uint8_t* vplane, -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/filter_yuv.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/filter_yuv.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/filter_yuv.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/filter_yuv.h 2017-07-01 03:36:35.132965913 +0200 -@@ -20,6 +20,12 @@ - int source_width, - uint8_t source_y_fraction); - -+MEDIA_EXPORT void FilterYUVRows_MMX(uint8_t* ybuf, -+ const uint8_t* y0_ptr, -+ const uint8_t* y1_ptr, -+ int source_width, -+ uint8_t source_y_fraction); -+ - MEDIA_EXPORT void FilterYUVRows_SSE2(uint8_t* ybuf, - const uint8_t* y0_ptr, - const uint8_t* y1_ptr, -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/filter_yuv_mmx.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/filter_yuv_mmx.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/filter_yuv_mmx.cc 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/filter_yuv_mmx.cc 2017-07-01 03:36:35.132965913 +0200 -@@ -0,0 +1,79 @@ -+// Copyright (c) 2011 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#if defined(_MSC_VER) -+#include -+#else -+#include -+#endif -+ -+#include "build/build_config.h" -+#include "media/base/simd/filter_yuv.h" -+ -+namespace media { -+ -+#if defined(COMPILER_MSVC) -+// Warning 4799 is about calling emms before the function exits. -+// We calls emms in a frame level so suppress this warning. -+#pragma warning(push) -+#pragma warning(disable: 4799) -+#endif -+ -+void FilterYUVRows_MMX(uint8_t* dest, -+ const uint8_t* src0, -+ const uint8_t* src1, -+ int width, -+ uint8_t fraction) { -+ int pixel = 0; -+ -+ // Process the unaligned bytes first. -+ int unaligned_width = -+ (8 - (reinterpret_cast(dest) & 7)) & 7; -+ while (pixel < width && pixel < unaligned_width) { -+ dest[pixel] = (src0[pixel] * (256 - fraction) + -+ src1[pixel] * fraction) >> 8; -+ ++pixel; -+ } -+ -+ __m64 zero = _mm_setzero_si64(); -+ __m64 src1_fraction = _mm_set1_pi16(fraction); -+ __m64 src0_fraction = _mm_set1_pi16(256 - fraction); -+ const __m64* src0_64 = reinterpret_cast(src0 + pixel); -+ const __m64* src1_64 = reinterpret_cast(src1 + pixel); -+ __m64* dest64 = reinterpret_cast<__m64*>(dest + pixel); -+ __m64* end64 = reinterpret_cast<__m64*>( -+ reinterpret_cast(dest + width) & ~7); -+ -+ while (dest64 < end64) { -+ __m64 src0 = *src0_64++; -+ __m64 src1 = *src1_64++; -+ __m64 src2 = _mm_unpackhi_pi8(src0, zero); -+ __m64 src3 = _mm_unpackhi_pi8(src1, zero); -+ src0 = _mm_unpacklo_pi8(src0, zero); -+ src1 = _mm_unpacklo_pi8(src1, zero); -+ src0 = _mm_mullo_pi16(src0, src0_fraction); -+ src1 = _mm_mullo_pi16(src1, src1_fraction); -+ src2 = _mm_mullo_pi16(src2, src0_fraction); -+ src3 = _mm_mullo_pi16(src3, src1_fraction); -+ src0 = _mm_add_pi16(src0, src1); -+ src2 = _mm_add_pi16(src2, src3); -+ src0 = _mm_srli_pi16(src0, 8); -+ src2 = _mm_srli_pi16(src2, 8); -+ src0 = _mm_packs_pu16(src0, src2); -+ *dest64++ = src0; -+ pixel += 8; -+ } -+ -+ while (pixel < width) { -+ dest[pixel] = (src0[pixel] * (256 - fraction) + -+ src1[pixel] * fraction) >> 8; -+ ++pixel; -+ } -+} -+ -+#if defined(COMPILER_MSVC) -+#pragma warning(pop) -+#endif -+ -+} // namespace media -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/sinc_resampler_sse.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/sinc_resampler_sse.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/sinc_resampler_sse.cc 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/sinc_resampler_sse.cc 2017-07-01 03:36:35.133965899 +0200 -@@ -0,0 +1,50 @@ -+// Copyright 2013 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#include "media/base/sinc_resampler.h" -+ -+#include -+ -+namespace media { -+ -+float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, -+ const float* k2, -+ double kernel_interpolation_factor) { -+ __m128 m_input; -+ __m128 m_sums1 = _mm_setzero_ps(); -+ __m128 m_sums2 = _mm_setzero_ps(); -+ -+ // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling -+ // these loops hurt performance in local testing. -+ if (reinterpret_cast(input_ptr) & 0x0F) { -+ for (int i = 0; i < kKernelSize; i += 4) { -+ m_input = _mm_loadu_ps(input_ptr + i); -+ m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); -+ m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); -+ } -+ } else { -+ for (int i = 0; i < kKernelSize; i += 4) { -+ m_input = _mm_load_ps(input_ptr + i); -+ m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); -+ m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); -+ } -+ } -+ -+ // Linearly interpolate the two "convolutions". -+ m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1( -+ static_cast(1.0 - kernel_interpolation_factor))); -+ m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1( -+ static_cast(kernel_interpolation_factor))); -+ m_sums1 = _mm_add_ps(m_sums1, m_sums2); -+ -+ // Sum components together. -+ float result; -+ m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); -+ _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps( -+ m_sums2, m_sums2, 1))); -+ -+ return result; -+} -+ -+} // namespace media -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/vector_math_sse.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/vector_math_sse.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/simd/vector_math_sse.cc 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/simd/vector_math_sse.cc 2017-07-01 03:36:35.133965899 +0200 -@@ -0,0 +1,118 @@ -+// Copyright 2013 The Chromium Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style license that can be -+// found in the LICENSE file. -+ -+#include "media/base/vector_math_testing.h" -+ -+#include -+ -+#include // NOLINT -+ -+namespace media { -+namespace vector_math { -+ -+void FMUL_SSE(const float src[], float scale, int len, float dest[]) { -+ const int rem = len % 4; -+ const int last_index = len - rem; -+ __m128 m_scale = _mm_set_ps1(scale); -+ for (int i = 0; i < last_index; i += 4) -+ _mm_store_ps(dest + i, _mm_mul_ps(_mm_load_ps(src + i), m_scale)); -+ -+ // Handle any remaining values that wouldn't fit in an SSE pass. -+ for (int i = last_index; i < len; ++i) -+ dest[i] = src[i] * scale; -+} -+ -+void FMAC_SSE(const float src[], float scale, int len, float dest[]) { -+ const int rem = len % 4; -+ const int last_index = len - rem; -+ __m128 m_scale = _mm_set_ps1(scale); -+ for (int i = 0; i < last_index; i += 4) { -+ _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i), -+ _mm_mul_ps(_mm_load_ps(src + i), m_scale))); -+ } -+ -+ // Handle any remaining values that wouldn't fit in an SSE pass. -+ for (int i = last_index; i < len; ++i) -+ dest[i] += src[i] * scale; -+} -+ -+// Convenience macro to extract float 0 through 3 from the vector |a|. This is -+// needed because compilers other than clang don't support access via -+// operator[](). -+#define EXTRACT_FLOAT(a, i) \ -+ (i == 0 ? \ -+ _mm_cvtss_f32(a) : \ -+ _mm_cvtss_f32(_mm_shuffle_ps(a, a, i))) -+ -+std::pair EWMAAndMaxPower_SSE( -+ float initial_value, const float src[], int len, float smoothing_factor) { -+ // When the recurrence is unrolled, we see that we can split it into 4 -+ // separate lanes of evaluation: -+ // -+ // y[n] = a(S[n]^2) + (1-a)(y[n-1]) -+ // = a(S[n]^2) + (1-a)^1(aS[n-1]^2) + (1-a)^2(aS[n-2]^2) + ... -+ // = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) -+ // -+ // where z[n] = a(S[n]^2) + (1-a)^4(z[n-4]) + (1-a)^8(z[n-8]) + ... -+ // -+ // Thus, the strategy here is to compute z[n], z[n-1], z[n-2], and z[n-3] in -+ // each of the 4 lanes, and then combine them to give y[n]. -+ -+ const int rem = len % 4; -+ const int last_index = len - rem; -+ -+ const __m128 smoothing_factor_x4 = _mm_set_ps1(smoothing_factor); -+ const float weight_prev = 1.0f - smoothing_factor; -+ const __m128 weight_prev_x4 = _mm_set_ps1(weight_prev); -+ const __m128 weight_prev_squared_x4 = -+ _mm_mul_ps(weight_prev_x4, weight_prev_x4); -+ const __m128 weight_prev_4th_x4 = -+ _mm_mul_ps(weight_prev_squared_x4, weight_prev_squared_x4); -+ -+ // Compute z[n], z[n-1], z[n-2], and z[n-3] in parallel in lanes 3, 2, 1 and -+ // 0, respectively. -+ __m128 max_x4 = _mm_setzero_ps(); -+ __m128 ewma_x4 = _mm_setr_ps(0.0f, 0.0f, 0.0f, initial_value); -+ int i; -+ for (i = 0; i < last_index; i += 4) { -+ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_4th_x4); -+ const __m128 sample_x4 = _mm_load_ps(src + i); -+ const __m128 sample_squared_x4 = _mm_mul_ps(sample_x4, sample_x4); -+ max_x4 = _mm_max_ps(max_x4, sample_squared_x4); -+ // Note: The compiler optimizes this to a single multiply-and-accumulate -+ // instruction: -+ ewma_x4 = _mm_add_ps(ewma_x4, -+ _mm_mul_ps(sample_squared_x4, smoothing_factor_x4)); -+ } -+ -+ // y[n] = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) -+ float ewma = EXTRACT_FLOAT(ewma_x4, 3); -+ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); -+ ewma += EXTRACT_FLOAT(ewma_x4, 2); -+ ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); -+ ewma += EXTRACT_FLOAT(ewma_x4, 1); -+ ewma_x4 = _mm_mul_ss(ewma_x4, weight_prev_x4); -+ ewma += EXTRACT_FLOAT(ewma_x4, 0); -+ -+ // Fold the maximums together to get the overall maximum. -+ max_x4 = _mm_max_ps(max_x4, -+ _mm_shuffle_ps(max_x4, max_x4, _MM_SHUFFLE(3, 3, 1, 1))); -+ max_x4 = _mm_max_ss(max_x4, _mm_shuffle_ps(max_x4, max_x4, 2)); -+ -+ std::pair result(ewma, EXTRACT_FLOAT(max_x4, 0)); -+ -+ // Handle remaining values at the end of |src|. -+ for (; i < len; ++i) { -+ result.first *= weight_prev; -+ const float sample = src[i]; -+ const float sample_squared = sample * sample; -+ result.first += sample_squared * smoothing_factor; -+ result.second = std::max(result.second, sample_squared); -+ } -+ -+ return result; -+} -+ -+} // namespace vector_math -+} // namespace media -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.cc 2017-07-01 03:36:35.133965899 +0200 -@@ -81,17 +81,12 @@ - #include - #include - -+#include "base/cpu.h" - #include "base/logging.h" - #include "build/build_config.h" - --#if defined(ARCH_CPU_X86_FAMILY) --#include --#define CONVOLVE_FUNC Convolve_SSE --#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -+#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) - #include --#define CONVOLVE_FUNC Convolve_NEON --#else --#define CONVOLVE_FUNC Convolve_C - #endif - - namespace media { -@@ -112,10 +107,41 @@ - return sinc_scale_factor; - } - -+#undef CONVOLVE_FUNC -+ - static int CalculateChunkSize(int block_size_, double io_ratio) { - return block_size_ / io_ratio; - } - -+// If we know the minimum architecture at compile time, avoid CPU detection. -+// Force NaCl code to use C routines since (at present) nothing there uses these -+// methods and plumbing the -msse built library is non-trivial. -+#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) -+#if defined(__SSE__) -+#define CONVOLVE_FUNC Convolve_SSE -+void SincResampler::InitializeCPUSpecificFeatures() {} -+#else -+// X86 CPU detection required. Functions will be set by -+// InitializeCPUSpecificFeatures(). -+#define CONVOLVE_FUNC g_convolve_proc_ -+ -+typedef float (*ConvolveProc)(const float*, const float*, const float*, double); -+static ConvolveProc g_convolve_proc_ = NULL; -+ -+void SincResampler::InitializeCPUSpecificFeatures() { -+ CHECK(!g_convolve_proc_); -+ g_convolve_proc_ = base::CPU().has_sse() ? Convolve_SSE : Convolve_C; -+} -+#endif -+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -+#define CONVOLVE_FUNC Convolve_NEON -+void SincResampler::InitializeCPUSpecificFeatures() {} -+#else -+// Unknown architecture. -+#define CONVOLVE_FUNC Convolve_C -+void SincResampler::InitializeCPUSpecificFeatures() {} -+#endif -+ - SincResampler::SincResampler(double io_sample_rate_ratio, - int request_frames, - const ReadCB& read_cb) -@@ -328,46 +354,7 @@ - kernel_interpolation_factor * sum2); - } - --#if defined(ARCH_CPU_X86_FAMILY) --float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, -- const float* k2, -- double kernel_interpolation_factor) { -- __m128 m_input; -- __m128 m_sums1 = _mm_setzero_ps(); -- __m128 m_sums2 = _mm_setzero_ps(); -- -- // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling -- // these loops hurt performance in local testing. -- if (reinterpret_cast(input_ptr) & 0x0F) { -- for (int i = 0; i < kKernelSize; i += 4) { -- m_input = _mm_loadu_ps(input_ptr + i); -- m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); -- m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); -- } -- } else { -- for (int i = 0; i < kKernelSize; i += 4) { -- m_input = _mm_load_ps(input_ptr + i); -- m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); -- m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); -- } -- } -- -- // Linearly interpolate the two "convolutions". -- m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1( -- static_cast(1.0 - kernel_interpolation_factor))); -- m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1( -- static_cast(kernel_interpolation_factor))); -- m_sums1 = _mm_add_ps(m_sums1, m_sums2); -- -- // Sum components together. -- float result; -- m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); -- _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps( -- m_sums2, m_sums2, 1))); -- -- return result; --} --#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -+#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) - float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, - const float* k2, - double kernel_interpolation_factor) { -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler.h 2017-07-01 03:36:35.133965899 +0200 -@@ -36,6 +36,10 @@ - kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1), - }; - -+ // Selects runtime specific CPU features like SSE. Must be called before -+ // using SincResampler. -+ static void InitializeCPUSpecificFeatures(); -+ - // Callback type for providing more data into the resampler. Expects |frames| - // of data to be rendered into |destination|; zero padded if not enough frames - // are available to satisfy the request. -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_perftest.cc 2017-07-01 03:36:35.134965884 +0200 -@@ -4,6 +4,7 @@ - - #include "base/bind.h" - #include "base/bind_helpers.h" -+#include "base/cpu.h" - #include "base/time/time.h" - #include "build/build_config.h" - #include "media/base/sinc_resampler.h" -@@ -61,6 +62,9 @@ - &resampler, SincResampler::Convolve_C, true, "unoptimized_aligned"); - - #if defined(CONVOLVE_FUNC) -+#if defined(ARCH_CPU_X86_FAMILY) -+ ASSERT_TRUE(base::CPU().has_sse()); -+#endif - RunConvolveBenchmark( - &resampler, SincResampler::CONVOLVE_FUNC, true, "optimized_aligned"); - RunConvolveBenchmark( -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/sinc_resampler_unittest.cc 2017-07-01 03:36:35.134965884 +0200 -@@ -10,6 +10,7 @@ - - #include "base/bind.h" - #include "base/bind_helpers.h" -+#include "base/cpu.h" - #include "base/macros.h" - #include "base/strings/string_number_conversions.h" - #include "base/time/time.h" -@@ -166,6 +167,10 @@ - static const double kKernelInterpolationFactor = 0.5; - - TEST(SincResamplerTest, Convolve) { -+#if defined(ARCH_CPU_X86_FAMILY) -+ ASSERT_TRUE(base::CPU().has_sse()); -+#endif -+ - // Initialize a dummy resampler. - MockSource mock_source; - SincResampler resampler( -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math.cc 2017-07-01 03:36:35.135965870 +0200 -@@ -7,12 +7,17 @@ - - #include - -+#include "base/cpu.h" - #include "base/logging.h" - #include "build/build_config.h" - -+namespace media { -+namespace vector_math { -+ -+// If we know the minimum architecture at compile time, avoid CPU detection. - // NaCl does not allow intrinsics. - #if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) --#include -+#if defined(__SSE__) - // Don't use custom SSE versions where the auto-vectorized C version performs - // better, which is anywhere clang is used. - #if !defined(__clang__) -@@ -23,20 +28,52 @@ - #define FMUL_FUNC FMUL_C - #endif - #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE -+void Initialize() {} -+#else -+// X86 CPU detection required. Functions will be set by Initialize(). -+#if !defined(__clang__) -+#define FMAC_FUNC g_fmac_proc_ -+#define FMUL_FUNC g_fmul_proc_ -+#else -+#define FMAC_FUNC FMAC_C -+#define FMUL_FUNC FMUL_C -+#endif -+#define EWMAAndMaxPower_FUNC g_ewma_power_proc_ -+ -+#if !defined(__clang__) -+typedef void (*MathProc)(const float src[], float scale, int len, float dest[]); -+static MathProc g_fmac_proc_ = NULL; -+static MathProc g_fmul_proc_ = NULL; -+#endif -+typedef std::pair (*EWMAAndMaxPowerProc)( -+ float initial_value, const float src[], int len, float smoothing_factor); -+static EWMAAndMaxPowerProc g_ewma_power_proc_ = NULL; -+ -+void Initialize() { -+ CHECK(!g_fmac_proc_); -+ CHECK(!g_fmul_proc_); -+ CHECK(!g_ewma_power_proc_); -+ const bool kUseSSE = base::CPU().has_sse(); -+#if !defined(__clang__) -+ g_fmac_proc_ = kUseSSE ? FMAC_SSE : FMAC_C; -+ g_fmul_proc_ = kUseSSE ? FMUL_SSE : FMUL_C; -+#endif -+ g_ewma_power_proc_ = kUseSSE ? EWMAAndMaxPower_SSE : EWMAAndMaxPower_C; -+} -+#endif - #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) - #include - #define FMAC_FUNC FMAC_NEON - #define FMUL_FUNC FMUL_NEON - #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON -+void Initialize() {} - #else - #define FMAC_FUNC FMAC_C - #define FMUL_FUNC FMUL_C - #define EWMAAndMaxPower_FUNC EWMAAndMaxPower_C -+void Initialize() {} - #endif - --namespace media { --namespace vector_math { -- - void FMAC(const float src[], float scale, int len, float dest[]) { - // Ensure |src| and |dest| are 16-byte aligned. - DCHECK_EQ(0u, reinterpret_cast(src) & (kRequiredAlignment - 1)); -@@ -89,111 +126,6 @@ - return result; - } - --#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) --void FMUL_SSE(const float src[], float scale, int len, float dest[]) { -- const int rem = len % 4; -- const int last_index = len - rem; -- __m128 m_scale = _mm_set_ps1(scale); -- for (int i = 0; i < last_index; i += 4) -- _mm_store_ps(dest + i, _mm_mul_ps(_mm_load_ps(src + i), m_scale)); -- -- // Handle any remaining values that wouldn't fit in an SSE pass. -- for (int i = last_index; i < len; ++i) -- dest[i] = src[i] * scale; --} -- --void FMAC_SSE(const float src[], float scale, int len, float dest[]) { -- const int rem = len % 4; -- const int last_index = len - rem; -- __m128 m_scale = _mm_set_ps1(scale); -- for (int i = 0; i < last_index; i += 4) { -- _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i), -- _mm_mul_ps(_mm_load_ps(src + i), m_scale))); -- } -- -- // Handle any remaining values that wouldn't fit in an SSE pass. -- for (int i = last_index; i < len; ++i) -- dest[i] += src[i] * scale; --} -- --// Convenience macro to extract float 0 through 3 from the vector |a|. This is --// needed because compilers other than clang don't support access via --// operator[](). --#define EXTRACT_FLOAT(a, i) \ -- (i == 0 ? \ -- _mm_cvtss_f32(a) : \ -- _mm_cvtss_f32(_mm_shuffle_ps(a, a, i))) -- --std::pair EWMAAndMaxPower_SSE( -- float initial_value, const float src[], int len, float smoothing_factor) { -- // When the recurrence is unrolled, we see that we can split it into 4 -- // separate lanes of evaluation: -- // -- // y[n] = a(S[n]^2) + (1-a)(y[n-1]) -- // = a(S[n]^2) + (1-a)^1(aS[n-1]^2) + (1-a)^2(aS[n-2]^2) + ... -- // = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) -- // -- // where z[n] = a(S[n]^2) + (1-a)^4(z[n-4]) + (1-a)^8(z[n-8]) + ... -- // -- // Thus, the strategy here is to compute z[n], z[n-1], z[n-2], and z[n-3] in -- // each of the 4 lanes, and then combine them to give y[n]. -- -- const int rem = len % 4; -- const int last_index = len - rem; -- -- const __m128 smoothing_factor_x4 = _mm_set_ps1(smoothing_factor); -- const float weight_prev = 1.0f - smoothing_factor; -- const __m128 weight_prev_x4 = _mm_set_ps1(weight_prev); -- const __m128 weight_prev_squared_x4 = -- _mm_mul_ps(weight_prev_x4, weight_prev_x4); -- const __m128 weight_prev_4th_x4 = -- _mm_mul_ps(weight_prev_squared_x4, weight_prev_squared_x4); -- -- // Compute z[n], z[n-1], z[n-2], and z[n-3] in parallel in lanes 3, 2, 1 and -- // 0, respectively. -- __m128 max_x4 = _mm_setzero_ps(); -- __m128 ewma_x4 = _mm_setr_ps(0.0f, 0.0f, 0.0f, initial_value); -- int i; -- for (i = 0; i < last_index; i += 4) { -- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_4th_x4); -- const __m128 sample_x4 = _mm_load_ps(src + i); -- const __m128 sample_squared_x4 = _mm_mul_ps(sample_x4, sample_x4); -- max_x4 = _mm_max_ps(max_x4, sample_squared_x4); -- // Note: The compiler optimizes this to a single multiply-and-accumulate -- // instruction: -- ewma_x4 = _mm_add_ps(ewma_x4, -- _mm_mul_ps(sample_squared_x4, smoothing_factor_x4)); -- } -- -- // y[n] = z[n] + (1-a)^1(z[n-1]) + (1-a)^2(z[n-2]) + (1-a)^3(z[n-3]) -- float ewma = EXTRACT_FLOAT(ewma_x4, 3); -- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); -- ewma += EXTRACT_FLOAT(ewma_x4, 2); -- ewma_x4 = _mm_mul_ps(ewma_x4, weight_prev_x4); -- ewma += EXTRACT_FLOAT(ewma_x4, 1); -- ewma_x4 = _mm_mul_ss(ewma_x4, weight_prev_x4); -- ewma += EXTRACT_FLOAT(ewma_x4, 0); -- -- // Fold the maximums together to get the overall maximum. -- max_x4 = _mm_max_ps(max_x4, -- _mm_shuffle_ps(max_x4, max_x4, _MM_SHUFFLE(3, 3, 1, 1))); -- max_x4 = _mm_max_ss(max_x4, _mm_shuffle_ps(max_x4, max_x4, 2)); -- -- std::pair result(ewma, EXTRACT_FLOAT(max_x4, 0)); -- -- // Handle remaining values at the end of |src|. -- for (; i < len; ++i) { -- result.first *= weight_prev; -- const float sample = src[i]; -- const float sample_squared = sample * sample; -- result.first += sample_squared * smoothing_factor; -- result.second = std::max(result.second, sample_squared); -- } -- -- return result; --} --#endif -- - #if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) - void FMAC_NEON(const float src[], float scale, int len, float dest[]) { - const int rem = len % 4; -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math.h 2017-07-01 03:36:35.135965870 +0200 -@@ -15,6 +15,11 @@ - // Required alignment for inputs and outputs to all vector math functions - enum { kRequiredAlignment = 16 }; - -+// Selects runtime specific optimizations such as SSE. Must be called prior to -+// calling FMAC() or FMUL(). Called during media library initialization; most -+// users should never have to call this. -+MEDIA_EXPORT void Initialize(); -+ - // Multiply each element of |src| (up to |len|) by |scale| and add to |dest|. - // |src| and |dest| must be aligned by kRequiredAlignment. - MEDIA_EXPORT void FMAC(const float src[], float scale, int len, float dest[]); -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_perftest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_perftest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_perftest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_perftest.cc 2017-07-01 03:36:35.135965870 +0200 -@@ -5,6 +5,7 @@ - #include - - #include "base/macros.h" -+#include "base/cpu.h" - #include "base/memory/aligned_memory.h" - #include "base/time/time.h" - #include "build/build_config.h" -@@ -82,15 +83,11 @@ - DISALLOW_COPY_AND_ASSIGN(VectorMathPerfTest); - }; - --// Define platform dependent function names for SIMD optimized methods. -+// Define platform independent function name for FMAC* perf tests. - #if defined(ARCH_CPU_X86_FAMILY) - #define FMAC_FUNC FMAC_SSE --#define FMUL_FUNC FMUL_SSE --#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE - #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) - #define FMAC_FUNC FMAC_NEON --#define FMUL_FUNC FMUL_NEON --#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON - #endif - - // Benchmark for each optimized vector_math::FMAC() method. -@@ -99,6 +96,9 @@ - RunBenchmark( - vector_math::FMAC_C, true, "vector_math_fmac", "unoptimized"); - #if defined(FMAC_FUNC) -+#if defined(ARCH_CPU_X86_FAMILY) -+ ASSERT_TRUE(base::CPU().has_sse()); -+#endif - // Benchmark FMAC_FUNC() with unaligned size. - ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / - sizeof(float)), 0U); -@@ -112,12 +112,24 @@ - #endif - } - -+#undef FMAC_FUNC -+ -+// Define platform independent function name for FMULBenchmark* tests. -+#if defined(ARCH_CPU_X86_FAMILY) -+#define FMUL_FUNC FMUL_SSE -+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -+#define FMUL_FUNC FMUL_NEON -+#endif -+ - // Benchmark for each optimized vector_math::FMUL() method. - TEST_F(VectorMathPerfTest, FMUL) { - // Benchmark FMUL_C(). - RunBenchmark( - vector_math::FMUL_C, true, "vector_math_fmul", "unoptimized"); - #if defined(FMUL_FUNC) -+#if defined(ARCH_CPU_X86_FAMILY) -+ ASSERT_TRUE(base::CPU().has_sse()); -+#endif - // Benchmark FMUL_FUNC() with unaligned size. - ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / - sizeof(float)), 0U); -@@ -131,6 +143,14 @@ - #endif - } - -+#undef FMUL_FUNC -+ -+#if defined(ARCH_CPU_X86_FAMILY) -+#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_SSE -+#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -+#define EWMAAndMaxPower_FUNC EWMAAndMaxPower_NEON -+#endif -+ - // Benchmark for each optimized vector_math::EWMAAndMaxPower() method. - TEST_F(VectorMathPerfTest, EWMAAndMaxPower) { - // Benchmark EWMAAndMaxPower_C(). -@@ -139,6 +159,9 @@ - "vector_math_ewma_and_max_power", - "unoptimized"); - #if defined(EWMAAndMaxPower_FUNC) -+#if defined(ARCH_CPU_X86_FAMILY) -+ ASSERT_TRUE(base::CPU().has_sse()); -+#endif - // Benchmark EWMAAndMaxPower_FUNC() with unaligned size. - ASSERT_NE((kVectorSize - 1) % (vector_math::kRequiredAlignment / - sizeof(float)), 0U); -@@ -156,4 +179,6 @@ - #endif - } - -+#undef EWMAAndMaxPower_FUNC -+ - } // namespace media -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_testing.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_testing.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_testing.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_testing.h 2017-07-01 03:36:35.136965855 +0200 -@@ -19,7 +19,7 @@ - MEDIA_EXPORT std::pair EWMAAndMaxPower_C( - float initial_value, const float src[], int len, float smoothing_factor); - --#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) -+#if defined(ARCH_CPU_X86_FAMILY) - MEDIA_EXPORT void FMAC_SSE(const float src[], float scale, int len, - float dest[]); - MEDIA_EXPORT void FMUL_SSE(const float src[], float scale, int len, -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_unittest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_unittest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/vector_math_unittest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/vector_math_unittest.cc 2017-07-01 03:36:35.136965855 +0200 -@@ -9,6 +9,7 @@ - #include - - #include "base/macros.h" -+#include "base/cpu.h" - #include "base/memory/aligned_memory.h" - #include "base/strings/string_number_conversions.h" - #include "base/strings/stringize_macros.h" -@@ -78,6 +79,7 @@ - - #if defined(ARCH_CPU_X86_FAMILY) - { -+ ASSERT_TRUE(base::CPU().has_sse()); - SCOPED_TRACE("FMAC_SSE"); - FillTestVectors(kInputFillValue, kOutputFillValue); - vector_math::FMAC_SSE( -@@ -119,6 +121,7 @@ - - #if defined(ARCH_CPU_X86_FAMILY) - { -+ ASSERT_TRUE(base::CPU().has_sse()); - SCOPED_TRACE("FMUL_SSE"); - FillTestVectors(kInputFillValue, kOutputFillValue); - vector_math::FMUL_SSE( -@@ -227,6 +230,7 @@ - - #if defined(ARCH_CPU_X86_FAMILY) - { -+ ASSERT_TRUE(base::CPU().has_sse()); - SCOPED_TRACE("EWMAAndMaxPower_SSE"); - const std::pair& result = vector_math::EWMAAndMaxPower_SSE( - initial_value_, data_.get(), data_len_, smoothing_factor_); -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert.cc 2017-07-01 03:36:35.136965855 +0200 -@@ -32,7 +32,7 @@ - #include "media/base/simd/convert_yuv_to_rgb.h" - #include "media/base/simd/filter_yuv.h" - --#if defined(ARCH_CPU_X86_FAMILY) -+#if defined(ARCH_CPU_X86_FAMILY) && defined(__MMX__) - #if defined(COMPILER_MSVC) - #include - #else -@@ -133,7 +133,7 @@ - - // Empty SIMD registers state after using them. - void EmptyRegisterStateStub() {} --#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -+#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) && defined(__MMX__) - void EmptyRegisterStateIntrinsic() { _mm_empty(); } - #endif - typedef void (*EmptyRegisterStateProc)(); -@@ -247,34 +247,46 @@ - // Assembly code confuses MemorySanitizer. Also not available in iOS builds. - #if defined(ARCH_CPU_X86_FAMILY) && !defined(MEMORY_SANITIZER) && \ - !defined(OS_IOS) -- g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_MMX; -+ base::CPU cpu; -+ if (cpu.has_mmx()) { -+ g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_MMX; -+ g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_MMX; -+ g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_MMX; -+ g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_MMX; -+ g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_MMX; - - #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -- g_empty_register_state_proc_ = EmptyRegisterStateIntrinsic; -+ g_filter_yuv_rows_proc_ = FilterYUVRows_MMX; -+#endif -+#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) && defined(__MMX__) -+ g_empty_register_state_proc_ = EmptyRegisterStateIntrinsic; - #else -- g_empty_register_state_proc_ = EmptyRegisterState_MMX; -+ g_empty_register_state_proc_ = EmptyRegisterState_MMX; - #endif -+ } - -- g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_SSE; -- g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_SSE; -+ if (cpu.has_sse()) { -+ g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_SSE; -+ g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE; -+ g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_SSE; -+ g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_SSE; -+ } - -- g_filter_yuv_rows_proc_ = FilterYUVRows_SSE2; -- g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_SSE2; -+ if (cpu.has_sse2()) { -+ g_filter_yuv_rows_proc_ = FilterYUVRows_SSE2; -+ g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_SSE2; - - #if defined(ARCH_CPU_X86_64) -- g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE2_X64; -+ g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE2_X64; - -- // Technically this should be in the MMX section, but MSVC will optimize out -- // the export of LinearScaleYUVToRGB32Row_MMX, which is required by the unit -- // tests, if that decision can be made at compile time. Since all X64 CPUs -- // have SSE2, we can hack around this by making the selection here. -- g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_MMX_X64; --#else -- g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE; -- g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_SSE; -+ // Technically this should be in the MMX section, but MSVC will optimize out -+ // the export of LinearScaleYUVToRGB32Row_MMX, which is required by the unit -+ // tests, if that decision can be made at compile time. Since all X64 CPUs -+ // have SSE2, we can hack around this by making the selection here. -+ g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_MMX_X64; - #endif -+ } - -- base::CPU cpu; - if (cpu.has_ssse3()) { - g_convert_rgb24_to_yuv_proc_ = &ConvertRGB24ToYUV_SSSE3; - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert_perftest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert_perftest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert_perftest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert_perftest.cc 2017-07-01 03:36:35.137965840 +0200 -@@ -71,6 +71,29 @@ - DISALLOW_COPY_AND_ASSIGN(YUVConvertPerfTest); - }; - -+TEST_F(YUVConvertPerfTest, ConvertYUVToRGB32Row_MMX) { -+ ASSERT_TRUE(base::CPU().has_mmx()); -+ -+ base::TimeTicks start = base::TimeTicks::Now(); -+ for (int i = 0; i < kPerfTestIterations; ++i) { -+ for (int row = 0; row < kSourceHeight; ++row) { -+ int chroma_row = row / 2; -+ ConvertYUVToRGB32Row_MMX( -+ yuv_bytes_.get() + row * kSourceWidth, -+ yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), -+ yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), -+ rgb_bytes_converted_.get(), -+ kWidth, -+ GetLookupTable(YV12)); -+ } -+ } -+ media::EmptyRegisterState(); -+ double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); -+ perf_test::PrintResult( -+ "yuv_convert_perftest", "", "ConvertYUVToRGB32Row_MMX", -+ kPerfTestIterations / total_time_seconds, "runs/s", true); -+} -+ - TEST_F(YUVConvertPerfTest, ConvertYUVToRGB32Row_SSE) { - ASSERT_TRUE(base::CPU().has_sse()); - -@@ -161,9 +184,32 @@ - } - #endif - --// 64-bit release + component builds on Windows are too smart and optimizes --// away the function being tested. --#if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD)) -+TEST_F(YUVConvertPerfTest, ScaleYUVToRGB32Row_MMX) { -+ ASSERT_TRUE(base::CPU().has_mmx()); -+ -+ const int kSourceDx = 80000; // This value means a scale down. -+ -+ base::TimeTicks start = base::TimeTicks::Now(); -+ for (int i = 0; i < kPerfTestIterations; ++i) { -+ for (int row = 0; row < kSourceHeight; ++row) { -+ int chroma_row = row / 2; -+ ScaleYUVToRGB32Row_MMX( -+ yuv_bytes_.get() + row * kSourceWidth, -+ yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), -+ yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), -+ rgb_bytes_converted_.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ } -+ } -+ media::EmptyRegisterState(); -+ double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); -+ perf_test::PrintResult( -+ "yuv_convert_perftest", "", "ScaleYUVToRGB32Row_MMX", -+ kPerfTestIterations / total_time_seconds, "runs/s", true); -+} -+ - TEST_F(YUVConvertPerfTest, ScaleYUVToRGB32Row_SSE) { - ASSERT_TRUE(base::CPU().has_sse()); - -@@ -190,6 +236,32 @@ - kPerfTestIterations / total_time_seconds, "runs/s", true); - } - -+TEST_F(YUVConvertPerfTest, LinearScaleYUVToRGB32Row_MMX) { -+ ASSERT_TRUE(base::CPU().has_mmx()); -+ -+ const int kSourceDx = 80000; // This value means a scale down. -+ -+ base::TimeTicks start = base::TimeTicks::Now(); -+ for (int i = 0; i < kPerfTestIterations; ++i) { -+ for (int row = 0; row < kSourceHeight; ++row) { -+ int chroma_row = row / 2; -+ LinearScaleYUVToRGB32Row_MMX( -+ yuv_bytes_.get() + row * kSourceWidth, -+ yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2), -+ yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2), -+ rgb_bytes_converted_.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ } -+ } -+ media::EmptyRegisterState(); -+ double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF(); -+ perf_test::PrintResult( -+ "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_MMX", -+ kPerfTestIterations / total_time_seconds, "runs/s", true); -+} -+ - TEST_F(YUVConvertPerfTest, LinearScaleYUVToRGB32Row_SSE) { - ASSERT_TRUE(base::CPU().has_sse()); - -@@ -215,7 +287,6 @@ - "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_SSE", - kPerfTestIterations / total_time_seconds, "runs/s", true); - } --#endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD) - - #endif // !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert_unittest.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert_unittest.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/base/yuv_convert_unittest.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/base/yuv_convert_unittest.cc 2017-07-01 03:36:35.137965840 +0200 -@@ -643,6 +643,37 @@ - EXPECT_EQ(0, error); - } - -+TEST(YUVConvertTest, ConvertYUVToRGB32Row_MMX) { -+ base::CPU cpu; -+ if (!cpu.has_mmx()) { -+ LOG(WARNING) << "System not supported. Test skipped."; -+ return; -+ } -+ -+ scoped_ptr yuv_bytes(new uint8[kYUV12Size]); -+ scoped_ptr rgb_bytes_reference(new uint8[kRGBSize]); -+ scoped_ptr rgb_bytes_converted(new uint8[kRGBSize]); -+ ReadYV12Data(&yuv_bytes); -+ -+ const int kWidth = 167; -+ ConvertYUVToRGB32Row_C(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_reference.get(), -+ kWidth, -+ GetLookupTable(YV12)); -+ ConvertYUVToRGB32Row_MMX(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_converted.get(), -+ kWidth, -+ GetLookupTable(YV12)); -+ media::EmptyRegisterState(); -+ EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(), -+ rgb_bytes_converted.get(), -+ kWidth * kBpp)); -+} -+ - TEST(YUVConvertTest, ConvertYUVToRGB32Row_SSE) { - base::CPU cpu; - if (!cpu.has_sse()) { -@@ -674,9 +705,40 @@ - kWidth * kBpp)); - } - --// 64-bit release + component builds on Windows are too smart and optimizes --// away the function being tested. --#if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD)) -+TEST(YUVConvertTest, ScaleYUVToRGB32Row_MMX) { -+ base::CPU cpu; -+ if (!cpu.has_mmx()) { -+ LOG(WARNING) << "System not supported. Test skipped."; -+ return; -+ } -+ -+ scoped_ptr yuv_bytes(new uint8[kYUV12Size]); -+ scoped_ptr rgb_bytes_reference(new uint8[kRGBSize]); -+ scoped_ptr rgb_bytes_converted(new uint8[kRGBSize]); -+ ReadYV12Data(&yuv_bytes); -+ -+ const int kWidth = 167; -+ const int kSourceDx = 80000; // This value means a scale down. -+ ScaleYUVToRGB32Row_C(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_reference.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ ScaleYUVToRGB32Row_MMX(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_converted.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ media::EmptyRegisterState(); -+ EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(), -+ rgb_bytes_converted.get(), -+ kWidth * kBpp)); -+} -+ - TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE) { - base::CPU cpu; - if (!cpu.has_sse()) { -@@ -711,6 +773,40 @@ - kWidth * kBpp)); - } - -+TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_MMX) { -+ base::CPU cpu; -+ if (!cpu.has_mmx()) { -+ LOG(WARNING) << "System not supported. Test skipped."; -+ return; -+ } -+ -+ scoped_ptr yuv_bytes(new uint8[kYUV12Size]); -+ scoped_ptr rgb_bytes_reference(new uint8[kRGBSize]); -+ scoped_ptr rgb_bytes_converted(new uint8[kRGBSize]); -+ ReadYV12Data(&yuv_bytes); -+ -+ const int kWidth = 167; -+ const int kSourceDx = 80000; // This value means a scale down. -+ LinearScaleYUVToRGB32Row_C(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_reference.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ LinearScaleYUVToRGB32Row_MMX(yuv_bytes.get(), -+ yuv_bytes.get() + kSourceUOffset, -+ yuv_bytes.get() + kSourceVOffset, -+ rgb_bytes_converted.get(), -+ kWidth, -+ kSourceDx, -+ GetLookupTable(YV12)); -+ media::EmptyRegisterState(); -+ EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(), -+ rgb_bytes_converted.get(), -+ kWidth * kBpp)); -+} -+ - TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_SSE) { - base::CPU cpu; - if (!cpu.has_sse()) { -@@ -744,7 +840,6 @@ - rgb_bytes_converted.get(), - kWidth * kBpp)); - } --#endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD) - - TEST(YUVConvertTest, FilterYUVRows_C_OutOfBounds) { - std::unique_ptr src(new uint8_t[16]); -@@ -761,6 +856,30 @@ - } - } - -+#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -+TEST(YUVConvertTest, FilterYUVRows_MMX_OutOfBounds) { -+ base::CPU cpu; -+ if (!cpu.has_mmx()) { -+ LOG(WARNING) << "System not supported. Test skipped."; -+ return; -+ } -+ -+ scoped_ptr src(new uint8[16]); -+ scoped_ptr dst(new uint8[16]); -+ -+ memset(src.get(), 0xff, 16); -+ memset(dst.get(), 0, 16); -+ -+ media::FilterYUVRows_MMX(dst.get(), src.get(), src.get(), 1, 255); -+ media::EmptyRegisterState(); -+ -+ EXPECT_EQ(255u, dst[0]); -+ for (int i = 1; i < 16; ++i) { -+ EXPECT_EQ(0u, dst[i]); -+ } -+} -+#endif // defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -+ - TEST(YUVConvertTest, FilterYUVRows_SSE2_OutOfBounds) { - base::CPU cpu; - if (!cpu.has_sse2()) { -@@ -782,6 +901,38 @@ - } - } - -+#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -+TEST(YUVConvertTest, FilterYUVRows_MMX_UnalignedDestination) { -+ base::CPU cpu; -+ if (!cpu.has_mmx()) { -+ LOG(WARNING) << "System not supported. Test skipped."; -+ return; -+ } -+ -+ const int kSize = 32; -+ scoped_ptr src(new uint8[kSize]); -+ scoped_ptr dst_sample(new uint8[kSize]); -+ scoped_ptr dst(new uint8[kSize]); -+ -+ memset(dst_sample.get(), 0, kSize); -+ memset(dst.get(), 0, kSize); -+ for (int i = 0; i < kSize; ++i) -+ src[i] = 100 + i; -+ -+ media::FilterYUVRows_C(dst_sample.get(), -+ src.get(), src.get(), 17, 128); -+ -+ // Generate an unaligned output address. -+ uint8* dst_ptr = -+ reinterpret_cast( -+ (reinterpret_cast(dst.get() + 8) & ~7) + 1); -+ media::FilterYUVRows_MMX(dst_ptr, src.get(), src.get(), 17, 128); -+ media::EmptyRegisterState(); -+ -+ EXPECT_EQ(0, memcmp(dst_sample.get(), dst_ptr, 17)); -+} -+#endif // defined(MEDIA_MMX_INTRINSICS_AVAILABLE) -+ - TEST(YUVConvertTest, FilterYUVRows_SSE2_UnalignedDestination) { - base::CPU cpu; - if (!cpu.has_sse2()) { -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/BUILD.gn 2017-07-01 03:36:35.138965826 +0200 -@@ -832,6 +832,26 @@ - "//base", - "//ui/gfx/geometry", - ] -+ if (current_cpu == "x86" || current_cpu == "x64") { -+ deps += [ -+ ":shared_memory_support_sse", -+ ] -+ } -+} -+ -+if (current_cpu == "x86" || current_cpu == "x64") { -+ source_set("shared_memory_support_sse") { -+ sources = [ -+ "base/simd/vector_math_sse.cc", -+ ] -+ configs += [ -+ "//media:media_config", -+ "//media:media_implementation", -+ ] -+ if (!is_win) { -+ cflags = [ "-msse" ] -+ } -+ } - } - - # TODO(watk): Refactor tests that could be made to run on Android. See -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/filters/wsola_internals.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/filters/wsola_internals.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/media/filters/wsola_internals.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/media/filters/wsola_internals.cc 2017-07-01 03:36:35.206964834 +0200 -@@ -15,7 +15,7 @@ - #include "base/logging.h" - #include "media/base/audio_bus.h" - --#if defined(ARCH_CPU_X86_FAMILY) -+#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE2__) - #define USE_SIMD 1 - #include - #elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/BUILD.gn 2017-07-01 03:36:35.273963857 +0200 -@@ -231,11 +231,6 @@ - if (!is_ios) { - sources += [ "ext/platform_canvas.cc" ] - } -- if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) { -- sources += [ "ext/convolver_SSE2.cc" ] -- } else if (current_cpu == "mipsel" && mips_dsp_rev >= 2) { -- sources += [ "ext/convolver_mips_dspr2.cc" ] -- } - - # The skia gypi values are relative to the skia_dir, so we need to rebase. - sources += skia_core_sources -@@ -500,6 +495,31 @@ - } - } - if (current_cpu == "x86" || current_cpu == "x64") { -+ source_set("skia_opts_sse2") { -+ sources = skia_opts.sse2_sources + -+ [ -+ # Chrome-specific. -+ "ext/convolver_SSE2.cc", -+ "ext/convolver_SSE2.h", -+ ] -+ sources -= [ -+ # Detection code must not be built with -msse2 -+ "//third_party/skia/src/opts/opts_check_x86.cpp", -+ ] -+ if (!is_win || is_clang) { -+ cflags = [ "-msse2" ] -+ } -+ if (is_win) { -+ defines = [ "SK_CPU_SSE_LEVEL=20" ] -+ } -+ visibility = [ ":skia_opts" ] -+ configs -= [ "//build/config/compiler:chromium_code" ] -+ configs += [ -+ ":skia_config", -+ ":skia_library_config", -+ "//build/config/compiler:no_chromium_code", -+ ] -+ } - source_set("skia_opts_sse3") { - sources = skia_opts.ssse3_sources - if (!is_win || is_clang) { -@@ -608,10 +628,13 @@ - if (skia_build_no_opts) { - sources = skia_opts.none_sources - } else if (current_cpu == "x86" || current_cpu == "x64") { -- sources = skia_opts.sse2_sources -+ sources = [ -+ "//third_party/skia/src/opts/opts_check_x86.cpp", -+ ] - deps += [ - ":skia_opts_avx", - ":skia_opts_hsw", -+ ":skia_opts_sse2", - ":skia_opts_sse3", - ":skia_opts_sse41", - ":skia_opts_sse42", -@@ -644,6 +667,13 @@ - - if (mips_dsp_rev >= 1) { - sources = skia_opts.mips_dsp_sources -+ if (mips_dsp_rev >= 2) { -+ sources += [ -+ # Chrome-specific. -+ "ext/convolver_mips_dspr2.cc", -+ "ext/convolver_mips_dspr2.h", -+ ] -+ } - } else { - sources = skia_opts.none_sources - } -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/ext/convolver.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/ext/convolver.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/ext/convolver.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/ext/convolver.cc 2017-07-01 03:36:35.331963011 +0200 -@@ -362,10 +362,13 @@ - - void SetupSIMD(ConvolveProcs *procs) { - #ifdef SIMD_SSE2 -- procs->extra_horizontal_reads = 3; -- procs->convolve_vertically = &ConvolveVertically_SSE2; -- procs->convolve_4rows_horizontally = &Convolve4RowsHorizontally_SSE2; -- procs->convolve_horizontally = &ConvolveHorizontally_SSE2; -+ base::CPU cpu; -+ if (cpu.has_sse2()) { -+ procs->extra_horizontal_reads = 3; -+ procs->convolve_vertically = &ConvolveVertically_SSE2; -+ procs->convolve_4rows_horizontally = &Convolve4RowsHorizontally_SSE2; -+ procs->convolve_horizontally = &ConvolveHorizontally_SSE2; -+ } - #elif defined SIMD_MIPS_DSPR2 - procs->extra_horizontal_reads = 3; - procs->convolve_vertically = &ConvolveVertically_mips_dspr2; -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/ext/convolver.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/ext/convolver.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/skia/ext/convolver.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/skia/ext/convolver.h 2017-07-01 03:36:35.331963011 +0200 -@@ -11,6 +11,7 @@ - #include - - #include "build/build_config.h" -+#include "base/cpu.h" - #include "third_party/skia/include/core/SkSize.h" - #include "third_party/skia/include/core/SkTypes.h" - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/BUILD.gn 2017-07-01 03:36:35.332962996 +0200 -@@ -160,6 +160,26 @@ - public_deps = [ - ":angle_common", - ] -+ -+ if (current_cpu == "x86") { -+ deps = [ -+ ":angle_image_util_x86_sse2", -+ ] -+ } -+} -+ -+source_set("angle_image_util_x86_sse2") { -+ configs -= angle_undefine_configs -+ configs += [ ":internal_config" ] -+ -+ deps = [ -+ ":angle_common", -+ ] -+ -+ sources = [ -+ "src/image_util/loadimage_SSE2.cpp", -+ ] -+ cflags = [ "-msse2", "-mfpmath=sse" ] - } - - static_library("translator") { -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/mathutil.h 2017-07-01 03:36:35.406961915 +0200 -@@ -142,9 +142,42 @@ - } - } - --inline bool supportsSSE2() -+#if defined(ANGLE_USE_SSE) && !defined(__x86_64__) && !defined(__SSE2__) && !defined(_MSC_VER) -+ -+// From the base/cpu.cc in Chromium, to avoid depending on Chromium headers -+ -+#if defined(__pic__) && defined(__i386__) -+ -+static inline void __cpuid(int cpu_info[4], int info_type) { -+ __asm__ volatile ( -+ "mov %%ebx, %%edi\n" -+ "cpuid\n" -+ "xchg %%edi, %%ebx\n" -+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) -+ : "a"(info_type) -+ ); -+} -+ -+#else -+ -+static inline void __cpuid(int cpu_info[4], int info_type) { -+ __asm__ volatile ( -+ "cpuid\n" -+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) -+ : "a"(info_type) -+ ); -+} -+ -+#endif -+ -+#endif -+ -+static inline bool supportsSSE2() - { - #if defined(ANGLE_USE_SSE) -+#if defined(__x86_64__) || defined(__SSE2__) -+ return true; -+#else - static bool checked = false; - static bool supports = false; - -@@ -153,7 +186,6 @@ - return supports; - } - --#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) - { - int info[4]; - __cpuid(info, 0); -@@ -165,9 +197,9 @@ - supports = (info[3] >> 26) & 1; - } - } --#endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) - checked = true; - return supports; -+#endif // defined(x86_64) || defined(__SSE2__) - #else // defined(ANGLE_USE_SSE) - return false; - #endif -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/common/platform.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/platform.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/common/platform.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/common/platform.h 2017-07-01 03:36:35.406961915 +0200 -@@ -81,7 +81,9 @@ - #include - #define ANGLE_USE_SSE - #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) -+#if defined(__x86_64__) || defined(__SSE2__) - #include -+#endif - #define ANGLE_USE_SSE - #endif - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.cpp 2017-07-01 03:36:35.407961901 +0200 -@@ -12,9 +12,17 @@ - #include "common/platform.h" - #include "image_util/imageformats.h" - -+#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) -+#error SSE2 parts must be built with -msse2 -+#endif -+ - namespace angle - { - -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+namespace SSE2 { -+#endif -+ - void LoadA8ToRGBA8(size_t width, - size_t height, - size_t depth, -@@ -28,6 +36,11 @@ - #if defined(ANGLE_USE_SSE) - if (gl::supportsSSE2()) - { -+#if !defined(__x86_64__) && !defined(__SSE2__) -+ angle::SSE2::LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, -+ inputDepthPitch, output, outputRowPitch, -+ outputDepthPitch); -+#else - __m128i zeroWide = _mm_setzero_si128(); - - for (size_t z = 0; z < depth; z++) -@@ -68,6 +81,7 @@ - } - } - } -+#endif - - return; - } -@@ -89,6 +103,8 @@ - } - } - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - void LoadA8ToBGRA8(size_t width, - size_t height, - size_t depth, -@@ -584,6 +600,8 @@ - } - } - -+#endif -+ - void LoadRGBA8ToBGRA8(size_t width, - size_t height, - size_t depth, -@@ -597,6 +615,11 @@ - #if defined(ANGLE_USE_SSE) - if (gl::supportsSSE2()) - { -+#if !defined(__x86_64__) && !defined(__SSE2__) -+ angle::SSE2::LoadRGBA8ToBGRA8(width, height, depth, input, -+ inputRowPitch, inputDepthPitch, output, -+ outputRowPitch, outputDepthPitch); -+#else - __m128i brMask = _mm_set1_epi32(0x00ff00ff); - - for (size_t z = 0; z < depth; z++) -@@ -641,6 +664,7 @@ - } - } - } -+#endif - - return; - } -@@ -663,6 +687,8 @@ - } - } - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - void LoadRGBA8ToBGRA4(size_t width, - size_t height, - size_t depth, -@@ -1320,4 +1346,10 @@ - } - } - -+#endif -+ -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+} // namespace SSE2 -+#endif -+ - } // namespace angle -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage.h 2017-07-01 03:36:35.408961886 +0200 -@@ -611,6 +611,32 @@ - size_t outputRowPitch, - size_t outputDepthPitch); - -+#if defined(__i386__) -+namespace SSE2 { -+ -+void LoadA8ToRGBA8(size_t width, -+ size_t height, -+ size_t depth, -+ const uint8_t *input, -+ size_t inputRowPitch, -+ size_t inputDepthPitch, -+ uint8_t *output, -+ size_t outputRowPitch, -+ size_t outputDepthPitch); -+ -+void LoadRGBA8ToBGRA8(size_t width, -+ size_t height, -+ size_t depth, -+ const uint8_t *input, -+ size_t inputRowPitch, -+ size_t inputDepthPitch, -+ uint8_t *output, -+ size_t outputRowPitch, -+ size_t outputDepthPitch); -+ -+} -+#endif // defined(__i386__) -+ - } // namespace angle - - #include "loadimage.inl" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/angle/src/image_util/loadimage_SSE2.cpp 2017-07-01 03:36:35.408961886 +0200 -@@ -0,0 +1,2 @@ -+#define BUILD_ONLY_THE_SSE2_PARTS -+#include "loadimage.cpp" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/qcms/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/qcms/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/qcms/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/qcms/BUILD.gn 2017-07-01 03:36:35.408961886 +0200 -@@ -30,8 +30,8 @@ - ] - - if (current_cpu == "x86" || current_cpu == "x64") { -- defines = [ "SSE2_ENABLE" ] -- sources += [ "src/transform-sse2.c" ] -+ defines = [ "SSE2_ENABLE" ] # runtime detection -+ deps = [ ":qcms_sse2" ] - } - } - -@@ -74,3 +74,15 @@ - public_configs = [ ":qcms_config" ] - } - } -+ -+source_set("qcms_sse2") { -+ configs -= [ "//build/config/compiler:chromium_code" ] -+ configs += [ "//build/config/compiler:no_chromium_code" ] -+ public_configs = [ ":qcms_config" ] -+ -+ if (current_cpu == "x86" || current_cpu == "x64") { -+ defines = [ "SSE2_ENABLE" ] -+ sources = [ "src/transform-sse2.c" ] -+ cflags = [ "-msse2" ] -+ } -+} -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp 2017-07-01 03:36:35.556959728 +0200 -@@ -31,7 +31,7 @@ - #include "wtf/MathExtras.h" - #include - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - #include - #endif - -@@ -662,7 +662,7 @@ - // the next event. - if (nextEventType == ParamEvent::LinearRampToValue) { - const float valueDelta = value2 - value1; --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if (fillToFrame > writeIndex) { - // Minimize in-loop operations. Calculate starting value and increment. - // Next step: value += inc. -@@ -841,7 +841,7 @@ - for (; writeIndex < fillToFrame; ++writeIndex) - values[writeIndex] = target; - } else { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if (fillToFrame > writeIndex) { - // Resolve recursion by expanding constants to achieve a 4-step - // loop unrolling. -@@ -959,7 +959,7 @@ - // Oversampled curve data can be provided if sharp discontinuities are - // desired. - unsigned k = 0; --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if (fillToFrame > writeIndex) { - const __m128 vCurveVirtualIndex = _mm_set_ps1(curveVirtualIndex); - const __m128 vCurvePointsPerFrame = -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.cpp 2017-07-01 03:36:35.673958021 +0200 -@@ -26,6 +26,9 @@ - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -+// include this first to get it before the CPU() function-like macro -+#include "base/cpu.h" -+ - #include "platform/audio/DirectConvolver.h" - - #if OS(MACOSX) -@@ -35,21 +38,47 @@ - #include "platform/audio/VectorMath.h" - #include "wtf/CPU.h" - --#if (CPU(X86) || CPU(X86_64)) && !OS(MACOSX) -+#if ((CPU(X86) && defined(__SSE2__)) || CPU(X86_64)) && !OS(MACOSX) - #include - #endif - -+#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) -+#error SSE2 parts must be built with -msse2 -+#endif -+ - namespace blink { - - using namespace VectorMath; - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - DirectConvolver::DirectConvolver(size_t inputBlockSize) -- : m_inputBlockSize(inputBlockSize), m_buffer(inputBlockSize * 2) {} -+ : m_inputBlockSize(inputBlockSize), m_buffer(inputBlockSize * 2) { -+#if CPU(X86) -+ base::CPU cpu; -+ m_haveSSE2 = cpu.has_sse2(); -+#endif -+} -+ -+#endif - -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+void DirectConvolver::m_processSSE2(AudioFloatArray* convolutionKernel, -+ const float* sourceP, -+ float* destP, -+ size_t framesToProcess) { -+#else - void DirectConvolver::process(AudioFloatArray* convolutionKernel, - const float* sourceP, - float* destP, - size_t framesToProcess) { -+#endif -+#if CPU(X86) && !defined(__SSE2__) -+ if (m_haveSSE2) { -+ m_processSSE2(convolutionKernel, sourceP, destP, framesToProcess); -+ return; -+ } -+#endif - ASSERT(framesToProcess == m_inputBlockSize); - if (framesToProcess != m_inputBlockSize) - return; -@@ -83,7 +112,7 @@ - #endif // CPU(X86) - #else - size_t i = 0; --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - // Convolution using SSE2. Currently only do this if both |kernelSize| and - // |framesToProcess| are multiples of 4. If not, use the straightforward loop - // below. -@@ -397,7 +426,7 @@ - } - destP[i++] = sum; - } --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - } - #endif - #endif // OS(MACOSX) -@@ -406,8 +435,12 @@ - memcpy(m_buffer.data(), inputP, sizeof(float) * framesToProcess); - } - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - void DirectConvolver::reset() { - m_buffer.zero(); - } - -+#endif -+ - } // namespace blink -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolver.h 2017-07-01 03:36:35.673958021 +0200 -@@ -32,6 +32,7 @@ - #include "platform/PlatformExport.h" - #include "platform/audio/AudioArray.h" - #include "wtf/Allocator.h" -+#include "wtf/CPU.h" - #include "wtf/Noncopyable.h" - - namespace blink { -@@ -54,6 +55,14 @@ - size_t m_inputBlockSize; - - AudioFloatArray m_buffer; -+ -+#if CPU(X86) -+ bool m_haveSSE2; -+ void m_processSSE2(AudioFloatArray* convolutionKernel, -+ const float* sourceP, -+ float* destP, -+ size_t framesToProcess); -+#endif - }; - - } // namespace blink -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/DirectConvolverSSE2.cpp 2017-07-01 03:36:35.673958021 +0200 -@@ -0,0 +1,2 @@ -+#define BUILD_ONLY_THE_SSE2_PARTS -+#include "DirectConvolver.cpp" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.cpp 2017-07-01 03:36:35.674958007 +0200 -@@ -26,15 +26,22 @@ - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -+// include this first to get it before the CPU() function-like macro -+#include "base/cpu.h" -+ - #include "platform/audio/SincResampler.h" - #include "platform/audio/AudioBus.h" - #include "wtf/CPU.h" - #include "wtf/MathExtras.h" - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - #include - #endif - -+#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) -+#error SSE2 parts must be built with -msse2 -+#endif -+ - // Input buffer layout, dividing the total buffer into regions (r0 - r5): - // - // |----------------|-----------------------------------------|----------------| -@@ -66,6 +73,8 @@ - - namespace blink { - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - SincResampler::SincResampler(double scaleFactor, - unsigned kernelSize, - unsigned numberOfKernelOffsets) -@@ -81,6 +90,10 @@ - m_sourceFramesAvailable(0), - m_sourceProvider(nullptr), - m_isBufferPrimed(false) { -+#if CPU(X86) -+ base::CPU cpu; -+ m_haveSSE2 = cpu.has_sse2(); -+#endif - initializeKernel(); - } - -@@ -201,9 +214,23 @@ - } - } - -+#endif -+ -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+void SincResampler::m_processSSE2(AudioSourceProvider* sourceProvider, -+ float* destination, -+ size_t framesToProcess) { -+#else - void SincResampler::process(AudioSourceProvider* sourceProvider, - float* destination, - size_t framesToProcess) { -+#endif -+#if CPU(X86) && !defined(__SSE2__) -+ if (m_haveSSE2) { -+ m_processSSE2(sourceProvider, destination, framesToProcess); -+ return; -+ } -+#endif - bool isGood = sourceProvider && m_blockSize > m_kernelSize && - m_inputBuffer.size() >= m_blockSize + m_kernelSize && - !(m_kernelSize % 2); -@@ -269,7 +296,7 @@ - { - float input; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - // If the sourceP address is not 16-byte aligned, the first several - // frames (at most three) should be processed seperately. - while ((reinterpret_cast(inputP) & 0x0F) && n) { -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResampler.h 2017-07-01 03:36:35.674958007 +0200 -@@ -33,6 +33,7 @@ - #include "platform/audio/AudioArray.h" - #include "platform/audio/AudioSourceProvider.h" - #include "wtf/Allocator.h" -+#include "wtf/CPU.h" - #include "wtf/Noncopyable.h" - - namespace blink { -@@ -96,6 +97,13 @@ - - // The buffer is primed once at the very beginning of processing. - bool m_isBufferPrimed; -+ -+#if CPU(X86) -+ bool m_haveSSE2; -+ void m_processSSE2(AudioSourceProvider*, -+ float* destination, -+ size_t framesToProcess); -+#endif - }; - - } // namespace blink -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/SincResamplerSSE2.cpp 2017-07-01 03:36:35.674958007 +0200 -@@ -0,0 +1,2 @@ -+#define BUILD_ONLY_THE_SSE2_PARTS -+#include "SincResampler.cpp" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.cpp 2017-07-01 03:36:35.675957992 +0200 -@@ -23,6 +23,9 @@ - * DAMAGE. - */ - -+// include this first to get it before the CPU() function-like macro -+#include "base/cpu.h" -+ - #include "platform/audio/VectorMath.h" - #include "wtf/Assertions.h" - #include "wtf/CPU.h" -@@ -33,10 +36,14 @@ - #include - #endif - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - #include - #endif - -+#if defined(BUILD_ONLY_THE_SSE2_PARTS) && !defined(__SSE2__) -+#error SSE2 parts must be built with -msse2 -+#endif -+ - #if HAVE(ARM_NEON_INTRINSICS) - #include - #endif -@@ -165,15 +172,30 @@ - } - #else - -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+namespace SSE2 { -+#endif -+ -+#if CPU(X86) && !defined(__SSE2__) -+static base::CPU cpu; -+#endif -+ - void vsma(const float* sourceP, - int sourceStride, - const float* scale, - float* destP, - int destStride, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vsma(sourceP, sourceStride, scale, destP, -+ destStride, framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if ((sourceStride == 1) && (destStride == 1)) { - float k = *scale; - -@@ -269,9 +291,16 @@ - float* destP, - int destStride, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vsmul(sourceP, sourceStride, scale, destP, -+ destStride, framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if ((sourceStride == 1) && (destStride == 1)) { - float k = *scale; - -@@ -360,7 +389,7 @@ - sourceP += sourceStride; - destP += destStride; - } --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - } - #endif - } -@@ -372,9 +401,17 @@ - float* destP, - int destStride, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vadd(source1P, sourceStride1, source2P, -+ sourceStride2, destP, destStride, -+ framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if ((sourceStride1 == 1) && (sourceStride2 == 1) && (destStride == 1)) { - // If the sourceP address is not 16-byte aligned, the first several frames - // (at most three) should be processed separately. -@@ -501,7 +538,7 @@ - source2P += sourceStride2; - destP += destStride; - } --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - } - #endif - } -@@ -513,9 +550,17 @@ - float* destP, - int destStride, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vmul(source1P, sourceStride1, source2P, -+ sourceStride2, destP, destStride, -+ framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if ((sourceStride1 == 1) && (sourceStride2 == 1) && (destStride == 1)) { - // If the source1P address is not 16-byte aligned, the first several frames - // (at most three) should be processed separately. -@@ -614,8 +659,15 @@ - float* realDestP, - float* imagDestP, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::zvmul(real1P, imag1P, real2P, imag2P, realDestP, -+ imagDestP, framesToProcess); -+ return; -+ } -+#endif - unsigned i = 0; --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - // Only use the SSE optimization in the very common case that all addresses - // are 16-byte aligned. Otherwise, fall through to the scalar code below. - if (!(reinterpret_cast(real1P) & 0x0F) && -@@ -671,10 +723,17 @@ - int sourceStride, - float* sumP, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vsvesq(sourceP, sourceStride, sumP, -+ framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - float sum = 0; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if (sourceStride == 1) { - // If the sourceP address is not 16-byte aligned, the first several frames - // (at most three) should be processed separately. -@@ -740,10 +799,17 @@ - int sourceStride, - float* maxP, - size_t framesToProcess) { -+#if CPU(X86) && !defined(__SSE2__) -+ if (cpu.has_sse2()) { -+ blink::VectorMath::SSE2::vmaxmgv(sourceP, sourceStride, maxP, -+ framesToProcess); -+ return; -+ } -+#endif - int n = framesToProcess; - float max = 0; - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - if (sourceStride == 1) { - // If the sourceP address is not 16-byte aligned, the first several frames - // (at most three) should be processed separately. -@@ -832,6 +898,8 @@ - *maxP = max; - } - -+#ifndef BUILD_ONLY_THE_SSE2_PARTS -+ - void vclip(const float* sourceP, - int sourceStride, - const float* lowThresholdP, -@@ -889,6 +957,12 @@ - } - } - -+#endif -+ -+#ifdef BUILD_ONLY_THE_SSE2_PARTS -+} // namespace SSE2 -+#endif -+ - #endif // OS(MACOSX) - - } // namespace VectorMath -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMath.h 2017-07-01 03:36:35.675957992 +0200 -@@ -27,6 +27,7 @@ - #define VectorMath_h - - #include "platform/PlatformExport.h" -+#include "wtf/CPU.h" - #include "wtf/build_config.h" - #include - -@@ -97,6 +98,62 @@ - int destStride, - size_t framesToProcess); - -+#if CPU(X86) -+namespace SSE2 { -+// Vector scalar multiply and then add. -+PLATFORM_EXPORT void vsma(const float* sourceP, -+ int sourceStride, -+ const float* scale, -+ float* destP, -+ int destStride, -+ size_t framesToProcess); -+ -+PLATFORM_EXPORT void vsmul(const float* sourceP, -+ int sourceStride, -+ const float* scale, -+ float* destP, -+ int destStride, -+ size_t framesToProcess); -+PLATFORM_EXPORT void vadd(const float* source1P, -+ int sourceStride1, -+ const float* source2P, -+ int sourceStride2, -+ float* destP, -+ int destStride, -+ size_t framesToProcess); -+ -+// Finds the maximum magnitude of a float vector. -+PLATFORM_EXPORT void vmaxmgv(const float* sourceP, -+ int sourceStride, -+ float* maxP, -+ size_t framesToProcess); -+ -+// Sums the squares of a float vector's elements. -+PLATFORM_EXPORT void vsvesq(const float* sourceP, -+ int sourceStride, -+ float* sumP, -+ size_t framesToProcess); -+ -+// For an element-by-element multiply of two float vectors. -+PLATFORM_EXPORT void vmul(const float* source1P, -+ int sourceStride1, -+ const float* source2P, -+ int sourceStride2, -+ float* destP, -+ int destStride, -+ size_t framesToProcess); -+ -+// Multiplies two complex vectors. -+PLATFORM_EXPORT void zvmul(const float* real1P, -+ const float* imag1P, -+ const float* real2P, -+ const float* imag2P, -+ float* realDestP, -+ float* imagDestP, -+ size_t framesToProcess); -+} -+#endif -+ - } // namespace VectorMath - } // namespace blink - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/audio/VectorMathSSE2.cpp 2017-07-01 03:36:35.675957992 +0200 -@@ -0,0 +1,2 @@ -+#define BUILD_ONLY_THE_SSE2_PARTS -+#include "VectorMath.cpp" -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/BUILD.gn 2017-07-01 03:36:35.676957977 +0200 -@@ -1529,6 +1529,10 @@ - deps += [ ":blink_x86_sse" ] - } - -+ if (current_cpu == "x86") { -+ deps += [ ":blink_x86_sse2" ] -+ } -+ - if (use_webaudio_ffmpeg) { - include_dirs += [ "//third_party/ffmpeg" ] - deps += [ "//third_party/ffmpeg" ] -@@ -1914,6 +1918,26 @@ - ] - } - } -+ -+if (current_cpu == "x86") { -+ source_set("blink_x86_sse2") { -+ sources = [ -+ "audio/DirectConvolverSSE2.cpp", -+ "audio/SincResamplerSSE2.cpp", -+ "audio/VectorMathSSE2.cpp", -+ ] -+ cflags = [ "-msse2", "-mfpmath=sse" ] -+ deps = [ -+ ":blink_common", -+ ] -+ configs += [ -+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. -+ "//build/config/compiler:no_size_t_to_int_warning", -+ "//third_party/WebKit/Source:config", -+ "//third_party/WebKit/Source:non_test_config", -+ ] -+ } -+} - - # This source set is used for fuzzers that need an environment similar to unit - # tests. -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/cpu/x86/WebGLImageConversionSSE.h 2017-07-01 03:36:35.676957977 +0200 -@@ -5,7 +5,7 @@ - #ifndef WebGLImageConversionSSE_h - #define WebGLImageConversionSSE_h - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - - #include - -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/WebKit/Source/platform/graphics/gpu/WebGLImageConversion.cpp 2017-07-01 03:36:35.677957963 +0200 -@@ -441,7 +441,7 @@ - const uint32_t* source32 = reinterpret_cast_ptr(source); - uint32_t* destination32 = reinterpret_cast_ptr(destination); - --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::unpackOneRowOfBGRA8LittleToRGBA8(source32, destination32, pixelsPerRow); - #endif - #if HAVE(MIPS_MSA_INTRINSICS) -@@ -467,7 +467,7 @@ - const uint16_t* source, - uint8_t* destination, - unsigned pixelsPerRow) { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::unpackOneRowOfRGBA5551LittleToRGBA8(source, destination, pixelsPerRow); - #endif - #if HAVE(ARM_NEON_INTRINSICS) -@@ -496,7 +496,7 @@ - const uint16_t* source, - uint8_t* destination, - unsigned pixelsPerRow) { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::unpackOneRowOfRGBA4444LittleToRGBA8(source, destination, pixelsPerRow); - #endif - #if HAVE(ARM_NEON_INTRINSICS) -@@ -711,7 +711,7 @@ - uint8_t>(const uint8_t* source, - uint8_t* destination, - unsigned pixelsPerRow) { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::packOneRowOfRGBA8LittleToR8(source, destination, pixelsPerRow); - #endif - #if HAVE(MIPS_MSA_INTRINSICS) -@@ -768,7 +768,7 @@ - uint8_t>(const uint8_t* source, - uint8_t* destination, - unsigned pixelsPerRow) { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::packOneRowOfRGBA8LittleToRA8(source, destination, pixelsPerRow); - #endif - #if HAVE(MIPS_MSA_INTRINSICS) -@@ -880,7 +880,7 @@ - uint8_t>(const uint8_t* source, - uint8_t* destination, - unsigned pixelsPerRow) { --#if CPU(X86) || CPU(X86_64) -+#if (CPU(X86) && defined(__SSE2__)) || CPU(X86_64) - SIMD::packOneRowOfRGBA8LittleToRGBA8(source, destination, pixelsPerRow); - #endif - #if HAVE(MIPS_MSA_INTRINSICS) -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/third_party/webrtc/common_audio/real_fourier.cc 2017-07-01 03:36:35.677957963 +0200 -@@ -14,6 +14,7 @@ - #include "webrtc/common_audio/real_fourier_ooura.h" - #include "webrtc/common_audio/real_fourier_openmax.h" - #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" -+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h" - - namespace webrtc { - -@@ -23,7 +24,15 @@ - - std::unique_ptr RealFourier::Create(int fft_order) { - #if defined(RTC_USE_OPENMAX_DL) -+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__) -+ // x86 CPU detection required. -+ if (WebRtc_GetCPUInfo(kSSE2)) -+ return std::unique_ptr(new RealFourierOpenmax(fft_order)); -+ else -+ return std::unique_ptr(new RealFourierOoura(fft_order)); -+#else - return std::unique_ptr(new RealFourierOpenmax(fft_order)); -+#endif - #else - return std::unique_ptr(new RealFourierOoura(fft_order)); - #endif -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/BUILD.gn 2017-07-01 03:36:35.762956723 +0200 -@@ -117,7 +117,7 @@ - - include_dirs = [ "." ] - -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "BUILDING_V8_SHARED" ] - } - } -@@ -131,14 +131,14 @@ - # This config should be applied to code using the libplatform. - config("libplatform_config") { - include_dirs = [ "include" ] -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "USING_V8_PLATFORM_SHARED" ] - } - } - - # This config should be applied to code using the libbase. - config("libbase_config") { -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "USING_V8_BASE_SHARED" ] - } - libs = [] -@@ -155,7 +155,7 @@ - # This config should only be applied to code using V8 and not any V8 code - # itself. - config("external_config") { -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "USING_V8_SHARED" ] - } - include_dirs = [ "include" ] -@@ -331,6 +331,9 @@ - cflags += [ "/arch:SSE2" ] - } - } -+ if (v8_current_cpu == "x87") { -+ defines += [ "V8_TARGET_ARCH_X87" ] -+ } - if (v8_current_cpu == "x64") { - defines += [ "V8_TARGET_ARCH_X64" ] - if (is_win) { -@@ -2274,7 +2277,7 @@ - - defines = [] - -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "BUILDING_V8_BASE_SHARED" ] - } - -@@ -2364,7 +2367,7 @@ - - configs = [ ":internal_config_base" ] - -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "BUILDING_V8_PLATFORM_SHARED" ] - } - -@@ -2507,7 +2510,26 @@ - } - } - --if (is_component_build) { -+if (v8_build_shared) { -+ shared_library("v8") { -+ sources = [ -+ "src/v8dll-main.cc", -+ ] -+ -+ deps = [ -+ ":v8_dump_build_config", -+ ] -+ -+ public_deps = [ -+ ":v8_base", -+ ":v8_maybe_snapshot", -+ ] -+ -+ configs += [ ":internal_config" ] -+ -+ public_configs = [ ":external_config" ] -+ } -+} else if (is_component_build) { - v8_component("v8") { - sources = [ - "src/v8dll-main.cc", -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/gni/v8.gni qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/gni/v8.gni ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/gni/v8.gni 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/gni/v8.gni 2017-07-01 03:36:35.828955760 +0200 -@@ -30,6 +30,9 @@ - # Enable ECMAScript Internationalization API. Enabling this feature will - # add a dependency on the ICU library. - v8_enable_i18n_support = true -+ -+ # Whether to build V8 as a shared library -+ v8_build_shared = false - } - - if (v8_use_external_startup_data == "") { -@@ -42,6 +45,11 @@ - v8_enable_backtrace = is_debug && !v8_optimized_debug - } - -+if (v8_current_cpu == "x86" || v8_current_cpu == "x87") { -+ # build V8 shared on x86 so we can swap x87 vs. SSE2 builds -+ v8_build_shared = true -+} -+ - # Points to // in v8 stand-alone or to //v8/ in chromium. We need absolute - # paths for all configs in templates as they are shared in different - # subdirectories. -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/make-v8-sse2-gyp.sh qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/make-v8-sse2-gyp.sh ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/make-v8-sse2-gyp.sh 1970-01-01 01:00:00.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/make-v8-sse2-gyp.sh 2017-07-01 03:36:35.895954782 +0200 -@@ -0,0 +1,56 @@ -+#!/bin/sh -+# This script renames the v8 targets to _sse2 names so that they do not conflict -+# with the non-SSE2 versions. -+ -+# Copyright 2016 Kevin Kofler. All rights reserved. -+# Redistribution and use in source and binary forms, with or without -+# modification, are permitted provided that the following conditions are -+# met: -+# -+# * Redistributions of source code must retain the above copyright -+# notice, this list of conditions and the following disclaimer. -+# * Redistributions in binary form must reproduce the above -+# copyright notice, this list of conditions and the following -+# disclaimer in the documentation and/or other materials provided -+# with the distribution. -+# * Neither the name of Google Inc. nor the names of its -+# contributors may be used to endorse or promote products derived -+# from this software without specific prior written permission. -+# -+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+# add comment noting that the file is generated -+echo "# Generated from v8.gyp by make-v8-sse2-gyp.sh" >v8_sse2.gyp -+# rename all target names -+SUBTARGETS=`grep "'target_name': '" v8.gyp | sed -e "s/^.*'target_name': '//g" -e "s/',$//g"` -+SEDS= -+for SUBTARGET in $SUBTARGETS ; do -+ SEDS=$SEDS\ -e\ "s/'$SUBTARGET\(['#]\)/'${SUBTARGET}_sse2\1/g" -+done -+# in addition: -+# * set v8_target_arch to "ia32" (instead of "x87") -+# * rename all actions -+# * fix mksnapshot_exec to match the renamed target -+# * rename the generated snapshot.cc (but not mksnapshot.cc) to snapshot_sse2.cc -+# * rename the generated *libraries.cc to *libraries_sse2.cc -+# * rename the generated *.bin to *_sse2.bin -+# * set product_name and product_dir for the v8_sse2 target -+sed -e "s/^\( 'variables': {\)/\1\n 'v8_target_arch': 'ia32',/g" \ -+ -e "s/\('action_name': '\)/\1v8_sse2_/g" \ -+ $SEDS \ -+ -e "s/\('mksnapshot_exec': '.*mksnapshot\)/\1_sse2/g" \ -+ -e "s#/snapshot\.cc#/snapshot_sse2.cc#g" \ -+ -e "s/libraries\.cc/libraries_sse2.cc/g" \ -+ -e "s/\.bin/_sse2.bin/g" \ -+ -e "s#^\( *\)\('target_name': 'v8_sse2',\)#\1\2\n\1'product_name': 'v8',\n\1'product_dir': '<(PRODUCT_DIR)/lib/sse2',#g" \ -+ v8.gyp >>v8_sse2.gyp -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/src/inspector/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/src/inspector/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/src/inspector/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/src/inspector/BUILD.gn 2017-07-01 03:36:35.895954782 +0200 -@@ -106,7 +106,7 @@ - "/wd4996", # Deprecated function call. - ] - } -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - defines = [ "BUILDING_V8_SHARED" ] - } - } -diff -Nur qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/test/cctest/BUILD.gn qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/test/cctest/BUILD.gn ---- qtwebengine-opensource-src-5.9.1/src/3rdparty/chromium/v8/test/cctest/BUILD.gn 2017-06-20 11:10:02.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/3rdparty/chromium/v8/test/cctest/BUILD.gn 2017-07-01 03:36:35.956953893 +0200 -@@ -335,7 +335,7 @@ - - defines = [] - -- if (is_component_build) { -+ if (is_component_build || v8_build_shared) { - # cctest can't be built against a shared library, so we - # need to depend on the underlying static target in that case. - deps += [ "../..:v8_maybe_snapshot" ] -diff -Nur qtwebengine-opensource-src-5.9.1/src/core/core_module.pro qtwebengine-opensource-src-5.9.1-no-sse2/src/core/core_module.pro ---- qtwebengine-opensource-src-5.9.1/src/core/core_module.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/core/core_module.pro 2017-07-01 03:36:36.017953003 +0200 -@@ -41,6 +41,31 @@ - else: QMAKE_LFLAGS += $$NINJA_LFLAGS - POST_TARGETDEPS += $$NINJA_TARGETDEPS - -+# go through the shared libraries that GN wants to link to -+# ignore the dummy convert_dict shared library used only to get a .pri file -+# add the ones NOT in lib/sse2 to LIBS_PRIVATE -+# don't add those in lib/sse2 that are only replacements for the normal ones -+# collect all shared libraries, non-SSE2 and SSE2, so they can be installed -+for(shlib, NINJA_SOLIBS) { -+ !contains(shlib, .*convert_dict.*) { -+ contains(shlib, .*/lib/sse2/.*) { -+ shlibs_sse2 += $$shlib -+ } else { -+ LIBS_PRIVATE += $$shlib -+ shlibs += $$shlib -+ } -+ } -+} -+ -+# set the shared libraries to be installed -+# add an rpath to their installation location -+shlib_install_path = $$[QT_INSTALL_LIBS]/qtwebengine -+!isEmpty(shlibs) { -+ shlibs.files += $$shlibs -+ shlibs_sse2.files += $$shlibs_sse2 -+ LIBS_PRIVATE += -Wl,--rpath,$$shlib_install_path -+} -+ - - LIBS_PRIVATE += -L$$api_library_path - CONFIG *= no_smart_library_merge -@@ -98,7 +123,12 @@ - locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales - resources.CONFIG += no_check_exist - resources.path = $$[QT_INSTALL_DATA]/resources -- INSTALLS += locales resources -+ # install the shared libraries -+ shlibs.CONFIG += no_check_exist -+ shlibs.path = $$shlib_install_path -+ shlibs_sse2.CONFIG += no_check_exist -+ shlibs_sse2.path = $$shlib_install_path/sse2 -+ INSTALLS += locales resources shlibs shlibs_sse2 - - !use?(system_icu) { - icu.CONFIG += no_check_exist -diff -Nur qtwebengine-opensource-src-5.9.1/src/process/process.pro qtwebengine-opensource-src-5.9.1-no-sse2/src/process/process.pro ---- qtwebengine-opensource-src-5.9.1/src/process/process.pro 2017-06-23 08:29:46.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.1-no-sse2/src/process/process.pro 2017-07-01 03:36:36.017953003 +0200 -@@ -9,6 +9,8 @@ - - SOURCES = main.cpp - -+QMAKE_LFLAGS += -Wl,-rpath-link,$$OUT_PWD/../core/Release -+ - win32 { - SOURCES += \ - support_win.cpp diff --git a/qtwebengine-opensource-src-5.9.2-qt57.patch b/qtwebengine-opensource-src-5.9.2-qt57.patch deleted file mode 100644 index 1c10e4b..0000000 --- a/qtwebengine-opensource-src-5.9.2-qt57.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -ur qtwebengine-opensource-src-5.9.2/src/core/web_contents_adapter.cpp qtwebengine-opensource-src-5.9.2-qt57/src/core/web_contents_adapter.cpp ---- qtwebengine-opensource-src-5.9.2/src/core/web_contents_adapter.cpp 2017-10-03 11:06:38.000000000 +0200 -+++ qtwebengine-opensource-src-5.9.2-qt57/src/core/web_contents_adapter.cpp 2017-11-16 17:17:51.072511997 +0100 -@@ -1265,7 +1265,15 @@ - } - - const QString &fileName = toQt(dropData.file_description_filename); -+#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - const QString &filePath = d->dndTmpDir->filePath(fileName); -+#else -+ QString filePath = d->dndTmpDir->path(); -+ if (!filePath.isEmpty()) { -+ filePath += QLatin1Char('/'); -+ filePath += fileName; -+ } -+#endif - QFile file(filePath); - if (!file.open(QIODevice::WriteOnly)) { - qWarning("Cannot write temporary file %s.", qUtf8Printable(filePath)); diff --git a/qtwebengine-opensource-src-5.9.3-no-aspirational-scripts.patch b/qtwebengine-opensource-src-5.9.3-no-aspirational-scripts.patch deleted file mode 100644 index 695b25f..0000000 --- a/qtwebengine-opensource-src-5.9.3-no-aspirational-scripts.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff -ur qtwebengine-opensource-src-5.9.3/src/3rdparty/chromium/components/url_formatter/url_formatter.cc qtwebengine-opensource-src-5.9.3-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter.cc ---- qtwebengine-opensource-src-5.9.3/src/3rdparty/chromium/components/url_formatter/url_formatter.cc 2017-11-08 20:13:31.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.3-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter.cc 2017-12-02 03:07:07.447476275 +0100 -@@ -478,39 +478,6 @@ - const icu::UnicodeSet* inclusion_set = uspoof_getInclusionUnicodeSet(status); - allowed_set.addAll(*inclusion_set); - -- // Five aspirational scripts are taken from UTR 31 Table 6 at -- // http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts . -- // Not all the characters of aspirational scripts are suitable for -- // identifiers. Therefore, only characters belonging to -- // [:Identifier_Type=Aspirational:] (listed in 'Status/Type=Aspirational' -- // section at -- // http://www.unicode.org/Public/security/latest/xidmodifications.txt) are -- // are added to the allowed set. The list has to be updated when a new -- // version of Unicode is released. The current version is 9.0.0 and ICU 60 -- // will have Unicode 10.0 data. --#if U_ICU_VERSION_MAJOR_NUM < 60 -- const icu::UnicodeSet aspirational_scripts( -- icu::UnicodeString( -- // Unified Canadian Syllabics -- "[\\u1401-\\u166C\\u166F-\\u167F" -- // Mongolian -- "\\u1810-\\u1819\\u1820-\\u1877\\u1880-\\u18AA" -- // Unified Canadian Syllabics -- "\\u18B0-\\u18F5" -- // Tifinagh -- "\\u2D30-\\u2D67\\u2D7F" -- // Yi -- "\\uA000-\\uA48C" -- // Miao -- "\\U00016F00-\\U00016F44\\U00016F50-\\U00016F7E" -- "\\U00016F8F-\\U00016F9F]", -- -1, US_INV), -- *status); -- allowed_set.addAll(aspirational_scripts); --#else --#error "Update aspirational_scripts per Unicode 10.0" --#endif -- - // U+0338 is included in the recommended set, while U+05F4 and U+2027 are in - // the inclusion set. However, they are blacklisted as a part of Mozilla's - // IDN blacklist (http://kb.mozillazine.org/Network.IDN.blacklist_chars). -diff -ur qtwebengine-opensource-src-5.9.3/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc qtwebengine-opensource-src-5.9.3-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc ---- qtwebengine-opensource-src-5.9.3/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc 2017-11-08 20:13:31.000000000 +0100 -+++ qtwebengine-opensource-src-5.9.3-no-aspirational-scripts/src/3rdparty/chromium/components/url_formatter/url_formatter_unittest.cc 2017-12-02 03:08:51.073912562 +0100 -@@ -102,22 +102,24 @@ - {"xn---123-kbjl2j0bl2k.in", - L"\x0939\x093f\x0928\x094d\x0926\x0940-123.in", true}, - -- // 5 Aspirational scripts -+ // What used to be 5 Aspirational scripts in the earlier versions of UAX 31. -+ // UAX 31 does not define aspirational scripts any more. -+ // See http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts . - // Unifieid Canadian Syllabary -- {"xn--dfe0tte.ca", L"\x1456\x14c2\x14ef.ca", true}, -+ {"xn--dfe0tte.ca", L"\x1456\x14c2\x14ef.ca", false}, - // Tifinagh - {"xn--4ljxa2bb4a6bxb.ma", -- L"\x2d5c\x2d49\x2d3c\x2d49\x2d4f\x2d30\x2d56.ma", true}, -+ L"\x2d5c\x2d49\x2d3c\x2d49\x2d4f\x2d30\x2d56.ma", false}, - // Tifinagh with a disallowed character(U+2D6F) - {"xn--hmjzaby5d5f.ma", L"\x2d5c\x2d49\x2d3c\x2d6f\x2d49\x2d4f.ma", false}, - // Yi -- {"xn--4o7a6e1x64c.cn", L"\xa188\xa320\xa071\xa0b7.cn", true}, -+ {"xn--4o7a6e1x64c.cn", L"\xa188\xa320\xa071\xa0b7.cn", false}, - // Mongolian - 'ordu' (place, camp) -- {"xn--56ec8bp.cn", L"\x1823\x1837\x1833\x1824.cn", true}, -+ {"xn--56ec8bp.cn", L"\x1823\x1837\x1833\x1824.cn", false}, - // Mongolian with a disallowed character - {"xn--95e5de3ds.cn", L"\x1823\x1837\x1804\x1833\x1824.cn", false}, - // Miao/Pollad -- {"xn--2u0fpf0a.cn", L"\U00016f04\U00016f62\U00016f59.cn", true}, -+ {"xn--2u0fpf0a.cn", L"\U00016f04\U00016f62\U00016f59.cn", false}, - - // Script mixing tests - // The following script combinations are allowed. diff --git a/sources b/sources index 61b00bb..d0b675c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (qtwebengine-opensource-src-5.9.3-clean.tar.xz) = fb1c6af02d7cbeef41da5cbe7e56861de3342a538940a997753fae204bdd5386d66b1385fc8450b6a4989e6e2b67e8c4f063e8192181cdc02ff64e0d48dde97e +SHA512 (qtwebengine-everywhere-src-5.10.0-clean.tar.xz) = 0c89061507a7f1541eb9433545f3610f96ac6b6b29dc2527a9bc15c945a0ce33d0d2bd693c9d865639b10a97077192fc387b0a5920e64b7860c576b987899fb2