import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1204192 - IonMonkey: MIPS: Split shareable code to mips-shared in BaselineIC-mips32. r=nbp (eeae38da4e)
- Bug 1204193 - IonMonkey: MIPS: Split shareable code to mips-shared in Bailouts-mips32. r=nbp (f24f496235)
- Bug 1204194 - IonMonkey: MIPS: Split shareable code to mips-shared in MoveEmitter-mips32. r=nbp (5c3bdc2fc2)
- Bug 1204214 - IonMonkey: MIPS: Split shareable code to mips-shared in BaselineCompiler-mips32. r=nbp (01903406d1)
- Bug 1205229 - IonMonkey: MIPS32: Make more CodeGenerator functions can be shared. r=nbp (d437fe618e)
- Bug 1209528 - IonMonkey: MIPS32: Add suffix 'f' for constant float32. r=arai (0f6600c083)
- Bug 1205232 - IonMonkey: MIPS32: Fix rounding of big negative float32 values in Ion. r=bbouvier (4652bb9b7a)
- Bug 1203044 - IonMonkey: MIPS32: Atomics operations should throw on oob access. r=lth (e898b3af95)
- Bug 1205135 - IonMonkey: MIPS: Split shareable code to mips-shared in CodeGenerator-mips32. r=nbp (b6d81b922d)
- readd some missing bits (2aa8c9fafd)
- Bug 1167189: Remove unnecessary checks after infallible allocations. r=bholley (fa7d8b9f7b)
- Bug 1209398 - Make AC_SUBST_SET emit a list of unique items instead of an actual set. r=gps (83e5877882)
- Bug 904572 - Add support for generating clang compilation database; r=glandium,r=gps (ab3e6e62fa)
- Bug 1209398 - Enable the FasterMake backend by default for desktop Firefox builds. r=gps (29f6fb3883)
- Bug 1204719 - Don't create interfaces.manifest files from the build backend. r=gps (5a63e36259)
- Bug 786520 - Install things to $(DIST)/branding from moz.build instead of manual rules in Makefile.ins. r=mshal (652552b547)
- Bug 1160563 - Part 1: Make ANDROID_RES_DIRS a moz.build variable. r=gps (e0719524f8)
- Bug 1159390 - Set sharedUserId in robocop.apk. r=gbrown (dde6716e2d)
- Bug 1160030 - Use TEST_HARNESS_FILES to install Robocop test files. r=froydnj (00cd01c3f2)
- Bug 1160030 - Use TEST_HARNESS_FILES to install Robocop ini files. r=froydnj (66d52518e7)
- Bug 938659 - Part 2: build system changes. r=mfinkle (0833d22ba3)
- Bug 1160563 - Pre: Allow ANDROID_RES_DIRS that are not relative to srcdir. r=gps (0d8a3ce66e)
- Bug 1160563 - Part 2: Make ANDROID_ASSETS_DIRS a moz.build variable. r=gps (9f4c132e2a)
- Bug 1195388 - Part 1: Make ANDROID_APK_{NAME,PACKAGE} moz.build variables. r=gps (4a2fa3fc09)
- Bug 1195388 - Part 2: Add ANDROID_EXTRA_{PACKAGES,RES_DIRS} moz.buildvariables. r=gps (7ad49e355e)
- Bug 1207893 - Change how we track object consumption from the build backend. r=gps (20ccc5b67a)
- Bug 1184405 - Add annotations for tags, file patterns, and test flavos to moz.build to specify tests potentially impacted by source files. r=gps (2db17131cc)
- Bug 1171105 - Ability to aggregate metadata from Files instances; r=glandium (59c8759e61)
- Bug 1184405 - Add a container type to mozbuild with a namedtuple-likeinterface and typed, mutable fields. r=gps (3062dbae71)
- Bug 1138283 - Fix bad documentation around wildcard patterns; r=glandium (5785d3284d)
- Bug 1155816 - part 2 - move EXTRA_*COMPONENTS manifest check to buildbackend time; r=mshal (c539616b45)
- Bug 1161270 - Add source manifest to reftest manifest representation in moz.build.;r=gps,roc (376b080084)
- Bug 1180813 - Use a cache for BuildConfig to improve mach speed. r=gps (d431b1ec23)
- Bug 1207882 - Associate an install target with every ContextDerived object. r=gps (62f63487a7)
- Bug 1126228 - Directory (--directory) argument for |mach warnings-list| and |mach warnings-summary|. r=gps (37a85d904f)
- Bug 1210642 - Allow to pass defines overrides when processing install manifests. r=gps (5eb483dc8d)
- Bug 1210642 - Add support for --silence-missing-directive-warnings for preprocessing within install manifests. r=gps (3a07d30b36)
- Bug 1176642 - Use absolute_import in mozpack; r=glandium (863ab20c4a)
- Bug 1162826 - Properly display full moz.build processing errors when empty KeyError or ValueError are thrown. r=mshal (57e8367680)
- Bug 1184405 - Add a mach command to expose test-deps file info. r=gps (7bcc10679c)
- Bug 1195735, r=zer0 (7fe14224e3)
- Bug 1205166 - IonMonkey: MIPS: Import MIPS64 support into Architecture-mips-shared. r=nbp f=rankov (84e1f9ec5d)
- Bug 1205166 - IonMonkey: MIPS64: Import Architecture-mips64. r=nbp f=rankov (fe173dd5af)
- Bug 1210322 - IonMonkey: MIPS: Rename BaseFloatRegister/s to FloatRegister/sMIPSShared. r=nbp (ac262cbb5d)
- Bug 1205167 - IonMonkey: MIPS64: Import Assembler-mips64. r=nbp f=rankov (079e84ea49)
- Bug 1215555 - Improve simulated OOM testing of ARM assembler buffer and fix bugs r=jolesen (253b976cec)
- Bug 1205167 - IonMonkey: MIPS: Import MIPS64 support into Assembler-mips-shared. r=froydnj f=rankov (94b23ac585)
- Bug 1213146 - IonMonkey: MIPS: Fix build failure caused by bug 1194139. r=nbp (12f7d5d572)
- Bug 1205566 - IonMonkey: MIPS: bailoutCmp32/Ptr optimization. r=nbp (9a40ee80d0)
- Bug 1209873 - IonMonkey; MIPS: Implement memory barrier. r=lth (964535cb6b)
- Bug 1209572 - IonMonkey: MIPS32: Goto done by short jump in convertUInt32ToFloat32. r=nbp (0b388199e7)
- pointer style (312fc6fe4f)
- missing bit of Bug 1140890 - Make sure the first argument cannot bail in between negative zero removal and creating result in substraction, r=nbp (afcc9bfdc7)
- and sync more build scripts with frontend branch
This commit is contained in:
2022-10-05 15:49:48 +08:00
parent d041f9bde0
commit fc52b62763
152 changed files with 6370 additions and 2790 deletions
+43
View File
@@ -0,0 +1,43 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JS_PREFERENCE_FILES += [
'pref/firefox-branding.js',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
BRANDING_FILES += [
'appname.bmp',
'bgintro.bmp',
'branding.nsi',
'clock.bmp',
'document.ico',
'firefox.ico',
'newtab.ico',
'newwindow.ico',
'particles.bmp',
'pbmode.ico',
'pencil-rtl.bmp',
'pencil.bmp',
'wizHeader.bmp',
'wizHeaderRTL.bmp',
'wizWatermark.bmp',
]
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
BRANDING_FILES += [
'background.png',
'disk.icns',
'document.icns',
'dsstore',
'firefox.icns',
]
elif CONFIG['MOZ_WIDGET_GTK']:
BRANDING_FILES += [
'default16.png',
'default32.png',
'default48.png',
'mozicon128.png',
]
-1
View File
@@ -37,7 +37,6 @@ if test -z "$MOZ_ARCH"; then
;;
arm-Darwin)
MOZ_ARCH=toolchain-default
MOZ_THUMB=yes
;;
esac
fi
+14
View File
@@ -355,6 +355,20 @@ fi
AC_SUBST(MOZ_PROGRAM_LDFLAGS)
dnl ASan assumes no symbols are being interposed, and when that happens,
dnl it's not happy with it. Unconveniently, since Firefox is exporting
dnl libffi symbols and Gtk+3 pulls system libffi via libwayland-client,
dnl system libffi interposes libffi symbols that ASan assumes are in
dnl libxul, so it barfs about buffer overflows.
dnl Using -Wl,-Bsymbolic ensures no exported symbol can be interposed.
if test -n "$GCC_USE_GNU_LD"; then
case "$LDFLAGS" in
*-fsanitize=address*)
LDFLAGS="$LDFLAGS -Wl,-Bsymbolic"
;;
esac
fi
])
dnl GCC and clang will fail if given an unknown warning option like -Wfoobar.
+10 -3
View File
@@ -28,7 +28,7 @@ define([AC_SUBST_SET],
[ifdef([AC_SUBST_SET_$1], ,
[define([AC_SUBST_SET_$1], )dnl
AC_DIVERT_PUSH(MOZ_DIVERSION_SUBST)dnl
(''' $1 ''', set(r''' [$]$1 '''.split()))
(''' $1 ''', unique_list(r''' [$]$1 '''.split()))
AC_DIVERT_POP()dnl
])])])])
@@ -129,6 +129,13 @@ topsrcdir = os.path.normpath(topsrcdir)
topobjdir = os.path.abspath(os.path.dirname(<<<__file__>>>))
def unique_list(l):
result = []
for i in l:
if l not in result:
result.append(i)
return result
dnl All defines and substs are stored with an additional space at the beginning
dnl and at the end of the string, to avoid any problem with values starting or
dnl ending with quotes.
@@ -228,9 +235,9 @@ define([MOZ_BUILD_BACKEND],
BUILD_BACKENDS="RecursiveMake"
MOZ_ARG_ENABLE_STRING(build-backend,
[ --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake}
[ --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake,CompileDB}
Enable additional build backends],
[ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])
AC_SUBST_LIST([BUILD_BACKENDS])
AC_SUBST_SET([BUILD_BACKENDS])
])
+108
View File
@@ -0,0 +1,108 @@
dnl This Source Code Form is subject to the terms of the Mozilla Public
dnl License, v. 2.0. If a copy of the MPL was not distributed with this
dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
AC_DEFUN([MOZ_IOS_PATH_PROG],
[
changequote({,})
_prog_name=ifelse($2, {}, `echo $1 | tr "[:upper:]" "[:lower:]"`, $2)
changequote([,])
AC_CACHE_CHECK([for $_prog_name in iOS SDK],
ac_cv_ios_path_$1,
[
_path=`xcrun --sdk $ios_sdk --find $_prog_name 2>/dev/null`
_res=$?
if test $_res -ne 0; then
AC_MSG_ERROR([Could not find '$_prog_name' in the iOS SDK])
fi
ac_cv_ios_path_$1=$_path
])
$1="${ac_cv_ios_path_$1}$3"
])
AC_DEFUN([MOZ_IOS_SDK],
[
MOZ_ARG_WITH_STRING(ios-sdk,
[ --with-ios-sdk=TYPE
Type of iOS SDK to use (iphonesimulator, iphoneos)
and optionally version (like iphoneos8.2)],
ios_sdk=$withval)
MOZ_ARG_ENABLE_STRING(ios-target,
[ --enable-ios-target=VER (default=8.0)
Set the minimum iOS version needed at runtime],
[_IOS_TARGET=$enableval])
_IOS_TARGET_DEFAULT=8.0
case "$target" in
arm*-apple-darwin*)
if test -z "$ios_sdk" -o "$ios_sdk" = "yes"; then
ios_sdk=iphoneos
fi
case "$ios_sdk" in
iphoneos*)
ios_target_arg="-miphoneos-version-min"
;;
*)
AC_MSG_ERROR([Only 'iphoneos' SDKs are valid when targeting iOS device, don't know what to do with '$ios_sdk'.])
;;
esac
;;
*-apple-darwin*)
ios_target_arg="-mios-simulator-version-min"
case "$ios_sdk" in
# Empty SDK is okay, this might be an OS X desktop build.
""|iphonesimulator*)
;;
# Default to iphonesimulator
yes)
ios_sdk=iphonesimulator
;;
*)
AC_MSG_ERROR([Only 'iphonesimulator' SDKs are valid when targeting iOS simulator.])
;;
esac
;;
esac
if test -n "$ios_sdk"; then
if test -z "$_IOS_TARGET"; then
_IOS_TARGET=$_IOS_TARGET_DEFAULT
ios_target_arg="${ios_target_arg}=${_IOS_TARGET}"
fi
# Ensure that xcrun knows where this SDK is.
ios_sdk_path=`xcrun --sdk $ios_sdk --show-sdk-path 2>/dev/null`
_ret=$?
if test $_ret -ne 0; then
AC_MSG_ERROR([iOS SDK '$ios_sdk' could not be found.])
fi
MOZ_IOS=1
export HOST_CC=clang
export HOST_CXX=clang++
# Add isysroot, arch, and ios target arguments
case "$target_cpu" in
arm*)
ARGS="-arch armv7"
;;
*)
# Unfortunately simulator builds need this.
export CROSS_COMPILE=1
;;
esac
ARGS=" $ARGS -isysroot $ios_sdk_path $ios_target_arg"
# Now find our tools
MOZ_IOS_PATH_PROG(CC, clang, $ARGS)
MOZ_IOS_PATH_PROG(CXX, clang++, $ARGS)
export CPP="$CC -E"
export LD="$CXX"
MOZ_IOS_PATH_PROG(AR)
MOZ_IOS_PATH_PROG(AS, as, $ARGS)
MOZ_IOS_PATH_PROG(OTOOL)
MOZ_IOS_PATH_PROG(STRIP)
export PKG_CONFIG_PATH=${ios_sdk_path}/usr/lib/pkgconfig/
fi
AC_SUBST(MOZ_IOS)
])
+3 -3
View File
@@ -19,9 +19,9 @@ files. e.g.::
with Files('**/Makefile.in'):
BUG_COMPONENT = ('Core', 'Build Config')
This working example says, *for all Makefile.in files in all directories
in this one and underneath it, set the Bugzilla component to
Core :: Build Config*.
This working example says, *for all Makefile.in files in every directory
underneath this one - including this directory - set the Bugzilla
component to Core :: Build Config*.
For more info, read the
:ref:`docs on Files <mozbuild_subcontext_Files>`.
+1
View File
@@ -85,6 +85,7 @@ MACH_MODULES = [
'python/mozbuild/mozbuild/mach_commands.py',
'python/mozbuild/mozbuild/backend/mach_commands.py',
'python/mozbuild/mozbuild/compilation/codecomplete.py',
'python/mozbuild/mozbuild/compilation/database.py',
'python/mozbuild/mozbuild/frontend/mach_commands.py',
'services/common/tests/mach_commands.py',
'testing/luciddream/mach_commands.py',
@@ -2,6 +2,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.roboexample.test"
#ifdef MOZ_ANDROID_SHARED_ID
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
#endif
android:versionCode="1"
android:versionName="1.0" >
+9 -42
View File
@@ -2,18 +2,13 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
mobile-tests := mobile/android/base/tests
mobile-tests := mobile/android/tests/browser/robocop
TESTPATH := $(topsrcdir)/$(mobile-tests)
dir-tests := $(DEPTH)/$(mobile-tests)
ANDROID_APK_NAME := robocop-debug
ANDROID_EXTRA_JARS += \
$(srcdir)/robotium-solo-4.3.1.jar \
$(NULL)
ANDROID_ASSETS_DIR := $(TESTPATH)/assets
_JAVA_HARNESS := \
Actions.java \
Assert.java \
@@ -40,57 +35,29 @@ java-tests := \
$(wildcard $(TESTPATH)/components/*.java) \
$(wildcard $(TESTPATH)/helpers/*.java)
PP_TARGETS += manifest
manifest := $(srcdir)/AndroidManifest.xml.in
manifest_TARGET := AndroidManifest.xml
PP_TARGETS += manifest
manifest := $(srcdir)/AndroidManifest.xml.in
manifest_TARGET := export
manifest_FLAGS += \
-DMOZ_ANDROID_SHARED_ID='$(ANDROID_PACKAGE_NAME).sharedID' \
-DMOZ_ANDROID_SHARED_ACCOUNT_TYPE='$(ANDROID_PACKAGE_NAME)_sync' \
$(NULL)
ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
# Install robocop configs and helper
INSTALL_TARGETS += robocop
robocop_TARGET := libs
robocop_DEST := $(CURDIR)
robocop_FILES := \
$(TESTPATH)/robocop.ini \
$(TESTPATH)/robocop_autophone.ini \
$(NULL)
robocop-deps := $(notdir $(robocop_FILES))
ROBOCOP_FILES := \
$(wildcard $(TESTPATH)/*.html) \
$(wildcard $(TESTPATH)/*.jpg) \
$(wildcard $(TESTPATH)/*.sjs) \
$(wildcard $(TESTPATH)/test*.js) \
$(wildcard $(TESTPATH)/robocop*.js) \
$(wildcard $(TESTPATH)/*.xml) \
$(wildcard $(TESTPATH)/*.ogg) \
$(wildcard $(TESTPATH)/*.mp4) \
$(wildcard $(TESTPATH)/*.webm) \
$(wildcard $(TESTPATH)/*.swf) \
$(wildcard $(TESTPATH)/reader_mode_pages) \
$(NULL)
ROBOCOP_DEST = $(DEPTH)/_tests/testing/mochitest/tests/robocop/
INSTALL_TARGETS += ROBOCOP
GARBAGE += \
AndroidManifest.xml \
$(robocop-deps) \
$(testconstants-dep) \
$(NULL)
JAVAFILES += \
$(java-harness) \
$(java-tests) \
$(robocop-deps) \
$(testconstants-dep) \
$(NULL)
include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
GENERATED_DIRS += $(dir-tests)
# The test APK needs to know the contents of the target APK while not
# being linked against them. This is a best effort to avoid getting
# out of sync with base's build config.
+1 -1
View File
@@ -9,4 +9,4 @@ from the original download found at:
http://code.google.com/p/robotium/
Firefox for Android developers should read the documentation in
mobile/android/base/tests/README.rst.
mobile/android/tests/browser/robocop/README.rst.
+23 -11
View File
@@ -6,15 +6,27 @@
DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
main = add_android_eclipse_project('Robocop', OBJDIR + '/AndroidManifest.xml')
main.package_name = 'org.mozilla.roboexample.test'
main.res = SRCDIR + '/res'
main.recursive_make_targets += [OBJDIR + '/AndroidManifest.xml']
main.extra_jars += [SRCDIR + '/robotium-solo-4.3.1.jar']
main.assets = TOPSRCDIR + '/mobile/android/base/tests/assets'
main.referenced_projects += ['Fennec']
base = '/mobile/android/tests/browser/robocop/'
main.add_classpathentry('harness', SRCDIR,
dstdir='harness/org/mozilla/gecko')
main.add_classpathentry('src', TOPSRCDIR + '/mobile/android/base/tests',
dstdir='src/org/mozilla/gecko/tests')
ANDROID_APK_NAME = 'robocop-debug'
ANDROID_APK_PACKAGE = 'org.mozilla.roboexample.test'
ANDROID_ASSETS_DIRS += [base + 'assets']
TEST_HARNESS_FILES.testing.mochitest += [
base + 'robocop.ini',
base + 'robocop_autophone.ini',
]
TEST_HARNESS_FILES.testing.mochitest.tests.robocop += [base + x for x in [
'*.html',
'*.jpg',
'*.mp4',
'*.ogg',
'*.sjs',
'*.swf',
'*.webm',
'*.xml',
'robocop*.js',
'test*.js',
]]
# The ** below preserves directory structure.
TEST_HARNESS_FILES.testing.mochitest.tests.robocop.reader_mode_pages += [base + 'reader_mode_pages/**']
+1 -3
View File
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME := sutAgentAndroid
include $(topsrcdir)/config/config.mk
JAVAFILES = \
AlertLooperThread.java \
@@ -25,6 +25,4 @@ ANDROID_EXTRA_JARS = \
$(srcdir)/network-libs/jmdns.jar \
$(NULL)
include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME := FenCP
include $(topsrcdir)/config/config.mk
JAVAFILES = \
DirCursor.java \
@@ -11,6 +11,4 @@ JAVAFILES = \
FileCursor.java \
$(NULL)
include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
@@ -3,3 +3,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME = 'FenCP'
ANDROID_APK_PACKAGE = 'org.mozilla.fencp'
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME := FfxCP
include $(topsrcdir)/config/config.mk
JAVAFILES = \
DirCursor.java \
@@ -11,6 +11,4 @@ JAVAFILES = \
FileCursor.java \
$(NULL)
include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
@@ -3,3 +3,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME = 'FfxCP'
ANDROID_APK_PACKAGE = 'org.mozilla.ffxcp'
+3
View File
@@ -3,3 +3,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME = 'sutAgentAndroid'
ANDROID_APK_PACKAGE = 'com.mozilla.SUTAgentAndroid'
@@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME := Watcher
include $(topsrcdir)/config/config.mk
JAVAFILES = \
IWatcherService.java \
@@ -12,6 +12,4 @@ JAVAFILES = \
WatcherService.java \
$(NULL)
include $(topsrcdir)/config/rules.mk
tools:: $(ANDROID_APK_NAME).apk
@@ -3,3 +3,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
ANDROID_APK_NAME = 'Watcher'
ANDROID_APK_PACKAGE = 'com.mozilla.watcher'
+4 -1
View File
@@ -25,8 +25,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
'mobile/sutagent/android/watcher',
'mobile/sutagent/android/ffxcp',
'mobile/sutagent/android/fencp',
'mobile/robocop',
]
if not CONFIG['MOZ_B2GDROID']:
TEST_DIRS += [
'mobile/robocop',
]
for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME',
'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID',
+41 -9
View File
@@ -75,8 +75,8 @@ def main():
# Run |nm|. Options:
# -u: show only undefined symbols
# -C: demangle symbol names
# -l: show a filename and line number for each undefined symbol
cmd = ['nm', '-u', '-C', '-l', args.file]
# -A: show an object filename for each undefined symbol
cmd = ['nm', '-u', '-C', '-A', args.file]
lines = subprocess.check_output(cmd, universal_newlines=True,
stderr=subprocess.PIPE).split('\n')
@@ -112,26 +112,30 @@ def main():
# This regexp matches the relevant lines in the output of |nm|, which look
# like the following.
#
# U malloc /path/to/objdir/dist/include/js/Utility.h:142
# js/src/libjs_static.a:jsutil.o: U malloc
#
alloc_fns_re = r'U (' + r'|'.join(alloc_fns) + r').*\/([\w\.]+):(\d+)$'
alloc_fns_re = r'([^:/ ]+):\s+U (' + r'|'.join(alloc_fns) + r')'
# This tracks which allocation/free functions have been seen in jsutil.cpp.
jsutil_cpp = set([])
# Would it be helpful to emit detailed line number information after a failure?
emit_line_info = False
for line in lines:
m = re.search(alloc_fns_re, line)
if m is None:
continue
fn = m.group(1)
filename = m.group(2)
linenum = m.group(3)
if filename == 'jsutil.cpp':
filename = m.group(1)
fn = m.group(2)
if filename == 'jsutil.o':
jsutil_cpp.add(fn)
else:
# An allocation is present in a non-special file. Fail!
fail("'" + fn + "' present at " + filename + ':' + linenum)
fail("'" + fn + "' present in " + filename)
# Try to give more precise information about the offending code.
emit_line_info = True
# Check that all functions we expect are used in jsutil.cpp. (This will
@@ -147,6 +151,34 @@ def main():
fail('unexpected allocation fns used in jsutil.cpp: ' +
', '.join(jsutil_cpp))
# If we found any improper references to allocation functions, try to use
# DWARF debug info to get more accurate line number information about the
# bad calls. This is a lot slower than 'nm -A', and it is not always
# precise when building with --enable-optimized.
if emit_line_info:
print('check_vanilla_allocations.py: Source lines with allocation calls:')
print('check_vanilla_allocations.py: Accurate in unoptimized builds; jsutil.cpp expected.')
# Run |nm|. Options:
# -u: show only undefined symbols
# -C: demangle symbol names
# -l: show line number information for each undefined symbol
cmd = ['nm', '-u', '-C', '-l', args.file]
lines = subprocess.check_output(cmd, universal_newlines=True,
stderr=subprocess.PIPE).split('\n')
# This regexp matches the relevant lines in the output of |nm -l|,
# which look like the following.
#
# U malloc jsutil.cpp:117
#
alloc_lines_re = r'U ((' + r'|'.join(alloc_fns) + r').*)\s+(\S+:\d+)$'
for line in lines:
m = re.search(alloc_lines_re, line)
if m:
print('check_vanilla_allocations.py:', m.group(1), 'called at', m.group(3))
if has_failed:
sys.exit(1)
+176
View File
@@ -0,0 +1,176 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# /!\ Please make sure to update the following comment when you touch this
# file. Thank you /!\
# The traditional Mozilla build system relied on going through the entire
# build tree a number of times with different targets, and many of the
# things happening at each step required other things happening in previous
# steps without any documentation of those dependencies.
#
# This new build system tries to start afresh by establishing what files or
# operations are needed for the build, and applying the necessary rules to
# have those in place, relying on make dependencies to get them going.
#
# As of writing, only building non-compiled parts of Firefox is supported
# here (a few other things are also left out). This is a starting point, with
# the intent to grow this build system to make it more complete.
#
# This file contains rules and dependencies to get things working. The intent
# is for a Makefile to define some dependencies and variables, and include
# this file. What needs to be defined there, and ends up being generated by
# python/mozbuild/mozbuild/backend/fastermake.py is the following:
# - TOPSRCDIR/TOPOBJDIR, respectively the top source directory and the top
# object directory
# - PYTHON, the path to the python executable
# - ACDEFINES, which contains a set of -Dvar=name to be used during
# preprocessing
# - MOZ_CHROME_FILE_FORMAT, which defines whether to use file copies or
# symbolic links
# - JAR_MN_TARGETS, which defines the targets to use for jar manifest
# processing, see further below
# - INSTALL_MANIFESTS, which defines the list of base directories handled
# by install manifests, see further below
# - MANIFEST_TARGETS, which defines the file paths of chrome manifests, see
# further below
#
# A convention used between this file and the Makefile including it is that
# global Make variables names are uppercase, while "local" Make variables
# applied to specific targets are lowercase.
# Targets to be triggered for a default build
default: $(addprefix install-,$(INSTALL_MANIFESTS))
default: $(addprefix jar-,$(JAR_MN_TARGETS))
# Explicit files to be built for a default build
default: $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS))
default: $(TOPOBJDIR)/dist/bin/greprefs.js
default: $(TOPOBJDIR)/dist/bin/platform.ini
default: $(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini
# Targets from the recursive make backend to be built for a default build
default: $(TOPOBJDIR)/config/makefiles/xpidl/xpidl
.PHONY: FORCE
# Extra define to trigger some workarounds. We should strive to limit the
# use of those. As of writing the only ones are in
# toolkit/content/buildconfig.html and browser/locales/jar.mn.
ACDEFINES += -DBUILD_FASTER
# Generic rule to fall back to the recursive make backend
$(TOPOBJDIR)/%: FORCE
$(MAKE) -C $(dir $@) $(notdir $@)
# Files under the faster/ sub-directory, however, are not meant to use the
# fallback
$(TOPOBJDIR)/faster/%: ;
# And files under dist/ are meant to be copied from their first dependency
# if there is no other rule.
$(TOPOBJDIR)/dist/%:
rm -f $@
cp $< $@
# Install files using install manifests
#
# The list of base directories is given in INSTALL_MANIFESTS. The
# corresponding install manifests are named correspondingly, with forward
# slashes replaced with underscores, and prefixed with `install_`. That is,
# the install manifest for `dist/bin` would be `install_dist_bin`.
$(addprefix install-,$(INSTALL_MANIFESTS)): install-%: $(TOPOBJDIR)/config/buildid
@# For now, force preprocessed files to be reprocessed every time.
@# The overhead is not that big, and this avoids waiting for proper
@# support for defines tracking in process_install_manifest.
@touch install_$(subst /,_,$*)
$(PYTHON) -m mozbuild.action.process_install_manifest \
--no-remove \
--no-remove-empty-directories \
$(TOPOBJDIR)/$* \
-DAB_CD=en-US \
-DMOZ_APP_BUILDID=$(shell cat $(TOPOBJDIR)/config/buildid) \
$(ACDEFINES) \
$(MOZ_DEBUG_DEFINES) \
install_$(subst /,_,$*)
# Install files from jar manifests. Ideally, they would be using install
# manifests, but the code to read jar manifests and emit appropriate
# install manifests is not there yet.
# Things missing:
# - DEFINES from config/config.mk
# - L10N
# - -e when USE_EXTENSION_MANIFEST is set in moz.build
#
# The list given in JAR_MN_TARGETS corresponds to the list of `jar-%` targets
# to be processed, with the `jar-` prefix stripped.
# The Makefile is expected to specify the source jar manifest as a dependency
# to each target. There is no expectation that the `jar-%` target name matches
# the source file name in any way. For example:
# JAR_MN_TARGETS = foo
# jar-foo: /path/to/some/jar.mn
# Additionally, extra defines can be specified for the processing of the jar
# manifest by settig the `defines` variable specifically for the given target.
# For example:
# jar-foo: defines = -Dqux=foo
# The default base path where files are going to be installed is `dist/bin`.
# It is possible to use a different path by setting the `install_target`
# variable. For example:
# jar-foo: install_target = dist/bin/foo
# When processing jar manifests, relative paths given inside a jar manifest
# can be resolved from an object directory. The default path for that object
# directory is the translation of the jar manifest directory path from the
# source directory to the object directory. That is, for
# $(TOPSRCDIR)/path/to/jar.mn, the default would be $(TOPOBJDIR)/path/to.
# In case a different path must be used for the object directory, the `objdir`
# variable can be set. For example:
# jar-foo: objdir=/some/other/path
jar-%: objdir ?= $(dir $(patsubst $(TOPSRCDIR)%,$(TOPOBJDIR)%,$<))
jar-%: install_target ?= dist/bin
jar-%:
cd $(objdir) && \
$(PYTHON) -m mozbuild.action.jar_maker \
-j $(TOPOBJDIR)/$(install_target)/chrome \
-t $(TOPSRCDIR) \
-f $(MOZ_CHROME_FILE_FORMAT) \
-c $(dir $<)/en-US \
-DAB_CD=en-US \
$(defines) \
$(ACDEFINES) \
$(MOZ_DEBUG_DEFINES) \
$<
# Create some chrome manifests
# This rule is forced to run every time because it may be updating files that
# already exit.
#
# The list of chrome manifests is given in MANIFEST_TARGETS, relative to the
# top object directory. The content for those manifests is given in the
# `content` variable associated with the target. For example:
# MANIFEST_TARGETS = foo
# $(TOPOBJDIR)/foo: content = "manifest foo.manifest" "manifest bar.manifest"
$(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)): FORCE
$(PYTHON) -m mozbuild.action.buildlist \
$@ \
$(content)
# ============================================================================
# Below is a set of additional dependencies and variables used to build things
# that are not supported by data in moz.build.
# GENERATED_FILES are not supported yet, and even if they were, the
# dependencies are missing information.
$(foreach p,linux osx windows,jar-browser-themes-$(p)-jar.mn): \
jar-browser-themes-%-jar.mn: \
$(TOPOBJDIR)/browser/themes/%/tab-selected-end.svg \
$(TOPOBJDIR)/browser/themes/%/tab-selected-start.svg
# Files to build with the recursive backend and simply copy
$(TOPOBJDIR)/dist/bin/greprefs.js: $(TOPOBJDIR)/modules/libpref/greprefs.js
$(TOPOBJDIR)/dist/bin/platform.ini: $(TOPOBJDIR)/toolkit/xre/platform.ini
$(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini: $(TOPOBJDIR)/webapprt/webapprt.ini
# The xpidl target in config/makefiles/xpidl requires the install manifest for
# dist/idl to have been processed.
$(TOPOBJDIR)/config/makefiles/xpidl/xpidl: $(TOPOBJDIR)/install-dist_idl
+31 -9
View File
@@ -16,15 +16,19 @@ endif #} JAVAFILES
ifdef ANDROID_APK_NAME #{
android_res_dirs := $(addprefix $(srcdir)/,$(or $(ANDROID_RES_DIRS),res))
$(if $(ANDROID_APK_PACKAGE),,$(error Missing ANDROID_APK_PACKAGE with ANDROID_APK_NAME))
android_res_dirs := $(or $(ANDROID_RES_DIRS),$(srcdir)/res)
_ANDROID_RES_FLAG := $(addprefix -S ,$(android_res_dirs))
_ANDROID_ASSETS_FLAG := $(addprefix -A ,$(ANDROID_ASSETS_DIR))
_ANDROID_ASSETS_FLAG := $(if $(ANDROID_ASSETS_DIRS),$(addprefix -A ,$(ANDROID_ASSETS_DIRS)))
android_manifest := $(or $(ANDROID_MANIFEST_FILE),AndroidManifest.xml)
GENERATED_DIRS += classes
GENERATED_DIRS += classes generated
generated_r_java := generated/$(subst .,/,$(ANDROID_APK_PACKAGE))/R.java
classes.dex: $(call mkdir_deps,classes)
classes.dex: R.java
classes.dex: $(generated_r_java)
classes.dex: $(ANDROID_APK_NAME).ap_
classes.dex: $(ANDROID_EXTRA_JARS)
classes.dex: $(JAVAFILES)
@@ -38,17 +42,35 @@ classes.dex: $(JAVAFILES)
# all causes Make to treat the target differently, in a way that
# defeats our dependencies.
R.java: .aapt.deps ;
$(generated_r_java): .aapt.deps ;
$(ANDROID_APK_NAME).ap_: .aapt.deps ;
# This uses the fact that Android resource directories list all
# resource files one subdirectory below the parent resource directory.
android_res_files := $(wildcard $(addsuffix /*,$(wildcard $(addsuffix /*,$(android_res_dirs)))))
.aapt.deps: $(android_manifest) $(android_res_files) $(wildcard $(ANDROID_ASSETS_DIR))
# An extra package like org.example.app generates dependencies like:
# generated/org/example/app/R.java: .aapt.deps ;
# classes.dex: generated/org/example/app/R.java
# GARBAGE: generated/org/example/app/R.java
$(foreach extra_package,$(ANDROID_EXTRA_PACKAGES), \
$(eval generated/$(subst .,/,$(extra_package))/R.java: .aapt.deps ;) \
$(eval classes.dex: generated/$(subst .,/,$(extra_package))/R.java) \
$(eval GARBAGE: generated/$(subst .,/,$(extra_package))/R.java) \
)
# aapt flag -m: 'make package directories under location specified by -J'.
# The --extra-package list is colon separated.
.aapt.deps: $(android_manifest) $(android_res_files) $(wildcard $(ANDROID_ASSETS_DIRS))
@$(TOUCH) $@
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar $(_ANDROID_RES_FLAG) $(_ANDROID_ASSETS_FLAG) \
-J ${@D} \
--custom-package $(ANDROID_APK_PACKAGE) \
--non-constant-id \
--auto-add-overlay \
$(if $(ANDROID_EXTRA_PACKAGES),--extra-packages $(subst $(NULL) ,:,$(strip $(ANDROID_EXTRA_PACKAGES)))) \
$(if $(ANDROID_EXTRA_RES_DIRS),$(addprefix -S ,$(ANDROID_EXTRA_RES_DIRS))) \
-m \
-J ${@D}/generated \
-F $(ANDROID_APK_NAME).ap_
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
@@ -60,10 +82,10 @@ $(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
$(DEBUG_JARSIGNER) $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@
$(ZIPALIGN) -f 4 $< $@
GARBAGE += \
R.java \
$(generated_r_java) \
classes.dex \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
+8 -2
View File
@@ -53,8 +53,14 @@ endif
chrome_manifests := @chrome_manifests@
%/interfaces.manifest: Makefile
$(call py_action,buildlist,$@ $(foreach xpt,$(filter $*/%,$(registered_xpt_files)),'interfaces $(notdir $(xpt))'))
interfaces_manifests := @interfaces_manifests@
xpidl_modules := @xpidl_modules@
xpt_files := @xpt_files@
registered_xpt_files := @registered_xpt_files@
xpt_files := $(registered_xpt_files) @xpt_files@
@xpidl_rules@
@@ -62,7 +68,7 @@ depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
GARBAGE += $(xpt_files) $(depends_files)
xpidl:: $(xpt_files) $(chrome_manifests)
xpidl:: $(xpt_files) $(chrome_manifests) $(interfaces_manifests)
$(xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir))
-8
View File
@@ -1159,14 +1159,6 @@ endif
################################################################################
# Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
ifneq (,$(filter %.js,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
ifeq (,$(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
ifndef NO_JS_MANIFEST
$(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
endif
endif
endif
ifdef EXTRA_COMPONENTS
misc:: $(EXTRA_COMPONENTS)
ifndef NO_DIST_INSTALL
+2
View File
@@ -3937,6 +3937,8 @@ esac
case "$MOZ_BUILD_APP" in
browser)
AC_DEFINE(MOZ_PHOENIX)
BUILD_BACKENDS="$BUILD_BACKENDS FasterMake"
;;
xulrunner)
+5
View File
@@ -123,6 +123,11 @@ class ModuleCompiler
bool finishGeneratingFunction(AsmFunction& func, CodeGenerator& codegen,
const AsmJSFunctionLabels& labels)
{
// If we have hit OOM then invariants which we assert below may not
// hold, so abort now.
if (masm().oom())
return false;
// Code range
unsigned line = func.lineno();
unsigned column = func.column();
+2 -3
View File
@@ -2211,14 +2211,13 @@ NeedNegativeZeroCheck(MDefinition* def)
// Figure out the order in which the addition's operands will
// execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
// definitions for us so that this just requires comparing ids.
MDefinition* first = use_def->toAdd()->getOperand(0);
MDefinition* second = use_def->toAdd()->getOperand(1);
MDefinition* first = use_def->toAdd()->lhs();
MDefinition* second = use_def->toAdd()->rhs();
if (first->id() > second->id()) {
MDefinition* temp = first;
first = second;
second = temp;
}
// Negative zero checks can be removed on the first executed
// operand only if it is guaranteed the second executed operand
// will produce a value other than -0. While the second is
+21 -11
View File
@@ -2169,7 +2169,7 @@ Assembler::as_BranchPool(uint32_t value, RepatchLabel* label, ARMBuffer::PoolEnt
if (label->bound()) {
BufferOffset dest(label);
as_b(dest.diffB<BOffImm>(ret), c, ret);
} else {
} else if (!oom()) {
label->use(ret.getOffset());
}
#ifdef JS_DISASM_ARM
@@ -2369,14 +2369,12 @@ Assembler::as_b(BOffImm off, Condition c, Label* documentation)
BufferOffset
Assembler::as_b(Label* l, Condition c)
{
if (m_buffer.oom()) {
BufferOffset ret;
return ret;
}
if (l->bound()) {
// Note only one instruction is emitted here, the NOP is overwritten.
BufferOffset ret = allocBranchInst();
if (oom())
return BufferOffset();
as_b(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
#ifdef JS_DISASM_ARM
spewBranch(m_buffer.getInstOrNull(ret), l);
@@ -2384,6 +2382,9 @@ Assembler::as_b(Label* l, Condition c)
return ret;
}
if (oom())
return BufferOffset();
int32_t old;
BufferOffset ret;
if (l->used()) {
@@ -2400,6 +2401,10 @@ Assembler::as_b(Label* l, Condition c)
BOffImm inv;
ret = as_b(inv, c, l);
}
if (oom())
return BufferOffset();
DebugOnly<int32_t> check = l->use(ret.getOffset());
MOZ_ASSERT(check == old);
return ret;
@@ -2436,14 +2441,12 @@ Assembler::as_bl(BOffImm off, Condition c, Label* documentation)
BufferOffset
Assembler::as_bl(Label* l, Condition c)
{
if (m_buffer.oom()) {
BufferOffset ret;
return ret;
}
if (l->bound()) {
// Note only one instruction is emitted here, the NOP is overwritten.
BufferOffset ret = allocBranchInst();
if (oom())
return BufferOffset();
as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
#ifdef JS_DISASM_ARM
spewBranch(m_buffer.getInstOrNull(ret), l);
@@ -2451,6 +2454,9 @@ Assembler::as_bl(Label* l, Condition c)
return ret;
}
if (oom())
return BufferOffset();
int32_t old;
BufferOffset ret;
// See if the list was empty :(
@@ -2468,6 +2474,10 @@ Assembler::as_bl(Label* l, Condition c)
BOffImm inv;
ret = as_bl(inv, c, l);
}
if (oom())
return BufferOffset();
DebugOnly<int32_t> check = l->use(ret.getOffset());
MOZ_ASSERT(check == old);
return ret;
@@ -23,7 +23,7 @@ uint32_t GetMIPSFlags()
static uint32_t flags = 0;
if (isSet)
return flags;
#ifdef JS_SIMULATOR_MIPS32
#if defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
isSet = true;
flags |= HWCAP_FPU;
return flags;
@@ -46,7 +46,7 @@ uint32_t GetMIPSFlags()
#endif
return flags;
#endif // JS_SIMULATOR_MIPS32
#endif // JS_SIMULATOR_MIPS32 || JS_SIMULATOR_MIPS64
}
bool hasFPU()
@@ -17,11 +17,13 @@
// gcc appears to use _mips_hard_float to denote
// that the target is a hard-float target.
#ifdef _mips_hard_float
#define JS_CODEGEN_MIPS32_HARDFP
#define JS_CODEGEN_MIPS_HARDFP
#endif
#if _MIPS_SIM == _ABIO32
#if (defined(_MIPS_SIM) && (_MIPS_SIM == _ABIO32)) || defined(JS_SIMULATOR_MIPS32)
#define USES_O32_ABI
#elif (defined(_MIPS_SIM) && (_MIPS_SIM == _ABI64)) || defined(JS_SIMULATOR_MIPS64)
#define USES_N64_ABI
#else
#error "Unsupported ABI"
#endif
@@ -73,6 +75,7 @@ class Registers
a1 = r5,
a2 = r6,
a3 = r7,
#if defined(USES_O32_ABI)
t0 = r8,
t1 = r9,
t2 = r10,
@@ -81,6 +84,24 @@ class Registers
t5 = r13,
t6 = r14,
t7 = r15,
ta0 = t4,
ta1 = t5,
ta2 = t6,
ta3 = t7,
#elif defined(USES_N64_ABI)
a4 = r8,
a5 = r9,
a6 = r10,
a7 = r11,
t0 = r12,
t1 = r13,
t2 = r14,
t3 = r15,
ta0 = a4,
ta1 = a5,
ta2 = a6,
ta3 = a7,
#endif
s0 = r16,
s1 = r17,
s2 = r18,
@@ -107,10 +128,10 @@ class Registers
uintptr_t r;
};
static const char * const RegNames[];
static const char* GetName(Code code) {
MOZ_ASSERT(code < Total);
static const char * const Names[] = REGISTERS_NAMES;
return Names[code];
return RegNames[code];
}
static const char* GetName(Encoding i) {
return GetName(Code(i));
@@ -122,12 +143,12 @@ class Registers
static const Encoding Invalid = invalid_reg;
static const uint32_t Total = 32;
static const uint32_t Allocatable = REGISTERS_ALLOCATABLE;
static const uint32_t Allocatable;
typedef uint32_t SetType;
static const SetType AllMask = 0xffffffff;
static const SetType SharedArgRegMask = (1 << a0) | (1 << a1) | (1 << a2) | (1 << a3);
static const SetType ArgRegMask = REGISTERS_ARGREGMASK;
static const SetType ArgRegMask;
static const SetType VolatileMask =
(1 << Registers::v0) |
@@ -140,10 +161,10 @@ class Registers
(1 << Registers::t1) |
(1 << Registers::t2) |
(1 << Registers::t3) |
(1 << Registers::t4) |
(1 << Registers::t5) |
(1 << Registers::t6) |
(1 << Registers::t7);
(1 << Registers::ta0) |
(1 << Registers::ta1) |
(1 << Registers::ta2) |
(1 << Registers::ta3);
// We use this constant to save registers when entering functions. This
// is why $ra is added here even though it is not "Non Volatile".
@@ -179,11 +200,11 @@ class Registers
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
// Registers returned from a JS -> JS call.
static const SetType JSCallMask = REGISTERS_JSCALLMASK;
static const SetType JSCallMask;
// Registers returned from a JS -> C call.
static const SetType SharedCallMask = (1 << Registers::v0);
static const SetType CallMask = REGISTERS_CALLMASK;
static const SetType CallMask;
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
@@ -202,7 +223,7 @@ class Registers
// Smallest integer type that can hold a register bitmask.
typedef uint32_t PackedRegisterMask;
class BaseFloatRegisters
class FloatRegistersMIPSShared
{
public:
enum FPRegisterID {
@@ -265,13 +286,13 @@ class BaseFloatRegisters
template <typename T>
class TypedRegisterSet;
class BaseFloatRegister
class FloatRegisterMIPSShared
{
public:
bool isInt32x4() const { return false; }
bool isFloat32x4() const { return false; }
typedef BaseFloatRegisters::SetType SetType;
typedef FloatRegistersMIPSShared::SetType SetType;
static uint32_t SetSize(SetType x) {
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
@@ -480,12 +480,31 @@ AssemblerMIPSShared::as_addiu(Register rd, Register rs, int32_t j)
return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
}
BufferOffset
AssemblerMIPSShared::as_daddu(Register rd, Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode());
}
BufferOffset
AssemblerMIPSShared::as_daddiu(Register rd, Register rs, int32_t j)
{
MOZ_ASSERT(Imm16::IsInSignedRange(j));
return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode());
}
BufferOffset
AssemblerMIPSShared::as_subu(Register rd, Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsubu(Register rd, Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode());
}
BufferOffset
AssemblerMIPSShared::as_mult(Register rs, Register rt)
{
@@ -498,6 +517,18 @@ AssemblerMIPSShared::as_multu(Register rs, Register rt)
return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
}
BufferOffset
AssemblerMIPSShared::as_dmult(Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode());
}
BufferOffset
AssemblerMIPSShared::as_dmultu(Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode());
}
BufferOffset
AssemblerMIPSShared::as_div(Register rs, Register rt)
{
@@ -510,6 +541,18 @@ AssemblerMIPSShared::as_divu(Register rs, Register rt)
return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
}
BufferOffset
AssemblerMIPSShared::as_ddiv(Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode());
}
BufferOffset
AssemblerMIPSShared::as_ddivu(Register rs, Register rt)
{
return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode());
}
BufferOffset
AssemblerMIPSShared::as_mul(Register rd, Register rs, Register rt)
{
@@ -531,12 +574,32 @@ AssemblerMIPSShared::as_sll(Register rd, Register rt, uint16_t sa)
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsll(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(sa < 32);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsll32(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(31 < sa && sa < 64);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode());
}
BufferOffset
AssemblerMIPSShared::as_sllv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsllv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode());
}
BufferOffset
AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa)
{
@@ -544,12 +607,32 @@ AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa)
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsrl(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(sa < 32);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsrl32(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(31 < sa && sa < 64);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode());
}
BufferOffset
AssemblerMIPSShared::as_srlv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsrlv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode());
}
BufferOffset
AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa)
{
@@ -557,12 +640,32 @@ AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa)
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsra(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(sa < 32);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsra32(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(31 < sa && sa < 64);
return writeInst(InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode());
}
BufferOffset
AssemblerMIPSShared::as_srav(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
}
BufferOffset
AssemblerMIPSShared::as_dsrav(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode());
}
BufferOffset
AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa)
{
@@ -570,12 +673,32 @@ AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa)
return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
}
BufferOffset
AssemblerMIPSShared::as_drotr(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(sa < 32);
return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode());
}
BufferOffset
AssemblerMIPSShared::as_drotr32(Register rd, Register rt, uint16_t sa)
{
MOZ_ASSERT(31 < sa && sa < 64);
return writeInst(InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode());
}
BufferOffset
AssemblerMIPSShared::as_rotrv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
}
BufferOffset
AssemblerMIPSShared::as_drotrv(Register rd, Register rt, Register rs)
{
return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode());
}
// Load and store instructions
BufferOffset
AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off)
@@ -607,6 +730,12 @@ AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off)
return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_lwu(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_lwl(Register rd, Register rs, int16_t off)
{
@@ -619,6 +748,30 @@ AssemblerMIPSShared::as_lwr(Register rd, Register rs, int16_t off)
return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_ldl(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_ldr(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off)
{
@@ -649,6 +802,30 @@ AssemblerMIPSShared::as_swr(Register rd, Register rs, int16_t off)
return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_sdl(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode());
}
BufferOffset
AssemblerMIPSShared::as_sdr(Register rd, Register rs, int16_t off)
{
return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode());
}
// Move from HI/LO register.
BufferOffset
AssemblerMIPSShared::as_mfhi(Register rd)
@@ -725,6 +902,12 @@ AssemblerMIPSShared::as_clz(Register rd, Register rs)
return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
}
BufferOffset
AssemblerMIPSShared::as_dclz(Register rd, Register rs)
{
return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode());
}
BufferOffset
AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
{
@@ -734,6 +917,33 @@ AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t siz
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
}
BufferOffset
AssemblerMIPSShared::as_dins(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
Register rd;
rd = Register::FromCode(pos + size - 1);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode());
}
BufferOffset
AssemblerMIPSShared::as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 && pos + size <= 64);
Register rd;
rd = Register::FromCode(pos + size - 1 - 32);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode());
}
BufferOffset
AssemblerMIPSShared::as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 && pos + size > 32 && pos + size <= 64);
Register rd;
rd = Register::FromCode(pos + size - 1 - 32);
return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode());
}
BufferOffset
AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
{
@@ -743,6 +953,46 @@ AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t siz
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
}
// Sign extend
BufferOffset
AssemblerMIPSShared::as_seb(Register rd, Register rt)
{
return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode());
}
BufferOffset
AssemblerMIPSShared::as_seh(Register rd, Register rt)
{
return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode());
}
BufferOffset
AssemblerMIPSShared::as_dext(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 63);
Register rd;
rd = Register::FromCode(size - 1);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode());
}
BufferOffset
AssemblerMIPSShared::as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 && pos + size <= 64);
Register rd;
rd = Register::FromCode(size - 1 - 32);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode());
}
BufferOffset
AssemblerMIPSShared::as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size)
{
MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 && pos + size > 32 && pos + size <= 64);
Register rd;
rd = Register::FromCode(size - 1);
return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode());
}
// FP instructions
BufferOffset
AssemblerMIPSShared::as_ld(FloatRegister fd, Register base, int32_t off)
@@ -796,6 +1046,30 @@ AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs)
return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
}
BufferOffset
AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs)
{
return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode());
}
BufferOffset
AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs)
{
return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode());
}
BufferOffset
AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs)
{
return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode());
}
BufferOffset
AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs)
{
return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode());
}
// FP convert instructions
BufferOffset
AssemblerMIPSShared::as_ceilws(FloatRegister fd, FloatRegister fs)
@@ -845,6 +1119,12 @@ AssemblerMIPSShared::as_truncwd(FloatRegister fd, FloatRegister fs)
return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
}
BufferOffset
AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs)
{
return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode());
}
BufferOffset
AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs)
{
+99 -44
View File
@@ -30,14 +30,18 @@ static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 };
static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 };
static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 };
static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 };
static MOZ_CONSTEXPR_VAR Register a4 = { Registers::ta0 };
static MOZ_CONSTEXPR_VAR Register a5 = { Registers::ta1 };
static MOZ_CONSTEXPR_VAR Register a6 = { Registers::ta2 };
static MOZ_CONSTEXPR_VAR Register a7 = { Registers::ta3 };
static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 };
static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 };
static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 };
static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 };
static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 };
static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 };
static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 };
static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 };
static MOZ_CONSTEXPR_VAR Register t4 = { Registers::ta0 };
static MOZ_CONSTEXPR_VAR Register t5 = { Registers::ta1 };
static MOZ_CONSTEXPR_VAR Register t6 = { Registers::ta2 };
static MOZ_CONSTEXPR_VAR Register t7 = { Registers::ta3 };
static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 };
static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 };
static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 };
@@ -85,10 +89,12 @@ static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0;
static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1;
static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2;
static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3;
static MOZ_CONSTEXPR_VAR Register IntArgReg4 = a4;
static MOZ_CONSTEXPR_VAR Register IntArgReg5 = a5;
static MOZ_CONSTEXPR_VAR Register IntArgReg6 = a6;
static MOZ_CONSTEXPR_VAR Register IntArgReg7 = a7;
static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin
static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin
static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = CALL_TEMP_NON_ARG_REGS;
static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs);
static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1;
@@ -246,6 +252,12 @@ enum Opcode {
op_blezl = 22 << OpcodeShift,
op_bgtzl = 23 << OpcodeShift,
op_daddi = 24 << OpcodeShift,
op_daddiu = 25 << OpcodeShift,
op_ldl = 26 << OpcodeShift,
op_ldr = 27 << OpcodeShift,
op_special2 = 28 << OpcodeShift,
op_special3 = 31 << OpcodeShift,
@@ -256,17 +268,24 @@ enum Opcode {
op_lbu = 36 << OpcodeShift,
op_lhu = 37 << OpcodeShift,
op_lwr = 38 << OpcodeShift,
op_lwu = 39 << OpcodeShift,
op_sb = 40 << OpcodeShift,
op_sh = 41 << OpcodeShift,
op_swl = 42 << OpcodeShift,
op_sw = 43 << OpcodeShift,
op_sdl = 44 << OpcodeShift,
op_sdr = 45 << OpcodeShift,
op_swr = 46 << OpcodeShift,
op_ll = 48 << OpcodeShift,
op_lwc1 = 49 << OpcodeShift,
op_ldc1 = 53 << OpcodeShift,
op_ld = 55 << OpcodeShift,
op_sc = 56 << OpcodeShift,
op_swc1 = 57 << OpcodeShift,
op_sdc1 = 61 << OpcodeShift
op_sdc1 = 61 << OpcodeShift,
op_sd = 63 << OpcodeShift,
};
enum RSField {
@@ -274,9 +293,11 @@ enum RSField {
// cop1 encoding of RS field.
rs_mfc1 = 0 << RSShift,
rs_one = 1 << RSShift,
rs_dmfc1 = 1 << RSShift,
rs_cfc1 = 2 << RSShift,
rs_mfhc1 = 3 << RSShift,
rs_mtc1 = 4 << RSShift,
rs_dmtc1 = 5 << RSShift,
rs_ctc1 = 6 << RSShift,
rs_mthc1 = 7 << RSShift,
rs_bc1 = 8 << RSShift,
@@ -315,10 +336,18 @@ enum FunctionField {
ff_mfhi = 16,
ff_mflo = 18,
ff_dsllv = 20,
ff_dsrlv = 22,
ff_dsrav = 23,
ff_mult = 24,
ff_multu = 25,
ff_div = 26,
ff_divu = 27,
ff_dmult = 28,
ff_dmultu = 29,
ff_ddiv = 30,
ff_ddivu = 31,
ff_add = 32,
ff_addu = 33,
@@ -331,6 +360,10 @@ enum FunctionField {
ff_slt = 42,
ff_sltu = 43,
ff_dadd = 44,
ff_daddu = 45,
ff_dsub = 46,
ff_dsubu = 47,
ff_tge = 48,
ff_tgeu = 49,
@@ -338,15 +371,29 @@ enum FunctionField {
ff_tltu = 51,
ff_teq = 52,
ff_tne = 54,
ff_dsll = 56,
ff_dsrl = 58,
ff_dsra = 59,
ff_dsll32 = 60,
ff_dsrl32 = 62,
ff_dsra32 = 63,
// special2 encoding of function field.
ff_mul = 2,
ff_clz = 32,
ff_clo = 33,
ff_dclz = 36,
// special3 encoding of function field.
ff_ext = 0,
ff_dextm = 1,
ff_dextu = 2,
ff_dext = 3,
ff_ins = 4,
ff_dinsm = 5,
ff_dinsu = 6,
ff_dins = 7,
ff_bshfl = 32,
// cop1 encoding of function field.
ff_add_fmt = 0,
@@ -811,12 +858,19 @@ class AssemblerMIPSShared : public AssemblerShared
// Arithmetic instructions
BufferOffset as_addu(Register rd, Register rs, Register rt);
BufferOffset as_addiu(Register rd, Register rs, int32_t j);
BufferOffset as_daddu(Register rd, Register rs, Register rt);
BufferOffset as_daddiu(Register rd, Register rs, int32_t j);
BufferOffset as_subu(Register rd, Register rs, Register rt);
BufferOffset as_dsubu(Register rd, Register rs, Register rt);
BufferOffset as_mult(Register rs, Register rt);
BufferOffset as_multu(Register rs, Register rt);
BufferOffset as_dmult(Register rs, Register rt);
BufferOffset as_dmultu(Register rs, Register rt);
BufferOffset as_div(Register rs, Register rt);
BufferOffset as_divu(Register rs, Register rt);
BufferOffset as_mul(Register rd, Register rs, Register rt);
BufferOffset as_ddiv(Register rs, Register rt);
BufferOffset as_ddivu(Register rs, Register rt);
// Logical instructions
BufferOffset as_and(Register rd, Register rs, Register rt);
@@ -832,13 +886,25 @@ class AssemblerMIPSShared : public AssemblerShared
// Shift instructions
// as_sll(zero, zero, x) instructions are reserved as nop
BufferOffset as_sll(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsll(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa);
BufferOffset as_sllv(Register rd, Register rt, Register rs);
BufferOffset as_dsllv(Register rd, Register rt, Register rs);
BufferOffset as_srl(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa);
BufferOffset as_srlv(Register rd, Register rt, Register rs);
BufferOffset as_dsrlv(Register rd, Register rt, Register rs);
BufferOffset as_sra(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsra(Register rd, Register rt, uint16_t sa);
BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa);
BufferOffset as_srav(Register rd, Register rt, Register rs);
BufferOffset as_rotr(Register rd, Register rt, uint16_t sa);
BufferOffset as_rotrv(Register rd, Register rt, Register rs);
BufferOffset as_dsrav(Register rd, Register rt, Register rs);
BufferOffset as_drotr(Register rd, Register rt, uint16_t sa);
BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa);
BufferOffset as_drotrv(Register rd, Register rt, Register rs);
// Load and store instructions
BufferOffset as_lb(Register rd, Register rs, int16_t off);
@@ -846,13 +912,22 @@ class AssemblerMIPSShared : public AssemblerShared
BufferOffset as_lh(Register rd, Register rs, int16_t off);
BufferOffset as_lhu(Register rd, Register rs, int16_t off);
BufferOffset as_lw(Register rd, Register rs, int16_t off);
BufferOffset as_lwu(Register rd, Register rs, int16_t off);
BufferOffset as_lwl(Register rd, Register rs, int16_t off);
BufferOffset as_lwr(Register rd, Register rs, int16_t off);
BufferOffset as_ll(Register rd, Register rs, int16_t off);
BufferOffset as_ld(Register rd, Register rs, int16_t off);
BufferOffset as_ldl(Register rd, Register rs, int16_t off);
BufferOffset as_ldr(Register rd, Register rs, int16_t off);
BufferOffset as_sb(Register rd, Register rs, int16_t off);
BufferOffset as_sh(Register rd, Register rs, int16_t off);
BufferOffset as_sw(Register rd, Register rs, int16_t off);
BufferOffset as_swl(Register rd, Register rs, int16_t off);
BufferOffset as_swr(Register rd, Register rs, int16_t off);
BufferOffset as_sc(Register rd, Register rs, int16_t off);
BufferOffset as_sd(Register rd, Register rs, int16_t off);
BufferOffset as_sdl(Register rd, Register rs, int16_t off);
BufferOffset as_sdr(Register rd, Register rs, int16_t off);
// Move from HI/LO register.
BufferOffset as_mfhi(Register rd);
@@ -872,8 +947,19 @@ class AssemblerMIPSShared : public AssemblerShared
// Bit twiddling.
BufferOffset as_clz(Register rd, Register rs);
BufferOffset as_dclz(Register rd, Register rs);
BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size);
BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size);
// Sign extend
BufferOffset as_seb(Register rd, Register rt);
BufferOffset as_seh(Register rd, Register rt);
// FP instructions
@@ -891,6 +977,10 @@ class AssemblerMIPSShared : public AssemblerShared
BufferOffset as_mtc1(Register rt, FloatRegister fs);
BufferOffset as_mfc1(Register rt, FloatRegister fs);
BufferOffset as_mthc1(Register rt, FloatRegister fs);
BufferOffset as_mfhc1(Register rt, FloatRegister fs);
BufferOffset as_dmtc1(Register rt, FloatRegister fs);
BufferOffset as_dmfc1(Register rt, FloatRegister fs);
public:
// FP convert instructions
@@ -970,7 +1060,8 @@ class AssemblerMIPSShared : public AssemblerShared
public:
static bool SupportsFloatingPoint() {
#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_SIMULATOR_MIPS32)
#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \
defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
return true;
#else
return false;
@@ -1234,42 +1325,6 @@ class InstJump : public Instruction
}
};
static const uint32_t NumIntArgRegs = NUM_INT_ARG_REGS;
static inline bool
GetIntArgReg(uint32_t usedArgSlots, Register* out)
{
if (usedArgSlots < NumIntArgRegs) {
*out = Register::FromCode(a0.code() + usedArgSlots);
return true;
}
return false;
}
// Get a register in which we plan to put a quantity that will be used as an
// integer argument. This differs from GetIntArgReg in that if we have no more
// actual argument registers to use we will fall back on using whatever
// CallTempReg* don't overlap the argument registers, and only fail once those
// run out too.
static inline bool
GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out)
{
// NOTE: We can't properly determine which regs are used if there are
// float arguments. If this is needed, we will have to guess.
MOZ_ASSERT(usedFloatArgs == 0);
if (GetIntArgReg(usedIntArgs, out))
return true;
// Unfortunately, we have to assume things about the point at which
// GetIntArgReg returns false, because we need to know how many registers it
// can allocate.
usedIntArgs -= NumIntArgRegs;
if (usedIntArgs >= NumCallTempNonArgRegs)
return false;
*out = CallTempNonArgRegs[usedIntArgs];
return true;
}
} // namespace jit
} // namespace js
@@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips-shared/Bailouts-mips-shared.h"
#include "jscntxt.h"
#include "jscompartment.h"
using namespace js;
using namespace js::jit;
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
InvalidationBailoutStack* bailout)
: machine_(bailout->machine())
{
framePointer_ = (uint8_t*) bailout->fp();
topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
attachOnJitActivation(activations);
uint8_t* returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex* osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
snapshotOffset_ = osiIndex->snapshotOffset();
}
@@ -4,8 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips32_Bailouts_mips32_h
#define jit_mips32_Bailouts_mips32_h
#ifndef jit_mips_shared_Bailouts_mips_shared_h
#define jit_mips_shared_Bailouts_mips_shared_h
#include "jit/Bailouts.h"
#include "jit/JitCompartment.h"
@@ -74,4 +74,4 @@ class BailoutStack
} // namespace jit
} // namespace js
#endif /* jit_mips32_Bailouts_mips32_h */
#endif /* jit_mips_shared_Bailouts_mips_shared_h */
@@ -0,0 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips-shared/BaselineCompiler-mips-shared.h"
using namespace js;
using namespace js::jit;
BaselineCompilerMIPSShared::BaselineCompilerMIPSShared(JSContext* cx, TempAllocator& alloc,
JSScript* script)
: BaselineCompilerShared(cx, alloc, script)
{
}
@@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips_shared_BaselineCompiler_mips_shared_h
#define jit_mips_shared_BaselineCompiler_mips_shared_h
#include "jit/shared/BaselineCompiler-shared.h"
namespace js {
namespace jit {
class BaselineCompilerMIPSShared : public BaselineCompilerShared
{
protected:
BaselineCompilerMIPSShared(JSContext* cx, TempAllocator& alloc, JSScript* script);
};
} // namespace jit
} // namespace js
#endif /* jit_mips_shared_BaselineCompiler_mips_shared_h */
@@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/BaselineIC.h"
#include "jit/SharedICHelpers.h"
using namespace js;
using namespace js::jit;
namespace js {
namespace jit {
bool
ICCompare_Double::Compiler::generateStubCode(MacroAssembler& masm)
{
Label failure, isNaN;
masm.ensureDouble(R0, FloatReg0, &failure);
masm.ensureDouble(R1, FloatReg1, &failure);
Register dest = R0.scratchReg();
Assembler::DoubleCondition doubleCond = JSOpToDoubleCondition(op);
masm.ma_cmp_set_double(dest, FloatReg0, FloatReg1, doubleCond);
masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
} // namespace jit
} // namespace js
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,259 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips_shared_CodeGenerator_mips_shared_h
#define jit_mips_shared_CodeGenerator_mips_shared_h
#include "jit/shared/CodeGenerator-shared.h"
namespace js {
namespace jit {
class OutOfLineBailout;
class OutOfLineTableSwitch;
class CodeGeneratorMIPSShared : public CodeGeneratorShared
{
friend class MoveResolverMIPS;
CodeGeneratorMIPSShared* thisFromCtor() {
return this;
}
protected:
NonAssertingLabel deoptLabel_;
inline Address ToAddress(const LAllocation& a);
inline Address ToAddress(const LAllocation* a);
MoveOperand toMoveOperand(LAllocation a) const;
template <typename T1, typename T2>
void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
Label bail;
masm.branch32(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
template<typename T>
void bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot* snapshot) {
if (lhs.getTag() == Operand::REG)
bailoutCmp32(c, lhs.toReg(), rhs, snapshot);
else if (lhs.getTag() == Operand::MEM)
bailoutCmp32(c, lhs.toAddress(), rhs, snapshot);
else
MOZ_CRASH("Invalid operand tag.");
}
template<typename T>
void bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot* snapshot) {
Label bail;
masm.branchTest32(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
template <typename T1, typename T2>
void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
Label bail;
masm.branchPtr(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) {
Label bail;
masm.branchTestPtr(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
Label bail;
masm.branchTest32(Assembler::Zero, reg, Imm32(0xFF), &bail);
bailoutFrom(&bail, snapshot);
}
void bailoutFrom(Label* label, LSnapshot* snapshot);
void bailout(LSnapshot* snapshot);
protected:
bool generateOutOfLineCode();
template <typename T>
void branchToBlock(Register lhs, T rhs, MBasicBlock* mir, Assembler::Condition cond)
{
mir = skipTrivialBlocks(mir);
Label* label = mir->lir()->label();
if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) {
// Note: the backedge is initially a jump to the next instruction.
// It will be patched to the target block's label during link().
RepatchLabel rejoin;
CodeOffsetJump backedge;
Label skip;
masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
backedge = masm.backedgeJump(&rejoin);
masm.bind(&rejoin);
masm.bind(&skip);
if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry)))
MOZ_CRASH();
} else {
masm.ma_b(lhs, rhs, label, cond);
}
}
void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
MBasicBlock* mir, Assembler::DoubleCondition cond);
// Emits a branch that directs control flow to the true block if |cond| is
// true, and the false block if |cond| is false.
template <typename T>
void emitBranch(Register lhs, T rhs, Assembler::Condition cond,
MBasicBlock* mirTrue, MBasicBlock* mirFalse)
{
if (isNextBlock(mirFalse->lir())) {
branchToBlock(lhs, rhs, mirTrue, cond);
} else {
branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond));
jumpToBlock(mirTrue);
}
}
void testZeroEmitBranch(Assembler::Condition cond, Register reg,
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
{
emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse);
}
public:
// Instruction visitors.
virtual void visitMinMaxD(LMinMaxD* ins);
virtual void visitMinMaxF(LMinMaxF* ins);
virtual void visitAbsD(LAbsD* ins);
virtual void visitAbsF(LAbsF* ins);
virtual void visitSqrtD(LSqrtD* ins);
virtual void visitSqrtF(LSqrtF* ins);
virtual void visitAddI(LAddI* ins);
virtual void visitSubI(LSubI* ins);
virtual void visitBitNotI(LBitNotI* ins);
virtual void visitBitOpI(LBitOpI* ins);
virtual void visitMulI(LMulI* ins);
virtual void visitDivI(LDivI* ins);
virtual void visitDivPowTwoI(LDivPowTwoI* ins);
virtual void visitModI(LModI* ins);
virtual void visitModPowTwoI(LModPowTwoI* ins);
virtual void visitModMaskI(LModMaskI* ins);
virtual void visitPowHalfD(LPowHalfD* ins);
virtual void visitShiftI(LShiftI* ins);
virtual void visitUrshD(LUrshD* ins);
virtual void visitClzI(LClzI* ins);
virtual void visitTestIAndBranch(LTestIAndBranch* test);
virtual void visitCompare(LCompare* comp);
virtual void visitCompareAndBranch(LCompareAndBranch* comp);
virtual void visitTestDAndBranch(LTestDAndBranch* test);
virtual void visitTestFAndBranch(LTestFAndBranch* test);
virtual void visitCompareD(LCompareD* comp);
virtual void visitCompareF(LCompareF* comp);
virtual void visitCompareDAndBranch(LCompareDAndBranch* comp);
virtual void visitCompareFAndBranch(LCompareFAndBranch* comp);
virtual void visitBitAndAndBranch(LBitAndAndBranch* lir);
virtual void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir);
virtual void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir);
virtual void visitNotI(LNotI* ins);
virtual void visitNotD(LNotD* ins);
virtual void visitNotF(LNotF* ins);
virtual void visitMathD(LMathD* math);
virtual void visitMathF(LMathF* math);
virtual void visitFloor(LFloor* lir);
virtual void visitFloorF(LFloorF* lir);
virtual void visitCeil(LCeil* lir);
virtual void visitCeilF(LCeilF* lir);
virtual void visitRound(LRound* lir);
virtual void visitRoundF(LRoundF* lir);
virtual void visitTruncateDToInt32(LTruncateDToInt32* ins);
virtual void visitTruncateFToInt32(LTruncateFToInt32* ins);
// Out of line visitors.
void visitOutOfLineBailout(OutOfLineBailout* ool);
protected:
virtual ValueOperand ToOutValue(LInstruction* ins) = 0;
void memoryBarrier(MemoryBarrierBits barrier);
public:
CodeGeneratorMIPSShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
void visitValue(LValue* value);
void visitDouble(LDouble* ins);
void visitFloat32(LFloat32* ins);
void visitGuardShape(LGuardShape* guard);
void visitGuardObjectGroup(LGuardObjectGroup* guard);
void visitGuardClass(LGuardClass* guard);
void visitNegI(LNegI* lir);
void visitNegD(LNegD* lir);
void visitNegF(LNegF* lir);
void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
void visitMemoryBarrier(LMemoryBarrier* ins);
void generateInvalidateEpilogue();
protected:
void visitEffectiveAddress(LEffectiveAddress* ins);
void visitUDivOrMod(LUDivOrMod* ins);
public:
// Unimplemented SIMD instructions
void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); }
void visitInt32x4(LInt32x4* ins) { MOZ_CRASH("NYI"); }
void visitFloat32x4(LFloat32x4* ins) { MOZ_CRASH("NYI"); }
void visitSimdReinterpretCast(LSimdReinterpretCast* ins) { MOZ_CRASH("NYI"); }
void visitSimdExtractElementI(LSimdExtractElementI* ins) { MOZ_CRASH("NYI"); }
void visitSimdExtractElementF(LSimdExtractElementF* ins) { MOZ_CRASH("NYI"); }
void visitSimdSignMaskX4(LSimdSignMaskX4* ins) { MOZ_CRASH("NYI"); }
void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir) { MOZ_CRASH("NYI"); }
void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir) { MOZ_CRASH("NYI"); }
void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir) { MOZ_CRASH("NYI"); }
};
// An out-of-line bailout thunk.
class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorMIPSShared>
{
LSnapshot* snapshot_;
uint32_t frameSize_;
public:
OutOfLineBailout(LSnapshot* snapshot, uint32_t frameSize)
: snapshot_(snapshot),
frameSize_(frameSize)
{ }
void accept(CodeGeneratorMIPSShared* codegen);
LSnapshot* snapshot() const {
return snapshot_;
}
};
} // namespace jit
} // namespace js
#endif /* jit_mips_shared_CodeGenerator_mips_shared_h */
@@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips-shared/MoveEmitter-mips-shared.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
void
MoveEmitterMIPSShared::emit(const MoveResolver& moves)
{
if (moves.numCycles()) {
// Reserve stack for cycle resolution
masm.reserveStack(moves.numCycles() * sizeof(double));
pushedAtCycle_ = masm.framePushed();
}
for (size_t i = 0; i < moves.numMoves(); i++)
emit(moves.getMove(i));
}
Address
MoveEmitterMIPSShared::cycleSlot(uint32_t slot, uint32_t subslot) const
{
int32_t offset = masm.framePushed() - pushedAtCycle_;
MOZ_ASSERT(Imm16::IsInSignedRange(offset));
return Address(StackPointer, offset + slot * sizeof(double) + subslot);
}
int32_t
MoveEmitterMIPSShared::getAdjustedOffset(const MoveOperand& operand)
{
MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
if (operand.base() != StackPointer)
return operand.disp();
// Adjust offset if stack pointer has been moved.
return operand.disp() + masm.framePushed() - pushedAtStart_;
}
Address
MoveEmitterMIPSShared::getAdjustedAddress(const MoveOperand& operand)
{
return Address(operand.base(), getAdjustedOffset(operand));
}
Register
MoveEmitterMIPSShared::tempReg()
{
spilledReg_ = SecondScratchReg;
return SecondScratchReg;
}
void
MoveEmitterMIPSShared::emitMove(const MoveOperand& from, const MoveOperand& to)
{
if (from.isGeneralReg()) {
// Second scratch register should not be moved by MoveEmitter.
MOZ_ASSERT(from.reg() != spilledReg_);
if (to.isGeneralReg())
masm.movePtr(from.reg(), to.reg());
else if (to.isMemory())
masm.storePtr(from.reg(), getAdjustedAddress(to));
else
MOZ_CRASH("Invalid emitMove arguments.");
} else if (from.isMemory()) {
if (to.isGeneralReg()) {
masm.loadPtr(getAdjustedAddress(from), to.reg());
} else if (to.isMemory()) {
masm.loadPtr(getAdjustedAddress(from), tempReg());
masm.storePtr(tempReg(), getAdjustedAddress(to));
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
} else if (from.isEffectiveAddress()) {
if (to.isGeneralReg()) {
masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg());
} else if (to.isMemory()) {
masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg());
masm.storePtr(tempReg(), getAdjustedAddress(to));
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
}
void
MoveEmitterMIPSShared::emitFloat32Move(const MoveOperand& from, const MoveOperand& to)
{
// Ensure that we can use ScratchFloat32Reg in memory move.
MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloat32Reg);
MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloat32Reg);
if (from.isFloatReg()) {
if (to.isFloatReg()) {
masm.moveFloat32(from.floatReg(), to.floatReg());
} else if (to.isGeneralReg()) {
// This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.moveFromFloat32(from.floatReg(), to.reg());
} else {
MOZ_ASSERT(to.isMemory());
masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
}
} else if (to.isFloatReg()) {
MOZ_ASSERT(from.isMemory());
masm.loadFloat32(getAdjustedAddress(from), to.floatReg());
} else if (to.isGeneralReg()) {
MOZ_ASSERT(from.isMemory());
// This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.loadPtr(getAdjustedAddress(from), to.reg());
} else {
MOZ_ASSERT(from.isMemory());
MOZ_ASSERT(to.isMemory());
masm.loadFloat32(getAdjustedAddress(from), ScratchFloat32Reg);
masm.storeFloat32(ScratchFloat32Reg, getAdjustedAddress(to));
}
}
void
MoveEmitterMIPSShared::emit(const MoveOp& move)
{
const MoveOperand& from = move.from();
const MoveOperand& to = move.to();
if (move.isCycleEnd() && move.isCycleBegin()) {
// A fun consequence of aliased registers is you can have multiple
// cycles at once, and one can end exactly where another begins.
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
completeCycle(from, to, move.type(), move.cycleEndSlot());
return;
}
if (move.isCycleEnd()) {
MOZ_ASSERT(inCycle_);
completeCycle(from, to, move.type(), move.cycleEndSlot());
MOZ_ASSERT(inCycle_ > 0);
inCycle_--;
return;
}
if (move.isCycleBegin()) {
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
inCycle_++;
}
switch (move.type()) {
case MoveOp::FLOAT32:
emitFloat32Move(from, to);
break;
case MoveOp::DOUBLE:
emitDoubleMove(from, to);
break;
case MoveOp::INT32:
MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
case MoveOp::GENERAL:
emitMove(from, to);
break;
default:
MOZ_CRASH("Unexpected move type");
}
}
void
MoveEmitterMIPSShared::assertDone()
{
MOZ_ASSERT(inCycle_ == 0);
}
void
MoveEmitterMIPSShared::finish()
{
assertDone();
masm.freeStack(masm.framePushed() - pushedAtStart_);
}
@@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips_shared_MoveEmitter_mips_shared_h
#define jit_mips_shared_MoveEmitter_mips_shared_h
#include "jit/MacroAssembler.h"
#include "jit/MoveResolver.h"
namespace js {
namespace jit {
class MoveEmitterMIPSShared
{
protected:
uint32_t inCycle_;
MacroAssembler& masm;
// Original stack push value.
uint32_t pushedAtStart_;
// These store stack offsets to spill locations, snapshotting
// codegen->framePushed_ at the time they were allocated. They are -1 if no
// stack space has been allocated for that particular spill.
int32_t pushedAtCycle_;
int32_t pushedAtSpill_;
// These are registers that are available for temporary use. They may be
// assigned InvalidReg. If no corresponding spill space has been assigned,
// then these registers do not need to be spilled.
Register spilledReg_;
FloatRegister spilledFloatReg_;
void assertDone();
Register tempReg();
FloatRegister tempFloatReg();
Address cycleSlot(uint32_t slot, uint32_t subslot) const;
int32_t getAdjustedOffset(const MoveOperand& operand);
Address getAdjustedAddress(const MoveOperand& operand);
void emitMove(const MoveOperand& from, const MoveOperand& to);
void emitFloat32Move(const MoveOperand& from, const MoveOperand& to);
virtual void emitDoubleMove(const MoveOperand& from, const MoveOperand& to) = 0;
virtual void breakCycle(const MoveOperand& from, const MoveOperand& to,
MoveOp::Type type, uint32_t slot) = 0;
virtual void completeCycle(const MoveOperand& from, const MoveOperand& to,
MoveOp::Type type, uint32_t slot) = 0;
void emit(const MoveOp& move);
public:
MoveEmitterMIPSShared(MacroAssembler& masm)
: inCycle_(0),
masm(masm),
pushedAtCycle_(-1),
pushedAtSpill_(-1),
pushedAtStart_(masm.framePushed()),
spilledReg_(InvalidReg),
spilledFloatReg_(InvalidFloatReg)
{ }
~MoveEmitterMIPSShared() {
assertDone();
}
void emit(const MoveResolver& moves);
void finish();
void setScratchRegister(Register reg) {}
};
} // namespace jit
} // namespace js
#endif /* jit_mips_shared_MoveEmitter_mips_shared_h */
+17
View File
@@ -11,6 +11,23 @@
namespace js {
namespace jit {
const char * const Registers::RegNames[] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" };
const uint32_t Allocatable = 14;
const Registers::SetType Registers::ArgRegMask = Registers::SharedArgRegMask;
const Registers::SetType Registers::JSCallMask =
(1 << Registers::a2) |
(1 << Registers::a3);
const Registers::SetType Registers::CallMask =
(1 << Registers::v0) |
(1 << Registers::v1); // used for double-size returns
FloatRegisters::Code
FloatRegisters::FromName(const char* name)
{
+2 -19
View File
@@ -12,23 +12,6 @@
#include <limits.h>
#include <stdint.h>
#define REGISTERS_NAMES \
{ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", \
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
#define REGISTERS_ALLOCATABLE 14
#define REGISTERS_ARGREGMASK SharedArgRegMask
#define REGISTERS_JSCALLMASK \
(1 << Registers::a2) | \
(1 << Registers::a3);
#define REGISTERS_CALLMASK \
(1 << Registers::v0) | \
(1 << Registers::v1); // used for double-size returns
#include "jit/mips-shared/Architecture-mips-shared.h"
#include "js/Utility.h"
@@ -59,7 +42,7 @@ static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void*);
// When using O32 ABI, floating-point coprocessor is 32 bit.
// When using N32 ABI, floating-point coprocessor is 64 bit.
class FloatRegisters : public BaseFloatRegisters
class FloatRegisters : public FloatRegistersMIPSShared
{
public:
static const char* GetName(uint32_t i) {
@@ -128,7 +111,7 @@ class FloatRegisters : public BaseFloatRegisters
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
class FloatRegister : public BaseFloatRegister
class FloatRegister : public FloatRegisterMIPSShared
{
public:
enum RegType {
+39 -7
View File
@@ -7,13 +7,6 @@
#ifndef jit_mips32_Assembler_mips32_h
#define jit_mips32_Assembler_mips32_h
// NOTE: Don't use these macros directly
// CallTempNonArgRegs
#define CALL_TEMP_NON_ARG_REGS \
{ t0, t1, t2, t3, t4 };
// NumIntArgRegs
#define NUM_INT_ARG_REGS 4;
#include "jit/mips-shared/Assembler-mips-shared.h"
#include "jit/mips32/Architecture-mips32.h"
@@ -24,6 +17,9 @@ namespace jit {
static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4;
static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5;
static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 };
static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs);
class ABIArgGenerator
{
unsigned usedArgSlots_;
@@ -159,6 +155,42 @@ class Assembler : public AssemblerMIPSShared
static int32_t ExtractCodeLabelOffset(uint8_t* code);
}; // Assembler
static const uint32_t NumIntArgRegs = 4;
static inline bool
GetIntArgReg(uint32_t usedArgSlots, Register* out)
{
if (usedArgSlots < NumIntArgRegs) {
*out = Register::FromCode(a0.code() + usedArgSlots);
return true;
}
return false;
}
// Get a register in which we plan to put a quantity that will be used as an
// integer argument. This differs from GetIntArgReg in that if we have no more
// actual argument registers to use we will fall back on using whatever
// CallTempReg* don't overlap the argument registers, and only fail once those
// run out too.
static inline bool
GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out)
{
// NOTE: We can't properly determine which regs are used if there are
// float arguments. If this is needed, we will have to guess.
MOZ_ASSERT(usedFloatArgs == 0);
if (GetIntArgReg(usedIntArgs, out))
return true;
// Unfortunately, we have to assume things about the point at which
// GetIntArgReg returns false, because we need to know how many registers it
// can allocate.
usedIntArgs -= NumIntArgRegs;
if (usedIntArgs >= NumCallTempNonArgRegs)
return false;
*out = CallTempNonArgRegs[usedIntArgs];
return true;
}
static inline uint32_t
GetArgStackDisp(uint32_t usedArgSlots)
{
+2 -16
View File
@@ -4,11 +4,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips32/Bailouts-mips32.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jit/mips-shared/Bailouts-mips-shared.h"
using namespace js;
using namespace js::jit;
@@ -46,17 +46,3 @@ BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
}
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
InvalidationBailoutStack* bailout)
: machine_(bailout->machine())
{
framePointer_ = (uint8_t*) bailout->fp();
topFrameSize_ = framePointer_ - bailout->sp();
topIonScript_ = bailout->ionScript();
attachOnJitActivation(activations);
uint8_t* returnAddressToFp_ = bailout->osiPointReturnAddress();
const OsiIndex* osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
snapshotOffset_ = osiIndex->snapshotOffset();
}
@@ -11,6 +11,6 @@ using namespace js::jit;
BaselineCompilerMIPS::BaselineCompilerMIPS(JSContext* cx, TempAllocator& alloc,
JSScript* script)
: BaselineCompilerShared(cx, alloc, script)
: BaselineCompilerMIPSShared(cx, alloc, script)
{
}
+2 -2
View File
@@ -7,12 +7,12 @@
#ifndef jit_mips32_BaselineCompiler_mips32_h
#define jit_mips32_BaselineCompiler_mips32_h
#include "jit/shared/BaselineCompiler-shared.h"
#include "jit/mips-shared/BaselineCompiler-mips-shared.h"
namespace js {
namespace jit {
class BaselineCompilerMIPS : public BaselineCompilerShared
class BaselineCompilerMIPS : public BaselineCompilerMIPSShared
{
protected:
BaselineCompilerMIPS(JSContext* cx, TempAllocator& alloc, JSScript* script);
-26
View File
@@ -4,16 +4,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsiter.h"
#include "jit/BaselineCompiler.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/Linker.h"
#include "jit/SharedICHelpers.h"
#include "jsboolinlines.h"
using namespace js;
using namespace js::jit;
@@ -45,27 +41,5 @@ ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
bool
ICCompare_Double::Compiler::generateStubCode(MacroAssembler& masm)
{
Label failure, isNaN;
masm.ensureDouble(R0, FloatReg0, &failure);
masm.ensureDouble(R1, FloatReg1, &failure);
Register dest = R0.scratchReg();
Assembler::DoubleCondition doubleCond = JSOpToDoubleCondition(op);
masm.ma_cmp_set_double(dest, FloatReg0, FloatReg1, doubleCond);
masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
} // namespace jit
} // namespace js
File diff suppressed because it is too large Load Diff
+5 -228
View File
@@ -7,114 +7,14 @@
#ifndef jit_mips32_CodeGenerator_mips32_h
#define jit_mips32_CodeGenerator_mips32_h
#include "jit/mips32/Assembler-mips32.h"
#include "jit/shared/CodeGenerator-shared.h"
#include "jit/mips-shared/CodeGenerator-mips-shared.h"
namespace js {
namespace jit {
class OutOfLineBailout;
class OutOfLineTableSwitch;
class CodeGeneratorMIPS : public CodeGeneratorShared
class CodeGeneratorMIPS : public CodeGeneratorMIPSShared
{
friend class MoveResolverMIPS;
CodeGeneratorMIPS* thisFromCtor() {
return this;
}
protected:
NonAssertingLabel deoptLabel_;
inline Address ToAddress(const LAllocation& a);
inline Address ToAddress(const LAllocation* a);
MoveOperand toMoveOperand(LAllocation a) const;
template <typename T1, typename T2>
void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
Label skip;
masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(c), ShortJump);
bailout(snapshot);
masm.bind(&skip);
}
template<typename T>
void bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot* snapshot) {
if (lhs.getTag() == Operand::REG)
bailoutCmp32(c, lhs.toReg(), rhs, snapshot);
else if (lhs.getTag() == Operand::MEM)
bailoutCmp32(c, lhs.toAddress(), rhs, snapshot);
else
MOZ_CRASH("Invalid operand tag.");
}
template<typename T>
void bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot* snapshot) {
Label bail;
masm.branchTest32(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
template <typename T1, typename T2>
void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
bailoutCmp32(c, lhs, rhs, snapshot);
}
void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) {
Label bail;
masm.branchTestPtr(c, lhs, rhs, &bail);
bailoutFrom(&bail, snapshot);
}
void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
Label bail;
masm.branchTest32(Assembler::Zero, reg, Imm32(0xFF), &bail);
bailoutFrom(&bail, snapshot);
}
void bailoutFrom(Label* label, LSnapshot* snapshot);
void bailout(LSnapshot* snapshot);
protected:
bool generateOutOfLineCode();
template <typename T>
void branchToBlock(Register lhs, T rhs, MBasicBlock* mir, Assembler::Condition cond)
{
mir = skipTrivialBlocks(mir);
Label* label = mir->lir()->label();
if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) {
// Note: the backedge is initially a jump to the next instruction.
// It will be patched to the target block's label during link().
RepatchLabel rejoin;
CodeOffsetJump backedge;
Label skip;
masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
backedge = masm.backedgeJump(&rejoin);
masm.bind(&rejoin);
masm.bind(&skip);
if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry)))
MOZ_CRASH();
} else {
masm.ma_b(lhs, rhs, label, cond);
}
}
void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
MBasicBlock* mir, Assembler::DoubleCondition cond);
// Emits a branch that directs control flow to the true block if |cond| is
// true, and the false block if |cond| is false.
template <typename T>
void emitBranch(Register lhs, T rhs, Assembler::Condition cond,
MBasicBlock* mirTrue, MBasicBlock* mirFalse)
{
if (isNextBlock(mirFalse->lir())) {
branchToBlock(lhs, rhs, mirTrue, cond);
} else {
branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond));
jumpToBlock(mirTrue);
}
}
void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
{
@@ -130,75 +30,17 @@ class CodeGeneratorMIPS : public CodeGeneratorShared
{
emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_OBJECT), cond, ifTrue, ifFalse);
}
void testZeroEmitBranch(Assembler::Condition cond, Register reg,
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
{
emitBranch(reg, Imm32(0), cond, ifTrue, ifFalse);
}
void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
public:
// Instruction visitors.
virtual void visitMinMaxD(LMinMaxD* ins);
virtual void visitMinMaxF(LMinMaxF* ins);
virtual void visitAbsD(LAbsD* ins);
virtual void visitAbsF(LAbsF* ins);
virtual void visitSqrtD(LSqrtD* ins);
virtual void visitSqrtF(LSqrtF* ins);
virtual void visitAddI(LAddI* ins);
virtual void visitSubI(LSubI* ins);
virtual void visitBitNotI(LBitNotI* ins);
virtual void visitBitOpI(LBitOpI* ins);
virtual void visitMulI(LMulI* ins);
virtual void visitDivI(LDivI* ins);
virtual void visitDivPowTwoI(LDivPowTwoI* ins);
virtual void visitModI(LModI* ins);
virtual void visitModPowTwoI(LModPowTwoI* ins);
virtual void visitModMaskI(LModMaskI* ins);
virtual void visitPowHalfD(LPowHalfD* ins);
virtual void visitShiftI(LShiftI* ins);
virtual void visitUrshD(LUrshD* ins);
virtual void visitClzI(LClzI* ins);
virtual void visitTestIAndBranch(LTestIAndBranch* test);
virtual void visitCompare(LCompare* comp);
virtual void visitCompareAndBranch(LCompareAndBranch* comp);
virtual void visitTestDAndBranch(LTestDAndBranch* test);
virtual void visitTestFAndBranch(LTestFAndBranch* test);
virtual void visitCompareD(LCompareD* comp);
virtual void visitCompareF(LCompareF* comp);
virtual void visitCompareDAndBranch(LCompareDAndBranch* comp);
virtual void visitCompareFAndBranch(LCompareFAndBranch* comp);
virtual void visitCompareB(LCompareB* lir);
virtual void visitCompareBAndBranch(LCompareBAndBranch* lir);
virtual void visitCompareBitwise(LCompareBitwise* lir);
virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
virtual void visitBitAndAndBranch(LBitAndAndBranch* lir);
virtual void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir);
virtual void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir);
virtual void visitNotI(LNotI* ins);
virtual void visitNotD(LNotD* ins);
virtual void visitNotF(LNotF* ins);
virtual void visitMathD(LMathD* math);
virtual void visitMathF(LMathF* math);
virtual void visitFloor(LFloor* lir);
virtual void visitFloorF(LFloorF* lir);
virtual void visitCeil(LCeil* lir);
virtual void visitCeilF(LCeilF* lir);
virtual void visitRound(LRound* lir);
virtual void visitRoundF(LRoundF* lir);
virtual void visitTruncateDToInt32(LTruncateDToInt32* ins);
virtual void visitTruncateFToInt32(LTruncateFToInt32* ins);
// Out of line visitors.
void visitOutOfLineBailout(OutOfLineBailout* ool);
void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
protected:
ValueOperand ToValue(LInstruction* ins, size_t pos);
ValueOperand ToOutValue(LInstruction* ins);
@@ -208,84 +50,19 @@ class CodeGeneratorMIPS : public CodeGeneratorShared
Register splitTagForTest(const ValueOperand& value);
public:
CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
CodeGeneratorMIPS(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
: CodeGeneratorMIPSShared(gen, graph, masm)
{ }
public:
void visitBox(LBox* box);
void visitBoxFloatingPoint(LBoxFloatingPoint* box);
void visitUnbox(LUnbox* unbox);
void visitValue(LValue* value);
void visitDouble(LDouble* ins);
void visitFloat32(LFloat32* ins);
void visitGuardShape(LGuardShape* guard);
void visitGuardObjectGroup(LGuardObjectGroup* guard);
void visitGuardClass(LGuardClass* guard);
void visitNegI(LNegI* lir);
void visitNegD(LNegD* lir);
void visitNegF(LNegF* lir);
void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
void generateInvalidateEpilogue();
void setReturnDoubleRegs(LiveRegisterSet* regs);
protected:
void visitEffectiveAddress(LEffectiveAddress* ins);
void visitUDivOrMod(LUDivOrMod* ins);
public:
// Unimplemented SIMD instructions
void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); }
void visitInt32x4(LInt32x4* ins) { MOZ_CRASH("NYI"); }
void visitFloat32x4(LFloat32x4* ins) { MOZ_CRASH("NYI"); }
void visitSimdReinterpretCast(LSimdReinterpretCast* ins) { MOZ_CRASH("NYI"); }
void visitSimdExtractElementI(LSimdExtractElementI* ins) { MOZ_CRASH("NYI"); }
void visitSimdExtractElementF(LSimdExtractElementF* ins) { MOZ_CRASH("NYI"); }
void visitSimdSignMaskX4(LSimdSignMaskX4* ins) { MOZ_CRASH("NYI"); }
void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir) { MOZ_CRASH("NYI"); }
void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir) { MOZ_CRASH("NYI"); }
void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir) { MOZ_CRASH("NYI"); }
void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir) { MOZ_CRASH("NYI"); }
};
typedef CodeGeneratorMIPS CodeGeneratorSpecific;
// An out-of-line bailout thunk.
class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorMIPS>
{
LSnapshot* snapshot_;
uint32_t frameSize_;
public:
OutOfLineBailout(LSnapshot* snapshot, uint32_t frameSize)
: snapshot_(snapshot),
frameSize_(frameSize)
{ }
void accept(CodeGeneratorMIPS* codegen);
LSnapshot* snapshot() const {
return snapshot_;
}
};
} // namespace jit
} // namespace js
+2 -2
View File
@@ -144,7 +144,7 @@ MacroAssemblerMIPSCompat::convertUInt32ToFloat32(Register src, FloatRegister des
// have enough precision.
convertUInt32ToDouble(src, dest);
convertDoubleToFloat32(dest, dest);
ma_b(&done);
ma_b(&done, ShortJump);
bind(&positive);
convertInt32ToFloat32(src, dest);
@@ -3372,7 +3372,7 @@ MacroAssembler::Pop(Register reg)
}
void
MacroAssembler::Pop(const ValueOperand &val)
MacroAssembler::Pop(const ValueOperand& val)
{
popValue(val);
framePushed_ -= sizeof(Value);
-190
View File
@@ -11,68 +11,6 @@
using namespace js;
using namespace js::jit;
MoveEmitterMIPS::MoveEmitterMIPS(MacroAssembler& masm)
: inCycle_(0),
masm(masm),
pushedAtCycle_(-1),
pushedAtSpill_(-1),
spilledReg_(InvalidReg),
spilledFloatReg_(InvalidFloatReg)
{
pushedAtStart_ = masm.framePushed();
}
void
MoveEmitterMIPS::emit(const MoveResolver& moves)
{
if (moves.numCycles()) {
// Reserve stack for cycle resolution
masm.reserveStack(moves.numCycles() * sizeof(double));
pushedAtCycle_ = masm.framePushed();
}
for (size_t i = 0; i < moves.numMoves(); i++)
emit(moves.getMove(i));
}
MoveEmitterMIPS::~MoveEmitterMIPS()
{
assertDone();
}
Address
MoveEmitterMIPS::cycleSlot(uint32_t slot, uint32_t subslot) const
{
int32_t offset = masm.framePushed() - pushedAtCycle_;
MOZ_ASSERT(Imm16::IsInSignedRange(offset));
return Address(StackPointer, offset + slot * sizeof(double) + subslot);
}
int32_t
MoveEmitterMIPS::getAdjustedOffset(const MoveOperand& operand)
{
MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
if (operand.base() != StackPointer)
return operand.disp();
// Adjust offset if stack pointer has been moved.
return operand.disp() + masm.framePushed() - pushedAtStart_;
}
Address
MoveEmitterMIPS::getAdjustedAddress(const MoveOperand& operand)
{
return Address(operand.base(), getAdjustedOffset(operand));
}
Register
MoveEmitterMIPS::tempReg()
{
spilledReg_ = SecondScratchReg;
return SecondScratchReg;
}
void
MoveEmitterMIPS::breakCycle(const MoveOperand& from, const MoveOperand& to,
MoveOp::Type type, uint32_t slotId)
@@ -175,76 +113,6 @@ MoveEmitterMIPS::completeCycle(const MoveOperand& from, const MoveOperand& to,
}
}
void
MoveEmitterMIPS::emitMove(const MoveOperand& from, const MoveOperand& to)
{
if (from.isGeneralReg()) {
// Second scratch register should not be moved by MoveEmitter.
MOZ_ASSERT(from.reg() != spilledReg_);
if (to.isGeneralReg())
masm.movePtr(from.reg(), to.reg());
else if (to.isMemory())
masm.storePtr(from.reg(), getAdjustedAddress(to));
else
MOZ_CRASH("Invalid emitMove arguments.");
} else if (from.isMemory()) {
if (to.isGeneralReg()) {
masm.loadPtr(getAdjustedAddress(from), to.reg());
} else if (to.isMemory()) {
masm.loadPtr(getAdjustedAddress(from), tempReg());
masm.storePtr(tempReg(), getAdjustedAddress(to));
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
} else if (from.isEffectiveAddress()) {
if (to.isGeneralReg()) {
masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg());
} else if (to.isMemory()) {
masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg());
masm.storePtr(tempReg(), getAdjustedAddress(to));
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
} else {
MOZ_CRASH("Invalid emitMove arguments.");
}
}
void
MoveEmitterMIPS::emitFloat32Move(const MoveOperand& from, const MoveOperand& to)
{
// Ensure that we can use ScratchFloat32Reg in memory move.
MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloat32Reg);
MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloat32Reg);
if (from.isFloatReg()) {
if (to.isFloatReg()) {
masm.moveFloat32(from.floatReg(), to.floatReg());
} else if (to.isGeneralReg()) {
// This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.moveFromFloat32(from.floatReg(), to.reg());
} else {
MOZ_ASSERT(to.isMemory());
masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
}
} else if (to.isFloatReg()) {
MOZ_ASSERT(from.isMemory());
masm.loadFloat32(getAdjustedAddress(from), to.floatReg());
} else if (to.isGeneralReg()) {
MOZ_ASSERT(from.isMemory());
// This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.loadPtr(getAdjustedAddress(from), to.reg());
} else {
MOZ_ASSERT(from.isMemory());
MOZ_ASSERT(to.isMemory());
masm.loadFloat32(getAdjustedAddress(from), ScratchFloat32Reg);
masm.storeFloat32(ScratchFloat32Reg, getAdjustedAddress(to));
}
}
void
MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
{
@@ -286,61 +154,3 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
masm.storeDouble(ScratchDoubleReg, getAdjustedAddress(to));
}
}
void
MoveEmitterMIPS::emit(const MoveOp& move)
{
const MoveOperand& from = move.from();
const MoveOperand& to = move.to();
if (move.isCycleEnd() && move.isCycleBegin()) {
// A fun consequence of aliased registers is you can have multiple
// cycles at once, and one can end exactly where another begins.
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
completeCycle(from, to, move.type(), move.cycleEndSlot());
return;
}
if (move.isCycleEnd()) {
MOZ_ASSERT(inCycle_);
completeCycle(from, to, move.type(), move.cycleEndSlot());
MOZ_ASSERT(inCycle_ > 0);
inCycle_--;
return;
}
if (move.isCycleBegin()) {
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
inCycle_++;
}
switch (move.type()) {
case MoveOp::FLOAT32:
emitFloat32Move(from, to);
break;
case MoveOp::DOUBLE:
emitDoubleMove(from, to);
break;
case MoveOp::INT32:
MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
case MoveOp::GENERAL:
emitMove(from, to);
break;
default:
MOZ_CRASH("Unexpected move type");
}
}
void
MoveEmitterMIPS::assertDone()
{
MOZ_ASSERT(inCycle_ == 0);
}
void
MoveEmitterMIPS::finish()
{
assertDone();
masm.freeStack(masm.framePushed() - pushedAtStart_);
}
+5 -37
View File
@@ -7,55 +7,23 @@
#ifndef jit_mips32_MoveEmitter_mips32_h
#define jit_mips32_MoveEmitter_mips32_h
#include "jit/MacroAssembler.h"
#include "jit/MoveResolver.h"
#include "jit/mips-shared/MoveEmitter-mips-shared.h"
namespace js {
namespace jit {
class MoveEmitterMIPS
class MoveEmitterMIPS : public MoveEmitterMIPSShared
{
uint32_t inCycle_;
MacroAssembler& masm;
// Original stack push value.
uint32_t pushedAtStart_;
// These store stack offsets to spill locations, snapshotting
// codegen->framePushed_ at the time they were allocated. They are -1 if no
// stack space has been allocated for that particular spill.
int32_t pushedAtCycle_;
int32_t pushedAtSpill_;
// These are registers that are available for temporary use. They may be
// assigned InvalidReg. If no corresponding spill space has been assigned,
// then these registers do not need to be spilled.
Register spilledReg_;
FloatRegister spilledFloatReg_;
void assertDone();
Register tempReg();
FloatRegister tempFloatReg();
Address cycleSlot(uint32_t slot, uint32_t subslot) const;
int32_t getAdjustedOffset(const MoveOperand& operand);
Address getAdjustedAddress(const MoveOperand& operand);
void emitMove(const MoveOperand& from, const MoveOperand& to);
void emitFloat32Move(const MoveOperand& from, const MoveOperand& to);
void emitDoubleMove(const MoveOperand& from, const MoveOperand& to);
void breakCycle(const MoveOperand& from, const MoveOperand& to,
MoveOp::Type type, uint32_t slot);
void completeCycle(const MoveOperand& from, const MoveOperand& to,
MoveOp::Type type, uint32_t slot);
void emit(const MoveOp &move);
public:
MoveEmitterMIPS(MacroAssembler &masm);
~MoveEmitterMIPS();
void emit(const MoveResolver &moves);
void finish();
void setScratchRegister(Register reg) {}
MoveEmitterMIPS(MacroAssembler& masm)
: MoveEmitterMIPSShared(masm)
{ }
};
typedef MoveEmitterMIPS MoveEmitter;
+1 -1
View File
@@ -13,7 +13,7 @@
#include "jit/JitFrames.h"
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/mips32/Bailouts-mips32.h"
#include "jit/mips-shared/Bailouts-mips-shared.h"
#include "jit/mips32/SharedICHelpers-mips32.h"
#ifdef JS_ION_PERF
# include "jit/PerfSpewer.h"
+93
View File
@@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips64/Architecture-mips64.h"
#include "jit/RegisterSets.h"
namespace js {
namespace jit {
const char * const Registers::RegNames[] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" };
const uint32_t Allocatable = 22;
const Registers::SetType Registers::ArgRegMask =
Registers::SharedArgRegMask |
(1 << a4) | (1 << a5) | (1 << a6) | (1 << a7);
const Registers::SetType Registers::JSCallMask =
(1 << Registers::v1);
const Registers::SetType Registers::CallMask =
(1 << Registers::v0);
FloatRegisters::Encoding
FloatRegisters::FromName(const char* name)
{
for (size_t i = 0; i < Total; i++) {
if (strcmp(GetName(Encoding(i)), name) == 0)
return Encoding(i);
}
return Invalid;
}
FloatRegister
FloatRegister::singleOverlay() const
{
MOZ_ASSERT(!isInvalid());
if (kind_ == Codes::Double)
return FloatRegister(reg_, Codes::Single);
return *this;
}
FloatRegister
FloatRegister::doubleOverlay() const
{
MOZ_ASSERT(!isInvalid());
if (kind_ != Codes::Double)
return FloatRegister(reg_, Codes::Double);
return *this;
}
FloatRegisterSet
FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
{
LiveFloatRegisterSet mod;
for (FloatRegisterIterator iter(s); iter.more(); iter++) {
if ((*iter).isSingle()) {
// Even for single size registers save complete double register.
mod.addUnchecked((*iter).doubleOverlay());
} else {
mod.addUnchecked(*iter);
}
}
return mod.set();
}
uint32_t
FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
{
FloatRegisterSet ss = s.reduceSetForPush();
uint64_t bits = ss.bits();
// We are only pushing double registers.
MOZ_ASSERT((bits & 0xffffffff) == 0);
uint32_t ret = mozilla::CountPopulation32(bits >> 32) * sizeof(double);
return ret;
}
uint32_t
FloatRegister::getRegisterDumpOffsetInBytes()
{
return id() * sizeof(double);
}
} // namespace ion
} // namespace js
+209
View File
@@ -0,0 +1,209 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips64_Architecture_mips64_h
#define jit_mips64_Architecture_mips64_h
#include "mozilla/MathAlgorithms.h"
#include <limits.h>
#include <stdint.h>
#include "jit/mips-shared/Architecture-mips-shared.h"
#include "js/Utility.h"
namespace js {
namespace jit {
// Shadow stack space is not required on MIPS64.
static const uint32_t ShadowStackSpace = 0;
// MIPS64 have 64 bit floating-point coprocessor. There are 32 double
// precision register which can also be used as single precision registers.
class FloatRegisters : public FloatRegistersMIPSShared
{
public:
enum ContentType {
Single,
Double,
NumTypes
};
static const char* GetName(uint32_t i) {
MOZ_ASSERT(i < TotalPhys);
return FloatRegistersMIPSShared::GetName(Encoding(i));
}
static Encoding FromName(const char* name);
static const uint32_t Total = 32 * NumTypes;
static const uint32_t Allocatable = 60;
// When saving all registers we only need to do is save double registers.
static const uint32_t TotalPhys = 32;
static_assert(sizeof(SetType) * 8 >= Total,
"SetType should be large enough to enumerate all registers.");
// Magic values which are used to duplicate a mask of physical register for
// a specific type of register. A multiplication is used to copy and shift
// the bits of the physical register mask.
static const SetType SpreadSingle = SetType(1) << (uint32_t(Single) * TotalPhys);
static const SetType SpreadDouble = SetType(1) << (uint32_t(Double) * TotalPhys);
static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
static const SetType SpreadVector = 0;
static const SetType Spread = SpreadScalar | SpreadVector;
static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
static const SetType AllMask = AllPhysMask * Spread;
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
static const SetType NonVolatileMask =
( (1U << FloatRegisters::f24) |
(1U << FloatRegisters::f25) |
(1U << FloatRegisters::f26) |
(1U << FloatRegisters::f27) |
(1U << FloatRegisters::f28) |
(1U << FloatRegisters::f29) |
(1U << FloatRegisters::f30) |
(1U << FloatRegisters::f31)
) * SpreadScalar
| AllPhysMask * SpreadVector;
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
static const SetType WrapperMask = VolatileMask;
static const SetType NonAllocatableMask =
( // f21 and f23 are MIPS scratch float registers.
(1U << FloatRegisters::f21) |
(1U << FloatRegisters::f23)
) * Spread;
// Registers that can be allocated without being saved, generally.
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
template <typename T>
class TypedRegisterSet;
class FloatRegister : public FloatRegisterMIPSShared
{
public:
typedef FloatRegisters Codes;
typedef size_t Code;
typedef Codes::Encoding Encoding;
typedef Codes::ContentType ContentType;
Encoding reg_: 6;
private:
ContentType kind_ : 3;
public:
MOZ_CONSTEXPR FloatRegister(uint32_t r, ContentType kind = Codes::Double)
: reg_(Encoding(r)), kind_(kind)
{ }
MOZ_CONSTEXPR FloatRegister()
: reg_(Encoding(FloatRegisters::invalid_freg)), kind_(Codes::Double)
{ }
bool operator==(const FloatRegister& other) const {
MOZ_ASSERT(!isInvalid());
MOZ_ASSERT(!other.isInvalid());
return kind_ == other.kind_ && reg_ == other.reg_;
}
bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; }
size_t size() const { return (kind_ == Codes::Double) ? sizeof(double) : sizeof (float); }
bool isInvalid() const {
return reg_ == FloatRegisters::invalid_freg;
}
bool isSingle() const { return kind_ == Codes::Single; }
bool isDouble() const { return kind_ == Codes::Double; }
FloatRegister singleOverlay() const;
FloatRegister doubleOverlay() const;
FloatRegister asSingle() const { return singleOverlay(); }
FloatRegister asDouble() const { return doubleOverlay(); }
FloatRegister asInt32x4() const { MOZ_CRASH("NYI"); }
FloatRegister asFloat32x4() const { MOZ_CRASH("NYI"); }
Code code() const {
MOZ_ASSERT(!isInvalid());
return Code(reg_ | (kind_ << 5));
}
Encoding encoding() const {
MOZ_ASSERT(!isInvalid());
MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
return reg_;
}
uint32_t id() const {
return reg_;
}
static FloatRegister FromCode(uint32_t i) {
uint32_t code = i & 0x1f;
uint32_t kind = i >> 5;
return FloatRegister(Code(code), ContentType(kind));
}
bool volatile_() const {
return !!((1 << reg_) & FloatRegisters::VolatileMask);
}
const char* name() const {
return FloatRegisters::GetName(reg_);
}
bool operator != (const FloatRegister& other) const {
return kind_ != other.kind_ || reg_ != other.reg_;
}
bool aliases(const FloatRegister& other) {
return reg_ == other.reg_;
}
uint32_t numAliased() const {
return 2;
}
void aliased(uint32_t aliasIdx, FloatRegister* ret) {
if (aliasIdx == 0) {
*ret = *this;
return;
}
MOZ_ASSERT(aliasIdx == 1);
if (isDouble())
*ret = singleOverlay();
else
*ret = doubleOverlay();
}
uint32_t numAlignedAliased() const {
return 2;
}
void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
MOZ_ASSERT(isDouble());
if (aliasIdx == 0) {
*ret = *this;
return;
}
MOZ_ASSERT(aliasIdx == 1);
*ret = singleOverlay();
}
SetType alignedOrDominatedAliasedSet() const {
return Codes::Spread << reg_;
}
static Code FromName(const char* name) {
return FloatRegisters::FromName(name);
}
static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
uint32_t getRegisterDumpOffsetInBytes();
};
} // namespace jit
} // namespace js
#endif /* jit_mips64_Architecture_mips64_h */
+493
View File
@@ -0,0 +1,493 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/mips64/Assembler-mips64.h"
#include "mozilla/DebugOnly.h"
using mozilla::DebugOnly;
using namespace js;
using namespace js::jit;
ABIArgGenerator::ABIArgGenerator()
: usedArgSlots_(0),
firstArgFloat(false),
current_()
{}
ABIArg
ABIArgGenerator::next(MIRType type)
{
switch (type) {
case MIRType_Int32:
case MIRType_Pointer: {
Register destReg;
if (GetIntArgReg(usedArgSlots_, &destReg))
current_ = ABIArg(destReg);
else
current_ = ABIArg(GetArgStackDisp(usedArgSlots_));
usedArgSlots_++;
break;
}
case MIRType_Float32:
case MIRType_Double: {
FloatRegister destFReg;
FloatRegister::ContentType contentType;
if (!usedArgSlots_)
firstArgFloat = true;
contentType = (type == MIRType_Double) ?
FloatRegisters::Double : FloatRegisters::Single;
if (GetFloatArgReg(usedArgSlots_, &destFReg))
current_ = ABIArg(FloatRegister(destFReg.id(), contentType));
else
current_ = ABIArg(GetArgStackDisp(usedArgSlots_));
usedArgSlots_++;
break;
}
default:
MOZ_CRASH("Unexpected argument type");
}
return current_;
}
const Register ABIArgGenerator::NonArgReturnReg0 = t0;
const Register ABIArgGenerator::NonArgReturnReg1 = t1;
const Register ABIArgGenerator::NonArg_VolatileReg = v0;
const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0;
const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1;
uint32_t
js::jit::RT(FloatRegister r)
{
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
return r.id() << RTShift;
}
uint32_t
js::jit::RD(FloatRegister r)
{
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
return r.id() << RDShift;
}
uint32_t
js::jit::SA(FloatRegister r)
{
MOZ_ASSERT(r.id() < FloatRegisters::TotalPhys);
return r.id() << SAShift;
}
// Used to patch jumps created by MacroAssemblerMIPS64Compat::jumpWithPatch.
void
jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, ReprotectCode reprotect)
{
Instruction* inst = (Instruction*)jump_.raw();
// Six instructions used in load 64-bit imm.
MaybeAutoWritableJitCode awjc(inst, 6 * sizeof(uint32_t), reprotect);
Assembler::UpdateLoad64Value(inst, (uint64_t)label.raw());
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
}
// For more infromation about backedges look at comment in
// MacroAssemblerMIPS64Compat::backedgeJump()
void
jit::PatchBackedge(CodeLocationJump& jump, CodeLocationLabel label,
JitRuntime::BackedgeTarget target)
{
uintptr_t sourceAddr = (uintptr_t)jump.raw();
uintptr_t targetAddr = (uintptr_t)label.raw();
InstImm* branch = (InstImm*)jump.raw();
MOZ_ASSERT(branch->extractOpcode() == (uint32_t(op_beq) >> OpcodeShift));
if (BOffImm16::IsInRange(targetAddr - sourceAddr)) {
branch->setBOffImm16(BOffImm16(targetAddr - sourceAddr));
} else {
if (target == JitRuntime::BackedgeLoopHeader) {
Instruction* inst = &branch[1];
Assembler::UpdateLoad64Value(inst, targetAddr);
// Jump to first ori. The lui will be executed in delay slot.
branch->setBOffImm16(BOffImm16(2 * sizeof(uint32_t)));
} else {
Instruction* inst = &branch[6];
Assembler::UpdateLoad64Value(inst, targetAddr);
// Jump to first ori of interrupt loop.
branch->setBOffImm16(BOffImm16(6 * sizeof(uint32_t)));
}
}
}
void
Assembler::executableCopy(uint8_t* buffer)
{
MOZ_ASSERT(isFinished);
m_buffer.executableCopy(buffer);
// Patch all long jumps during code copy.
for (size_t i = 0; i < longJumps_.length(); i++) {
Instruction* inst = (Instruction*) ((uintptr_t)buffer + longJumps_[i]);
uint64_t value = Assembler::ExtractLoad64Value(inst);
Assembler::UpdateLoad64Value(inst, (uint64_t)buffer + value);
}
AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
}
uintptr_t
Assembler::GetPointer(uint8_t* instPtr)
{
Instruction* inst = (Instruction*)instPtr;
return Assembler::ExtractLoad64Value(inst);
}
static JitCode *
CodeFromJump(Instruction* jump)
{
uint8_t* target = (uint8_t*)Assembler::ExtractLoad64Value(jump);
return JitCode::FromExecutable(target);
}
void
Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader)
{
while (reader.more()) {
JitCode* child = CodeFromJump((Instruction*)(code->raw() + reader.readUnsigned()));
TraceManuallyBarrieredEdge(trc, &child, "rel32");
}
}
static void
TraceOneDataRelocation(JSTracer* trc, Instruction* inst)
{
void* ptr = (void*)Assembler::ExtractLoad64Value(inst);
void* prior = ptr;
// All pointers on MIPS64 will have the top bits cleared. If those bits
// are not cleared, this must be a Value.
uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
if (word >> JSVAL_TAG_SHIFT) {
jsval_layout layout;
layout.asBits = word;
Value v = IMPL_TO_JSVAL(layout);
TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value");
ptr = (void*)JSVAL_TO_IMPL(v).asBits;
} else {
// No barrier needed since these are constants.
TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(&ptr),
"ion-masm-ptr");
}
if (ptr != prior) {
Assembler::UpdateLoad64Value(inst, uint64_t(ptr));
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
}
}
static void
TraceDataRelocations(JSTracer* trc, uint8_t* buffer, CompactBufferReader& reader)
{
while (reader.more()) {
size_t offset = reader.readUnsigned();
Instruction* inst = (Instruction*)(buffer + offset);
TraceOneDataRelocation(trc, inst);
}
}
static void
TraceDataRelocations(JSTracer* trc, MIPSBuffer* buffer, CompactBufferReader& reader)
{
while (reader.more()) {
BufferOffset bo (reader.readUnsigned());
MIPSBuffer::AssemblerBufferInstIterator iter(bo, buffer);
TraceOneDataRelocation(trc, iter.cur());
}
}
void
Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader)
{
::TraceDataRelocations(trc, code->raw(), reader);
}
void
Assembler::trace(JSTracer* trc)
{
for (size_t i = 0; i < jumps_.length(); i++) {
RelativePatch& rp = jumps_[i];
if (rp.kind == Relocation::JITCODE) {
JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target);
TraceManuallyBarrieredEdge(trc, &code, "masmrel32");
MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target));
}
}
if (dataRelocations_.length()) {
CompactBufferReader reader(dataRelocations_);
::TraceDataRelocations(trc, &m_buffer, reader);
}
}
int64_t
Assembler::ExtractCodeLabelOffset(uint8_t* code)
{
Instruction* inst = (Instruction*)code;
return Assembler::ExtractLoad64Value(inst);
}
void
Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address)
{
if (label->used()) {
int64_t src = label->offset();
do {
Instruction* inst = (Instruction*) (rawCode + src);
uint64_t next = Assembler::ExtractLoad64Value(inst);
Assembler::UpdateLoad64Value(inst, (uint64_t)address);
src = next;
} while (src != AbsoluteLabel::INVALID_OFFSET);
}
label->bind();
}
void
Assembler::bind(InstImm* inst, uint64_t branch, uint64_t target)
{
int64_t offset = target - branch;
InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
// If encoded offset is 4, then the jump must be short
if (BOffImm16(inst[0]).decode() == 4) {
MOZ_ASSERT(BOffImm16::IsInRange(offset));
inst[0].setBOffImm16(BOffImm16(offset));
inst[1].makeNop();
return;
}
// Generate the long jump for calls because return address has to be the
// address after the reserved block.
if (inst[0].encode() == inst_bgezal.encode()) {
addLongJump(BufferOffset(branch));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
// There is 1 nop after this.
return;
}
if (BOffImm16::IsInRange(offset)) {
bool conditional = (inst[0].encode() != inst_bgezal.encode() &&
inst[0].encode() != inst_beq.encode());
inst[0].setBOffImm16(BOffImm16(offset));
inst[1].makeNop();
// Skip the trailing nops in conditional branches.
// FIXME: On Loongson3 platform, the branch degrade performance.
if (0 && conditional) {
inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(5 * sizeof(uint32_t))).encode();
// There are 4 nops after this
}
return;
}
if (inst[0].encode() == inst_beq.encode()) {
// Handle long unconditional jump.
addLongJump(BufferOffset(branch));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
inst[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
} else {
// Handle long conditional jump.
inst[0] = invertBranch(inst[0], BOffImm16(7 * sizeof(uint32_t)));
// No need for a "nop" here because we can clobber scratch.
addLongJump(BufferOffset(branch + sizeof(uint32_t)));
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, target);
inst[5] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
}
}
void
Assembler::bind(RepatchLabel* label)
{
BufferOffset dest = nextOffset();
if (label->used()) {
// If the label has a use, then change this use to refer to
// the bound label;
BufferOffset b(label->offset());
InstImm* inst1 = (InstImm*)editSrc(b);
// If first instruction is branch, then this is a loop backedge.
if (inst1->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift)) {
// Backedges are short jumps when bound, but can become long
// when patched.
uint64_t offset = dest.getOffset() - label->offset();
MOZ_ASSERT(BOffImm16::IsInRange(offset));
inst1->setBOffImm16(BOffImm16(offset));
} else {
Assembler::UpdateLoad64Value(inst1, dest.getOffset());
}
}
label->bind(dest.getOffset());
}
uint32_t
Assembler::PatchWrite_NearCallSize()
{
// Load an address needs 4 instructions, and a jump with a delay slot.
return (4 + 2) * sizeof(uint32_t);
}
void
Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
{
Instruction* inst = (Instruction*) start.raw();
uint8_t* dest = toCall.raw();
// Overwrite whatever instruction used to be here with a call.
// Always use long jump for two reasons:
// - Jump has to be the same size because of PatchWrite_NearCallSize.
// - Return address has to be at the end of replaced block.
// Short jump wouldn't be more efficient.
Assembler::WriteLoad64Instructions(inst, ScratchRegister, (uint64_t)dest);
inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
inst[5] = InstNOP();
// Ensure everyone sees the code that was just written into memory.
AutoFlushICache::flush(uintptr_t(inst), PatchWrite_NearCallSize());
}
uint64_t
Assembler::ExtractLoad64Value(Instruction* inst0)
{
InstImm* i0 = (InstImm*) inst0;
InstImm* i1 = (InstImm*) inst0->next();
InstReg* i2 = (InstReg*) inst1->next();
InstImm* i3 = (InstImm*) inst2->next();
InstImm* i5 = (InstImm*) inst3->next()->next();
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) &&
(i2->extractFunctionField() == ff_dsrl32))
{
uint64_t value = (uint64_t(i0->extractImm16Value()) << 32) |
(uint64_t(i1->extractImm16Value()) << 16) |
uint64_t(i3->extractImm16Value());
return uint64_t((int64_t(value) <<16) >> 16);
}
MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
uint64_t value = (uint64_t(i0->extractImm16Value()) << 48) |
(uint64_t(i1->extractImm16Value()) << 32) |
(uint64_t(i3->extractImm16Value()) << 16) |
uint64_t(i5->extractImm16Value());
return value;
}
void
Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value)
{
InstImm* i0 = (InstImm*) inst0;
InstImm* i1 = (InstImm*) inst0->next();
InstReg* i2 = (InstReg*) inst1->next();
InstImm* i3 = (InstImm*) inst2->next();
InstImm* i5 = (InstImm*) inst3->next()->next();
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
if ((i2->extractOpcode() == ((uint32_t)op_special >> OpcodeShift)) &&
(i2->extractFunctionField() == ff_dsrl32))
{
i0->setImm16(Imm16::Lower(Imm32(value >> 32)));
i1->setImm16(Imm16::Upper(Imm32(value)));
i3->setImm16(Imm16::Lower(Imm32(value)));
return;
}
MOZ_ASSERT(i5->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
i0->setImm16(Imm16::Upper(Imm32(value >> 32)));
i1->setImm16(Imm16::Lower(Imm32(value >> 32)));
i3->setImm16(Imm16::Upper(Imm32(value)));
i5->setImm16(Imm16::Lower(Imm32(value)));
}
void
Assembler::WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value)
{
Instruction* inst1 = inst0->next();
Instruction* inst2 = inst1->next();
Instruction* inst3 = inst2->next();
*inst0 = InstImm(op_lui, zero, reg, Imm16::Lower(Imm32(value >> 32)));
*inst1 = InstImm(op_ori, reg, reg, Imm16::Upper(Imm32(value)));
*inst2 = InstReg(op_special, rs_one, reg, reg, 48 - 32, ff_dsrl32);
*inst3 = InstImm(op_ori, reg, reg, Imm16::Lower(Imm32(value)));
}
void
Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
PatchedImmPtr expectedValue)
{
Instruction* inst = (Instruction*) label.raw();
// Extract old Value
DebugOnly<uint64_t> value = Assembler::ExtractLoad64Value(inst);
MOZ_ASSERT(value == uint64_t(expectedValue.value));
// Replace with new value
Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value));
AutoFlushICache::flush(uintptr_t(inst), 6 * sizeof(uint32_t));
}
void
Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm)
{
InstImm* inst = (InstImm*)code;
Assembler::UpdateLoad64Value(inst, (uint64_t)imm.value);
}
void
Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
{
Instruction* inst = (Instruction*)inst_.raw();
InstImm* i0 = (InstImm*) inst;
InstImm* i1 = (InstImm*) i0->next();
InstImm* i3 = (InstImm*) i1->next()->next();
Instruction* i4 = (Instruction*) i3->next();
MOZ_ASSERT(i0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
MOZ_ASSERT(i1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
MOZ_ASSERT(i3->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
if (enabled) {
MOZ_ASSERT(i4->extractOpcode() != ((uint32_t)op_lui >> OpcodeShift));
InstReg jalr = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
*i4 = jalr;
} else {
InstNOP nop;
*i4 = nop;
}
AutoFlushICache::flush(uintptr_t(i4), sizeof(uint32_t));
}
void
Assembler::UpdateBoundsCheck(uint64_t heapSize, Instruction* inst)
{
// Replace with new value
Assembler::UpdateLoad64Value(inst, heapSize);
}
+217
View File
@@ -0,0 +1,217 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_mips64_Assembler_mips64_h
#define jit_mips64_Assembler_mips64_h
#include "jit/mips-shared/Assembler-mips-shared.h"
#include "jit/mips64/Architecture-mips64.h"
namespace js {
namespace jit {
static MOZ_CONSTEXPR_VAR Register CallTempReg4 = a4;
static MOZ_CONSTEXPR_VAR Register CallTempReg5 = a5;
static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3 };
static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs);
class ABIArgGenerator
{
unsigned usedArgSlots_;
bool firstArgFloat;
ABIArg current_;
public:
ABIArgGenerator();
ABIArg next(MIRType argType);
ABIArg& current() { return current_; }
uint32_t stackBytesConsumedSoFar() const {
if (usedArgSlots_ <= 8)
return 0;
return (usedArgSlots_ - 8) * sizeof(int64_t);
}
static const Register NonArgReturnReg0;
static const Register NonArgReturnReg1;
static const Register NonArg_VolatileReg;
static const Register NonReturn_VolatileReg0;
static const Register NonReturn_VolatileReg1;
};
static MOZ_CONSTEXPR_VAR Register JSReturnReg = v1;
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = JSReturnReg;
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = JSReturnReg;
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegisters::Single };
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f23, FloatRegisters::Single };
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f23, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f21, FloatRegisters::Single };
static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchDoubleReg = { FloatRegisters::f21, FloatRegisters::Double };
// Registers used in the GenerateFFIIonExit Disable Activation block.
// None of these may be the second scratch register (t8).
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data;
static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type;
static MOZ_CONSTEXPR_VAR FloatRegister f0 = { FloatRegisters::f0, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f2 = { FloatRegisters::f2, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f3 = { FloatRegisters::f3, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f4 = { FloatRegisters::f4, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f5 = { FloatRegisters::f5, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f6 = { FloatRegisters::f6, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f7 = { FloatRegisters::f7, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f8 = { FloatRegisters::f8, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f9 = { FloatRegisters::f9, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f10 = { FloatRegisters::f10, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f11 = { FloatRegisters::f11, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f12 = { FloatRegisters::f12, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f13 = { FloatRegisters::f13, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f14 = { FloatRegisters::f14, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f15 = { FloatRegisters::f15, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f16 = { FloatRegisters::f16, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f17 = { FloatRegisters::f17, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f18 = { FloatRegisters::f18, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f19 = { FloatRegisters::f19, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f20 = { FloatRegisters::f20, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f21 = { FloatRegisters::f21, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f22 = { FloatRegisters::f22, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f23 = { FloatRegisters::f23, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f24 = { FloatRegisters::f24, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f25 = { FloatRegisters::f25, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f26 = { FloatRegisters::f26, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f27 = { FloatRegisters::f27, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f28 = { FloatRegisters::f28, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f29 = { FloatRegisters::f29, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegisters::Double };
static MOZ_CONSTEXPR_VAR FloatRegister f31 = { FloatRegisters::f31, FloatRegisters::Double };
// MIPS64 CPUs can only load multibyte data that is "naturally"
// eight-byte-aligned, sp register should be sixteen-byte-aligned.
static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 16;
static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 16;
static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1,
"Stack alignment should be a non-zero multiple of sizeof(Value)");
// TODO this is just a filler to prevent a build failure. The MIPS SIMD
// alignment requirements still need to be explored.
// TODO Copy the static_asserts from x64/x86 assembler files.
static MOZ_CONSTEXPR_VAR uint32_t SimdMemoryAlignment = 16;
static MOZ_CONSTEXPR_VAR uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
static MOZ_CONSTEXPR_VAR Scale ScalePointer = TimesEight;
class Assembler : public AssemblerMIPSShared
{
public:
Assembler()
: AssemblerMIPSShared()
{ }
// MacroAssemblers hold onto gcthings, so they are traced by the GC.
void trace(JSTracer* trc);
static uintptr_t GetPointer(uint8_t*);
using AssemblerMIPSShared::bind;
using AssemblerMIPSShared::PatchDataWithValueCheck;
void bind(RepatchLabel* label);
void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address);
static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
void bind(InstImm* inst, uint64_t branch, uint64_t target);
// Copy the assembly code to the given buffer, and perform any pending
// relocations relying on the target address.
void executableCopy(uint8_t* buffer);
static uint32_t PatchWrite_NearCallSize();
static uint64_t ExtractLoad64Value(Instruction* inst0);
static void UpdateLoad64Value(Instruction* inst0, uint64_t value);
static void WriteLoad64Instructions(Instruction* inst0, Register reg, uint64_t value);
static void PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
static void PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
PatchedImmPtr expectedValue);
static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm);
static void ToggleCall(CodeLocationLabel inst_, bool enabled);
static void UpdateBoundsCheck(uint64_t logHeapSize, Instruction* inst);
static int64_t ExtractCodeLabelOffset(uint8_t* code);
}; // Assembler
static const uint32_t NumIntArgRegs = 8;
static const uint32_t NumFloatArgRegs = NumIntArgRegs;
static inline bool
GetIntArgReg(uint32_t usedArgSlots, Register* out)
{
if (usedArgSlots < NumIntArgRegs) {
*out = Register::FromCode(a0.code() + usedArgSlots);
return true;
}
return false;
}
static inline bool
GetFloatArgReg(uint32_t usedArgSlots, FloatRegister* out)
{
if (usedArgSlots < NumFloatArgRegs) {
*out = FloatRegister::FromCode(f12.code() + usedArgSlots);
return true;
}
return false;
}
// Get a register in which we plan to put a quantity that will be used as an
// integer argument. This differs from GetIntArgReg in that if we have no more
// actual argument registers to use we will fall back on using whatever
// CallTempReg* don't overlap the argument registers, and only fail once those
// run out too.
static inline bool
GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out)
{
// NOTE: We can't properly determine which regs are used if there are
// float arguments. If this is needed, we will have to guess.
MOZ_ASSERT(usedFloatArgs == 0);
if (GetIntArgReg(usedIntArgs, out))
return true;
// Unfortunately, we have to assume things about the point at which
// GetIntArgReg returns false, because we need to know how many registers it
// can allocate.
usedIntArgs -= NumIntArgRegs;
if (usedIntArgs >= NumCallTempNonArgRegs)
return false;
*out = CallTempNonArgRegs[usedIntArgs];
return true;
}
static inline uint32_t
GetArgStackDisp(uint32_t usedArgSlots)
{
MOZ_ASSERT(usedArgSlots >= NumIntArgRegs);
return (usedArgSlots - NumIntArgRegs) * sizeof(int64_t);
}
} // namespace jit
} // namespace js
#endif /* jit_mips64_Assembler_mips64_h */
+6 -1
View File
@@ -152,8 +152,13 @@ class AssemblerBuffer
bool ensureSpace(int size) {
// Space can exist in the most recent Slice.
if (tail && tail->length() + size <= tail->Capacity())
if (tail && tail->length() + size <= tail->Capacity()) {
// Simulate allocation failure even when we don't need a new slice.
if (js::oom::ShouldFailWithOOM())
return fail_oom();
return true;
}
// Otherwise, a new Slice must be added.
Slice* slice = newSlice(lifoAlloc_);
@@ -704,6 +704,8 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
// Mark and emit the guard branch.
markNextAsBranch();
this->putBytes(guardSize_ * InstSize, nullptr);
if (this->oom())
return;
BufferOffset afterPool = this->nextOffset();
Asm::WritePoolGuard(branch, this->getInst(branch), afterPool);
@@ -864,7 +866,7 @@ struct AssemblerBufferWithConstantPools : public AssemblerBuffer<SliceSize, Inst
}
inhibitNops_ = true;
while (sizeExcludingCurrentPool() & (alignment - 1))
while ((sizeExcludingCurrentPool() & (alignment - 1)) && !this->oom())
putInt(alignFillInst_);
inhibitNops_ = false;
}
@@ -78,7 +78,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
LInstruction* ins_;
public:
OutOfLineSimdFloatToIntCheck(Register temp, FloatRegister input, LInstruction* ins)
OutOfLineSimdFloatToIntCheck(Register temp, FloatRegister input, LInstruction *ins)
: temp_(temp), input_(input), ins_(ins)
{}
@@ -238,7 +238,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual void visitGuardClass(LGuardClass* guard);
virtual void visitEffectiveAddress(LEffectiveAddress* ins);
virtual void visitUDivOrMod(LUDivOrMod* ins);
virtual void visitUDivOrModConstant(LUDivOrModConstant* ins);
virtual void visitUDivOrModConstant(LUDivOrModConstant *ins);
virtual void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
virtual void visitMemoryBarrier(LMemoryBarrier* ins);
virtual void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir);
+17 -1
View File
@@ -11,6 +11,8 @@ component_intl = ('Core', 'JavaScript: Internationalization API')
component_jit = ('Core', 'JavaScript Engine: JIT')
component_stl = ('Core', 'JavaScript: Standard Library')
FILES_PER_UNIFIED_FILE = 6
with Files('../public/**'):
BUG_COMPONENT = component_engine
with Files('*'):
@@ -47,6 +49,10 @@ with Files('builtin/make_intl_data.py'):
with Files('../public/TrackedOptimizationInfo.h'):
BUG_COMPONENT = component_jit
if CONFIG['DEHYDRA_PATH']:
DIRS += ['analysis-tests']
if CONFIG['JS_BUNDLED_EDITLINE']:
DIRS += ['editline']
@@ -476,11 +482,16 @@ elif CONFIG['JS_CODEGEN_ARM64']:
'jit/arm64/vixl/MozSimulator-vixl.cpp',
'jit/arm64/vixl/Simulator-vixl.cpp'
]
elif CONFIG['JS_CODEGEN_MIPS32']:
elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
UNIFIED_SOURCES += [
'jit/mips-shared/Architecture-mips-shared.cpp',
'jit/mips-shared/Assembler-mips-shared.cpp',
'jit/mips-shared/Bailouts-mips-shared.cpp',
'jit/mips-shared/BaselineCompiler-mips-shared.cpp',
'jit/mips-shared/BaselineIC-mips-shared.cpp',
'jit/mips-shared/CodeGenerator-mips-shared.cpp',
'jit/mips-shared/Lowering-mips-shared.cpp',
'jit/mips-shared/MoveEmitter-mips-shared.cpp',
]
if CONFIG['JS_CODEGEN_MIPS32']:
UNIFIED_SOURCES += [
@@ -500,6 +511,11 @@ elif CONFIG['JS_CODEGEN_MIPS32']:
UNIFIED_SOURCES += [
'jit/mips32/Simulator-mips32.cpp'
]
elif CONFIG['JS_CODEGEN_MIPS64']:
UNIFIED_SOURCES += [
'jit/mips64/Architecture-mips64.cpp',
'jit/mips64/Assembler-mips64.cpp',
]
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
+2 -18
View File
@@ -164,15 +164,7 @@ JSObject2WrappedJSMap::SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const
Native2WrappedNativeMap*
Native2WrappedNativeMap::newMap(int length)
{
Native2WrappedNativeMap* map = new Native2WrappedNativeMap(length);
if (map && map->mTable)
return map;
// Allocation of the map or the creation of its hash table has
// failed. This will cause a nullptr deref later when we attempt
// to use the map, so we abort immediately to provide a more
// useful crash stack.
NS_RUNTIMEABORT("Ran out of memory.");
return nullptr;
return new Native2WrappedNativeMap(length);
}
Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
@@ -300,15 +292,7 @@ ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocS
ClassInfo2WrappedNativeProtoMap*
ClassInfo2WrappedNativeProtoMap::newMap(int length)
{
ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(length);
if (map && map->mTable)
return map;
// Allocation of the map or the creation of its hash table has
// failed. This will cause a nullptr deref later when we attempt
// to use the map, so we abort immediately to provide a more
// useful crash stack.
NS_RUNTIMEABORT("Ran out of memory.");
return nullptr;
return new ClassInfo2WrappedNativeProtoMap(length);
}
ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
+6 -4
View File
@@ -45,15 +45,16 @@ class ReftestManifest(object):
self.dirs = set()
self.files = set()
self.manifests = set()
self.tests = set()
def load(self, path):
"""Parse a reftest manifest file."""
normalized = os.path.normpath(os.path.abspath(path))
self.manifests.add(normalized)
normalized_path = os.path.normpath(os.path.abspath(path))
self.manifests.add(normalized_path)
if not self.path:
self.path = normalized
self.path = normalized_path
mdir = os.path.dirname(normalized)
mdir = os.path.dirname(normalized_path)
self.dirs.add(mdir)
with open(path, 'r') as fh:
@@ -123,3 +124,4 @@ class ReftestManifest(object):
test = os.path.normpath(os.path.join(mdir, urlprefix + f))
self.files.add(test)
self.dirs.add(os.path.dirname(test))
self.tests.add((test, normalized_path))
@@ -0,0 +1 @@
This is an example asset.
+2 -4
View File
@@ -28,11 +28,9 @@ LOCAL_INCLUDES += [
'/netwerk/streamconv/converters',
]
protocols = CONFIG['NECKO_PROTOCOLS'].copy()
if 'about' in protocols:
protocols.remove('about')
protocols = CONFIG['NECKO_PROTOCOLS']
LOCAL_INCLUDES += sorted([
'/netwerk/protocol/%s' % d for d in protocols
'/netwerk/protocol/%s' % d for d in protocols if d != 'about'
])
if CONFIG['OS_ARCH'] == 'WINNT':
+199 -1
View File
@@ -5,10 +5,13 @@
from __future__ import absolute_import, print_function, unicode_literals
import argparse
import glob
import logging
import mozpack.path as mozpath
import os
import platform
import subprocess
import sys
import which
from mozbuild.base import (
MachCommandBase,
@@ -20,6 +23,46 @@ from mach.decorators import (
Command,
)
ESLINT_NOT_FOUND_MESSAGE = '''
Could not find eslint! We looked at the --binary option, at the ESLINT
environment variable, and then at your path. Install eslint and needed plugins
with
mach eslint --setup
and try again.
'''.strip()
NODE_NOT_FOUND_MESSAGE = '''
nodejs is either not installed or is installed to a non-standard path.
Please install nodejs from https://nodejs.org and try again.
Valid installation paths:
'''.strip()
NPM_NOT_FOUND_MESSAGE = '''
Node Package Manager (npm) is either not installed or installed to a
non-standard path. Please install npm from https://nodejs.org (it comes as an
option in the node installation) and try again.
Valid installation paths:
'''.strip()
ESLINT_PROMPT = '''
Would you like to use eslint
'''.strip()
ESLINT_PLUGIN_MOZILLA_PROMPT = '''
eslint-plugin-mozilla is an eslint plugin containing rules that help enforce
JavaScript coding standards in the Mozilla project. Would you like to use this
plugin
'''.strip()
ESLINT_PLUGIN_REACT_PROMPT = '''
eslint-plugin-react is an eslint plugin containing rules that help React
developers follow strict guidelines. Would you like to install it
'''.strip()
@CommandProvider
class MachCommands(MachCommandBase):
@@ -53,6 +96,7 @@ class MachCommands(MachCommandBase):
help='Tests to run. Each test can be a single file or a directory.')
def python_test(self, tests, verbose=False, stop=False):
self._activate_virtualenv()
import glob
# Python's unittest, and in particular discover, has problems with
# clashing namespaces when importing multiple test modules. What follows
@@ -119,3 +163,157 @@ class MachCommands(MachCommandBase):
return 1
return 0 if return_code == 0 else 1
@Command('eslint', category='devenv',
description='Run eslint or help configure eslint for optimal development.')
@CommandArgument('-s', '--setup', default=False, action='store_true',
help='configure eslint for optimal development.')
@CommandArgument('path', nargs='?', default='.',
help='Path to files to lint, like "browser/components/loop" '
'or "mobile/android". '
'Defaults to the current directory if not given.')
@CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx]',
help='Filename extensions to lint, default: "[.js,.jsm,.jsx]".')
@CommandArgument('-b', '--binary', default=None,
help='Path to eslint binary.')
@CommandArgument('args', nargs=argparse.REMAINDER) # Passed through to eslint.
def eslint(self, setup, path, ext=None, binary=None, args=[]):
'''Run eslint.'''
if setup:
return self.eslint_setup()
if not binary:
binary = os.environ.get('ESLINT', None)
if not binary:
try:
binary = which.which('eslint')
except which.WhichError:
pass
if not binary:
print(ESLINT_NOT_FOUND_MESSAGE)
return 1
# The cwd below is unfortunate. eslint --config=PATH/TO/.eslintrc works,
# but --ignore-path=PATH/TO/.eslintignore treats paths as relative to
# the current directory, rather than as relative to the location of
# .eslintignore (see https://github.com/eslint/eslint/issues/1382).
# mach commands always execute in the topsrcdir, so we could make all
# paths in .eslint relative to the topsrcdir, but it's not clear if
# that's a good choice for future eslint and IDE integrations.
# Unfortunately, running after chdir does not print the full path to
# files (convenient for opening with copy-and-paste). In the meantime,
# we just print the active path.
self.log(logging.INFO, 'eslint', {'binary': binary, 'path': path},
'Running {binary} in {path}')
cmd_args = [binary,
'--ext', ext, # This keeps ext as a single argument.
] + args
# Path must come after arguments. Path is '.' due to cwd below.
cmd_args += ['.']
return self.run_process(cmd_args,
cwd=path,
pass_thru=True, # Allow user to run eslint interactively.
ensure_exit_code=False, # Don't throw on non-zero exit code.
)
def eslint_setup(self, update_only=False):
"""Ensure eslint is optimally configured.
This command will inspect your eslint configuration and
guide you through an interactive wizard helping you configure
eslint for optimal use on Mozilla projects.
"""
sys.path.append(os.path.dirname(__file__))
# At the very least we need node installed.
nodePath = self.getNodeOrNpmPath("node")
if not nodePath:
return 1
npmPath = self.getNodeOrNpmPath("npm")
if not npmPath:
return 1
# Install eslint.
print("Installing eslint...")
with open(os.devnull, "w") as fnull:
subprocess.call([npmPath, "install", "eslint", "-g"],
stdout=fnull, stderr=fnull)
# Install eslint-plugin-mozilla.
print("")
print("Installing eslint-plugin-mozilla...")
with open(os.devnull, "w") as fnull:
subprocess.call([npmPath, "link"],
cwd="testing/eslint-plugin-mozilla",
stdout=fnull, stderr=fnull)
# Install eslint-plugin-react.
print("")
print("Installing eslint-plugin-react...")
with open(os.devnull, "w") as fnull:
subprocess.call([npmPath, "install", "-g", "eslint-plugin-react"],
stdout=fnull, stderr=fnull)
def getPossibleNodePathsWin(self):
"""
Return possible nodejs paths on Windows.
"""
if platform.system() != "Windows":
return []
return {
"%s\\nodejs" % os.environ.get("SystemDrive"),
os.path.join(os.environ.get("ProgramFiles"), "nodejs"),
os.path.join(os.environ.get("PROGRAMW6432"), "nodejs"),
os.path.join(os.environ.get("PROGRAMFILES"), "nodejs")
}
def getNodeOrNpmPath(self, filename):
"""
Return the nodejs or npm path.
"""
try:
appPath = which.which(filename)
return appPath
except which.WhichError:
pass
if platform.system() == "Windows":
try:
for ext in ["", ".cmd", ".exe"]:
nodeOrNpmPath = which.which(filename + ext,
path=self.getPossibleNodePathsWin())
if self.is_valid(nodeOrNpmPath):
return nodeOrNpmPath
except which.WhichError:
pass
if filename == "node":
print(NODE_NOT_FOUND_MESSAGE)
elif filename == "npm":
print(NPM_NOT_FOUND_MESSAGE)
if platform.system() == "Windows":
appPaths = self.getPossibleNodePathsWin()
for p in appPaths:
print(" - " + p)
elif platform.system() == "Darwin":
print(" - /usr/local/bin/node")
elif platform.system() == "Linux":
print(" - /usr/bin/nodejs")
return None
def is_valid(self, path):
try:
with open(os.devnull, "w") as fnull:
subprocess.check_call([path, "--version"], stdout=fnull)
return True
except subprocess.CalledProcessError:
return False
+5 -1
View File
@@ -12,12 +12,16 @@ from __future__ import absolute_import, print_function
import sys
import os
from mozbuild.util import lock_file
from mozbuild.util import (
ensureParentDir,
lock_file,
)
def addEntriesToListFile(listFile, entries):
"""Given a file |listFile| containing one entry per line,
add each entry in |entries| to the file, unless it is already
present."""
ensureParentDir(listFile)
lock = lock_file(listFile + ".lck")
try:
if os.path.exists(listFile):
@@ -8,6 +8,7 @@ import argparse
import sys
from mozpack.copier import FileCopier
from mozpack.manifests import InstallManifest
from mozbuild.util import DefinesAction
COMPLETE = 'From {dest}: Kept {existing} existing; Added/updated {updated}; ' \
@@ -17,19 +18,36 @@ COMPLETE = 'From {dest}: Kept {existing} existing; Added/updated {updated}; ' \
def process_manifest(destdir, paths,
remove_unaccounted=True,
remove_all_directory_symlinks=True,
remove_empty_directories=True):
remove_empty_directories=True,
defines={}):
manifest = InstallManifest()
for path in paths:
manifest |= InstallManifest(path=path)
copier = FileCopier()
manifest.populate_registry(copier)
manifest.populate_registry(copier, defines_override=defines)
return copier.copy(destdir,
remove_unaccounted=remove_unaccounted,
remove_all_directory_symlinks=remove_all_directory_symlinks,
remove_empty_directories=remove_empty_directories)
class DefinesAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
defines = getattr(namespace, self.dest)
if defines is None:
defines = {}
values = values.split('=', 1)
if len(values) == 1:
name, value = values[0], 1
else:
name, value = values
if value.isdigit():
value = int(value)
defines[name] = value
setattr(namespace, self.dest, defines)
def main(argv):
parser = argparse.ArgumentParser(
description='Process install manifest files.')
@@ -42,13 +60,17 @@ def main(argv):
help='Do not remove all directory symlinks from destination.')
parser.add_argument('--no-remove-empty-directories', action='store_true',
help='Do not remove empty directories from destination.')
parser.add_argument('-D', action=DefinesAction,
dest='defines', metavar="VAR[=VAL]",
help='Define a variable to override what is specified in the manifest')
args = parser.parse_args(argv)
result = process_manifest(args.destdir, args.manifests,
remove_unaccounted=not args.no_remove,
remove_all_directory_symlinks=not args.no_remove_all_directory_symlinks,
remove_empty_directories=not args.no_remove_empty_directories)
remove_empty_directories=not args.no_remove_empty_directories,
defines=args.defines)
print(COMPLETE.format(dest=args.destdir,
existing=result.existing_files_count,
@@ -55,21 +55,19 @@ class AndroidEclipseBackend(CommonBackend):
"""Write out Android Eclipse project files."""
if not isinstance(obj, ContextDerived):
return
return False
CommonBackend.consume_object(self, obj)
if CommonBackend.consume_object(self, obj):
# If CommonBackend acknowledged the object, we're done with it.
return True
# If CommonBackend acknowledged the object, we're done with it.
if obj._ack:
return
# We don't want to handle most things, so we just acknowledge all objects...
obj.ack()
# ... and handle the one case we care about specially.
# Handle the one case we care about specially.
if isinstance(obj, ContextWrapped) and isinstance(obj.wrapped, AndroidEclipseProjectData):
self._process_android_eclipse_project_data(obj.wrapped, obj.srcdir, obj.objdir)
# We don't want to handle most things, so we just acknowledge all objects
return True
def consume_finished(self):
"""The common backend handles WebIDL and test files. We don't handle
these, so we don't call our superclass.
+2 -1
View File
@@ -117,7 +117,8 @@ class BuildBackend(LoggingMixin):
"""
for obj in objs:
obj_start = time.time()
self.consume_object(obj)
if not self.consume_object(obj):
raise Exception('Unhandled object of type %s' % type(obj))
self._execution_time += time.time() - obj_start
if isinstance(obj, ContextDerived):
+3 -3
View File
@@ -206,7 +206,7 @@ class CommonBackend(BuildBackend):
# Do not handle ConfigFileSubstitution for Makefiles. Leave that
# to other
if mozpath.basename(obj.output_path) == 'Makefile':
return
return False
with self._get_preprocessor(obj) as pp:
pp.do_include(obj.input_path)
self.backend_input_files.add(obj.input_path)
@@ -251,9 +251,9 @@ class CommonBackend(BuildBackend):
if hasattr(self, '_process_unified_sources'):
self._process_unified_sources(obj)
else:
return
return False
obj.ack()
return True
def consume_finished(self):
if len(self._idl_manager.idls):
@@ -27,6 +27,8 @@ else:
class BuildConfig(object):
"""Represents the output of configure."""
_CODE_CACHE = {}
def __init__(self):
self.topsrcdir = None
self.topobjdir = None
@@ -35,26 +37,35 @@ class BuildConfig(object):
self.substs = {}
self.files = []
@staticmethod
def from_config_status(path):
@classmethod
def from_config_status(cls, path):
"""Create an instance from a config.status file."""
code_cache = cls._CODE_CACHE
mtime = os.path.getmtime(path)
with open(path, 'rt') as fh:
source = fh.read()
code = compile(source, path, 'exec', dont_inherit=1)
g = {
'__builtins__': __builtins__,
'__file__': path,
}
l = {}
exec(code, g, l)
# cache the compiled code as it can be reused
# we cache it the first time, or if the file changed
if not path in code_cache or code_cache[path][0] != mtime:
with open(path, 'rt') as fh:
source = fh.read()
code_cache[path] = (
mtime,
compile(source, path, 'exec', dont_inherit=1)
)
config = BuildConfig()
g = {
'__builtins__': __builtins__,
'__file__': path,
}
l = {}
exec(code_cache[path][1], g, l)
for name in l['__all__']:
setattr(config, name, l[name])
config = BuildConfig()
return config
for name in l['__all__']:
setattr(config, name, l[name])
return config
class ConfigEnvironment(object):
@@ -65,8 +65,6 @@ class CppEclipseBackend(CommonBackend):
return os.path.join(srcdir_parent, workspace_dirname)
def consume_object(self, obj):
obj.ack()
reldir = getattr(obj, 'relativedir', None)
# Note that unlike VS, Eclipse' indexer seem to crawl the headers and
@@ -74,6 +72,8 @@ class CppEclipseBackend(CommonBackend):
if isinstance(obj, Defines):
self._paths_to_defines.setdefault(reldir, {}).update(obj.defines)
return True
def consume_finished(self):
settings_dir = os.path.join(self._project_dir, '.settings')
launch_dir = os.path.join(self._project_dir, 'RunConfigurations')
@@ -0,0 +1,244 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import, unicode_literals
from mozbuild.backend.common import CommonBackend
from mozbuild.frontend.data import (
ContextDerived,
Defines,
DistFiles,
FinalTargetFiles,
JARManifest,
JavaScriptModules,
JsPreferenceFile,
Resources,
VariablePassthru,
)
from mozbuild.makeutil import Makefile
from mozbuild.util import OrderedDefaultDict
from mozpack.manifests import InstallManifest
import mozpack.path as mozpath
from collections import OrderedDict
from itertools import chain
class FasterMakeBackend(CommonBackend):
def _init(self):
super(FasterMakeBackend, self)._init()
self._seen_directories = set()
self._defines = dict()
self._jar_manifests = OrderedDict()
self._manifest_entries = OrderedDefaultDict(list)
self._install_manifests = OrderedDefaultDict(InstallManifest)
def _add_preprocess(self, obj, path, dest, **kwargs):
target = mozpath.basename(path)
# This matches what PP_TARGETS do in config/rules.
if target.endswith('.in'):
target = target[:-3]
depfile = mozpath.join(
self.environment.topobjdir, 'faster', '.deps',
mozpath.join(obj.install_target, dest, target).replace('/', '_'))
self._install_manifests[obj.install_target].add_preprocess(
mozpath.join(obj.srcdir, path),
mozpath.join(dest, target),
depfile,
**kwargs)
def consume_object(self, obj):
if not isinstance(obj, Defines) and isinstance(obj, ContextDerived):
defines = self._defines.get(obj.objdir, {})
if defines:
defines = defines.defines
if isinstance(obj, Defines):
self._defines[obj.objdir] = obj
# We're assuming below that Defines come first for a given objdir,
# which is kind of set in stone from the order things are treated
# in emitter.py.
assert obj.objdir not in self._seen_directories
elif isinstance(obj, JARManifest) and \
obj.install_target.startswith('dist/bin'):
defines = self._defines.get(obj.objdir, [])
if defines:
defines = list(defines.get_defines())
self._jar_manifests[obj.path] = (obj.objdir,
obj.install_target,
defines)
elif isinstance(obj, VariablePassthru) and \
obj.install_target.startswith('dist/bin'):
for f in obj.variables.get('EXTRA_COMPONENTS', {}):
path = mozpath.join(obj.install_target, 'components',
mozpath.basename(f))
self._install_manifests[obj.install_target].add_symlink(
mozpath.join(obj.srcdir, f),
mozpath.join('components', mozpath.basename(f))
)
if f.endswith('.manifest'):
manifest = mozpath.join(obj.install_target,
'chrome.manifest')
self._manifest_entries[manifest].append(
'manifest components/%s' % mozpath.basename(f))
for f in obj.variables.get('EXTRA_PP_COMPONENTS', {}):
self._add_preprocess(obj, f, 'components', defines=defines)
if f.endswith('.manifest'):
manifest = mozpath.join(obj.install_target,
'chrome.manifest')
self._manifest_entries[manifest].append(
'manifest components/%s' % mozpath.basename(f))
elif isinstance(obj, JavaScriptModules) and \
obj.install_target.startswith('dist/bin'):
for path, strings in obj.modules.walk():
base = mozpath.join('modules', path)
for f in strings:
if obj.flavor == 'extra':
self._install_manifests[obj.install_target].add_symlink(
mozpath.join(obj.srcdir, f),
mozpath.join(base, mozpath.basename(f))
)
elif obj.flavor == 'extra_pp':
self._add_preprocess(obj, f, base, defines=defines)
elif isinstance(obj, JsPreferenceFile) and \
obj.install_target.startswith('dist/bin'):
# The condition for the directory value in config/rules.mk is:
# ifneq (,$(DIST_SUBDIR)$(XPI_NAME)$(LIBXUL_SDK))
# - LIBXUL_SDK is not supported (it likely doesn't work in the
# recursive backend anyways
# - when XPI_NAME is set, obj.install_target will start with
# dist/xpi-stage
# - when DIST_SUBDIR is set, obj.install_target will start with
# dist/bin/$(DIST_SUBDIR)
# So an equivalent condition that is not cumbersome for us and that
# is enough at least for now is checking if obj.install_target is
# different from dist/bin.
if obj.install_target == 'dist/bin':
pref_dir = 'defaults/pref'
else:
pref_dir = 'defaults/preferences'
dest = mozpath.join(obj.install_target, pref_dir,
mozpath.basename(obj.path))
# We preprocess these, but they don't necessarily have preprocessor
# directives, so tell the preprocessor to not complain about that.
self._add_preprocess(obj, obj.path, pref_dir, defines=defines,
silence_missing_directive_warnings=True)
elif isinstance(obj, Resources) and \
obj.install_target.startswith('dist/bin'):
for path, strings in obj.resources.walk():
base = mozpath.join('res', path)
for f in strings:
flags = strings.flags_for(f)
if flags and flags.preprocess:
self._add_preprocess(obj, f, base, marker='%',
defines=obj.defines)
else:
self._install_manifests[obj.install_target].add_symlink(
mozpath.join(obj.srcdir, f),
mozpath.join(base, mozpath.basename(f))
)
elif isinstance(obj, FinalTargetFiles) and \
obj.install_target.startswith('dist/bin'):
for path, strings in obj.files.walk():
base = mozpath.join(obj.install_target, path)
for f in strings:
self._install_manifests[obj.install_target].add_symlink(
mozpath.join(obj.srcdir, f),
mozpath.join(path, mozpath.basename(f))
)
elif isinstance(obj, DistFiles) and \
obj.install_target.startswith('dist/bin'):
# We preprocess these, but they don't necessarily have preprocessor
# directives, so tell the preprocessor to not complain about that.
for f in obj.files:
self._add_preprocess(obj, f, '', defines=defines,
silence_missing_directive_warnings=True)
else:
# We currently ignore a lot of object types, so just acknowledge
# everything.
return True
self._seen_directories.add(obj.objdir)
return True
def consume_finished(self):
mk = Makefile()
# Add the default rule at the very beginning.
mk.create_rule(['default'])
mk.add_statement('TOPSRCDIR = %s' % self.environment.topsrcdir)
mk.add_statement('TOPOBJDIR = %s' % self.environment.topobjdir)
# Add a few necessary variables inherited from configure
for var in (
'PYTHON',
'ACDEFINES',
'MOZ_CHROME_FILE_FORMAT',
):
mk.add_statement('%s = %s' % (var, self.environment.substs[var]))
# Add all necessary information for jar manifest processing
jar_mn_targets = []
for path, (objdir, install_target, defines) in \
self._jar_manifests.iteritems():
rel_manifest = mozpath.relpath(path, self.environment.topsrcdir)
target = rel_manifest.replace('/', '-')
assert target not in jar_mn_targets
jar_mn_targets.append(target)
target = 'jar-%s' % target
mk.create_rule([target]).add_dependencies([path])
if objdir != mozpath.join(self.environment.topobjdir,
mozpath.dirname(rel_manifest)):
mk.create_rule([target]).add_dependencies(
['objdir = %s' % objdir])
if install_target != 'dist/bin':
mk.create_rule([target]).add_dependencies(
['install_target = %s' % install_target])
if defines:
mk.create_rule([target]).add_dependencies(
['defines = %s' % ' '.join(defines)])
mk.add_statement('JAR_MN_TARGETS = %s' % ' '.join(jar_mn_targets))
# Add information for chrome manifest generation
manifest_targets = []
for target, entries in self._manifest_entries.iteritems():
manifest_targets.append(target)
target = '$(TOPOBJDIR)/%s' % target
mk.create_rule([target]).add_dependencies(
['content = %s' % ' '.join('"%s"' % e for e in entries)])
mk.add_statement('MANIFEST_TARGETS = %s' % ' '.join(manifest_targets))
# Add information for install manifests.
mk.add_statement('INSTALL_MANIFESTS = %s'
% ' '.join(self._install_manifests.keys()))
mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk')
for base, install_manifest in self._install_manifests.iteritems():
with self._write_file(
mozpath.join(self.environment.topobjdir, 'faster',
'install_%s' % base.replace('/', '_'))) as fh:
install_manifest.write(fileobj=fh)
with self._write_file(
mozpath.join(self.environment.topobjdir, 'faster',
'Makefile')) as fh:
mk.dump(fh, removal_guard=False)
@@ -26,6 +26,10 @@ import mozpack.path as mozpath
from .common import CommonBackend
from ..frontend.data import (
AndroidAssetsDirs,
AndroidResDirs,
AndroidExtraResDirs,
AndroidExtraPackages,
AndroidEclipseProjectData,
BrandingFiles,
ConfigFileSubstitution,
@@ -71,6 +75,11 @@ from ..util import (
from ..makeutil import Makefile
MOZBUILD_VARIABLES = [
b'ANDROID_APK_NAME',
b'ANDROID_APK_PACKAGE',
b'ANDROID_ASSETS_DIRS',
b'ANDROID_EXTRA_PACKAGES',
b'ANDROID_EXTRA_RES_DIRS',
b'ANDROID_GENERATED_RESFILES',
b'ANDROID_RES_DIRS',
b'ASFLAGS',
@@ -419,11 +428,11 @@ class RecursiveMakeBackend(CommonBackend):
"""Write out build files necessary to build with recursive make."""
if not isinstance(obj, ContextDerived):
return
return False
backend_file = self._get_backend_file_for(obj)
CommonBackend.consume_object(self, obj)
consumed = CommonBackend.consume_object(self, obj)
# CommonBackend handles XPIDLFile and TestManifest, but we want to do
# some extra things for them.
@@ -436,8 +445,8 @@ class RecursiveMakeBackend(CommonBackend):
self._process_test_manifest(obj, backend_file)
# If CommonBackend acknowledged the object, we're done with it.
if obj._ack:
return
if consumed:
return True
if isinstance(obj, DirectoryTraversal):
self._process_directory_traversal(obj, backend_file)
@@ -514,7 +523,7 @@ class RecursiveMakeBackend(CommonBackend):
elif isinstance(obj, Resources):
self._process_resources(obj, obj.resources, backend_file)
elif isinstance(obj, BrandingFiles):
self._process_branding_files(obj, obj.files, backend_file)
@@ -569,7 +578,7 @@ class RecursiveMakeBackend(CommonBackend):
elif isinstance(obj.wrapped, AndroidEclipseProjectData):
self._process_android_eclipse_project_data(obj.wrapped, backend_file)
else:
return
return False
elif isinstance(obj, SharedLibrary):
self._process_shared_library(obj, backend_file)
@@ -594,9 +603,26 @@ class RecursiveMakeBackend(CommonBackend):
for f in obj.files:
backend_file.write('DIST_FILES += %s\n' % f)
elif isinstance(obj, AndroidResDirs):
for p in obj.paths:
backend_file.write('ANDROID_RES_DIRS += %s\n' % p.full_path)
elif isinstance(obj, AndroidAssetsDirs):
for p in obj.paths:
backend_file.write('ANDROID_ASSETS_DIRS += %s\n' % p.full_path)
elif isinstance(obj, AndroidExtraResDirs):
for p in obj.paths:
backend_file.write('ANDROID_EXTRA_RES_DIRS += %s\n' % p.full_path)
elif isinstance(obj, AndroidExtraPackages):
for p in obj.packages:
backend_file.write('ANDROID_EXTRA_PACKAGES += %s\n' % p)
else:
return
obj.ack()
return False
return True
def _fill_root_mk(self):
"""
@@ -1066,6 +1092,7 @@ INSTALL_TARGETS += %(prefix)s
modules = manager.modules
xpt_modules = sorted(modules.keys())
xpt_files = set()
registered_xpt_files = set()
mk = Makefile()
@@ -1097,15 +1124,16 @@ INSTALL_TARGETS += %(prefix)s
rules = StringIO()
mk.dump(rules, removal_guard=False)
# Write out manifests defining interfaces
interfaces_manifests = []
dist_dir = mozpath.join(self.environment.topobjdir, 'dist')
for manifest, entries in manager.interface_manifests.items():
path = mozpath.join(self.environment.topobjdir, manifest)
with self._write_file(path) as fh:
for xpt in sorted(entries):
fh.write('interfaces %s\n' % xpt)
interfaces_manifests.append(mozpath.join('$(DEPTH)', manifest))
for xpt in sorted(entries):
registered_xpt_files.add(mozpath.join(
'$(DEPTH)', mozpath.dirname(manifest), xpt))
if install_target.startswith('dist/'):
path = mozpath.join(self.environment.topobjdir, manifest)
path = mozpath.relpath(path, dist_dir)
prefix, subpath = path.split('/', 1)
key = 'dist_%s' % prefix
@@ -1128,9 +1156,11 @@ INSTALL_TARGETS += %(prefix)s
obj.config = self.environment
self._create_makefile(obj, extra=dict(
chrome_manifests = ' '.join(chrome_manifests),
interfaces_manifests = ' '.join(interfaces_manifests),
xpidl_rules=rules.getvalue(),
xpidl_modules=' '.join(xpt_modules),
xpt_files=' '.join(sorted(xpt_files)),
xpt_files=' '.join(sorted(xpt_files - registered_xpt_files)),
registered_xpt_files=' '.join(sorted(registered_xpt_files)),
))
def _process_program(self, program, backend_file):
@@ -93,9 +93,6 @@ class VisualStudioBackend(CommonBackend):
path=os.path.join(self._out_dir, 'mozilla.sln'))
def consume_object(self, obj):
# Just acknowledge everything.
obj.ack()
reldir = getattr(obj, 'relativedir', None)
if hasattr(obj, 'config') and reldir not in self._paths_to_configs:
@@ -130,6 +127,9 @@ class VisualStudioBackend(CommonBackend):
else:
includes.append(os.path.join('$(TopSrcDir)', reldir, p))
# Just acknowledge everything.
return True
def _add_sources(self, reldir, obj):
s = self._paths_to_sources.setdefault(reldir, set())
s.update(obj.files)
@@ -26,12 +26,9 @@ class Introspection(MachCommandBase):
help='Source file to display compilation flags for')
def compileflags(self, what):
from mozbuild.util import resolve_target_to_make
import shlex
from mozbuild.compilation import util
top_make = os.path.join(self.topobjdir, 'Makefile')
if not os.path.exists(top_make):
print('Your tree has not been built yet. Please run '
'|mach build| with no arguments.')
if not util.check_top_objdir(self.topobjdir):
return 1
path_arg = self._wrap_path_argument(what)
@@ -42,23 +39,7 @@ class Introspection(MachCommandBase):
if make_dir is None and make_target is None:
return 1
build_vars = {}
def on_line(line):
elements = [s.strip() for s in line.split('=', 1)]
if len(elements) != 2:
return
build_vars[elements[0]] = elements[1]
try:
old_logger = self.log_manager.replace_terminal_handler(None)
self._run_make(directory=make_dir, target='showbuild', log=False,
print_directory=False, allow_parallel=False, silent=True,
line_handler=on_line)
finally:
self.log_manager.replace_terminal_handler(old_logger)
build_vars = util.get_build_vars(make_dir, self)
if what.endswith('.c'):
name = 'COMPILE_CFLAGS'
@@ -68,20 +49,5 @@ class Introspection(MachCommandBase):
if name not in build_vars:
return
flags = ['-isystem', '-I', '-include', '-MF']
new_args = []
path = os.path.join(self.topobjdir, make_dir)
for arg in shlex.split(build_vars[name]):
if new_args and new_args[-1] in flags:
arg = os.path.normpath(os.path.join(path, arg))
else:
flag = [(f, arg[len(f):]) for f in flags + ['--sysroot=']
if arg.startswith(f)]
if flag:
flag, val = flag[0]
if val:
arg = flag + os.path.normpath(os.path.join(path, val))
new_args.append(arg)
print(' '.join(new_args))
print(util.get_flags(self.topobjdir, make_dir, build_vars, name))
@@ -0,0 +1,119 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# This modules provides functionality for dealing with code completion.
import os
from mozbuild.base import MozbuildObject
from mozbuild.compilation import util
from mozbuild.backend.common import CommonBackend
from mozbuild.frontend.data import (
Sources,
HostSources,
UnifiedSources,
GeneratedSources,
)
from mach.config import ConfigSettings
from mach.logging import LoggingManager
class CompileDBBackend(CommonBackend):
def _init(self):
CommonBackend._init(self)
if not util.check_top_objdir(self.environment.topobjdir):
raise Exception()
# The database we're going to dump out to.
self._db = []
# The cache for per-directory flags
self._flags = {}
log_manager = LoggingManager()
self._cmd = MozbuildObject(self.environment.topsrcdir, ConfigSettings(),
log_manager, self.environment.topobjdir)
def consume_object(self, obj):
if isinstance(obj, UnifiedSources):
# For unified sources, only include the unified source file.
# Note that unified sources are never used for host sources.
for f in obj.unified_source_mapping:
flags = self._get_dir_flags(obj.objdir)
self._build_db_line(obj, self.environment, f[0],
obj.canonical_suffix, flags, False)
elif isinstance(obj, Sources) or isinstance(obj, HostSources) or \
isinstance(obj, GeneratedSources):
# For other sources, include each source file.
for f in obj.files:
flags = self._get_dir_flags(obj.objdir)
self._build_db_line(obj, self.environment, f,
obj.canonical_suffix, flags,
isinstance(obj, HostSources))
return True
def consume_finished(self):
import json
# Output the database (a JSON file) to objdir/compile_commands.json
outputfile = os.path.join(self.environment.topobjdir, 'compile_commands.json')
with self._write_file(outputfile) as jsonout:
json.dump(self._db, jsonout, indent=0)
def _get_dir_flags(self, directory):
if directory in self._flags:
return self._flags[directory]
from mozbuild.util import resolve_target_to_make
make_dir, make_target = resolve_target_to_make(self.environment.topobjdir, directory)
if make_dir is None and make_target is None:
raise Exception('Cannot figure out the make dir and target for ' + directory)
build_vars = util.get_build_vars(directory, self._cmd)
# We only care about the following build variables.
for name in ('COMPILE_CFLAGS', 'COMPILE_CXXFLAGS',
'COMPILE_CMFLAGS', 'COMPILE_CMMFLAGS'):
if name not in build_vars:
continue
build_vars[name] = util.get_flags(self.environment.topobjdir, directory,
build_vars, name)
self._flags[directory] = build_vars
return self._flags[directory]
def _build_db_line(self, obj, cenv, filename, canonical_suffix, flags, ishost):
# Distinguish between host and target files.
prefix = 'HOST_' if ishost else ''
if canonical_suffix == '.c':
compiler = cenv.substs[prefix + 'CC']
cflags = flags['COMPILE_CFLAGS']
# Add the Objective-C flags if needed.
if filename.endswith('.m'):
cflags += ' ' + flags['COMPILE_CMFLAGS']
elif canonical_suffix == '.cpp':
compiler = cenv.substs[prefix + 'CXX']
cflags = flags['COMPILE_CXXFLAGS']
# Add the Objective-C++ flags if needed.
if filename.endswith('.mm'):
cflags += ' ' + flags['COMPILE_CMMFLAGS']
else:
return
cmd = ' '.join([
compiler,
'-o', '/dev/null', '-c',
cflags,
filename,
])
self._db.append({
'directory': obj.objdir,
'command': cmd,
'file': filename
})
@@ -0,0 +1,63 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import shlex
def check_top_objdir(topobjdir):
top_make = os.path.join(topobjdir, 'Makefile')
if not os.path.exists(top_make):
print('Your tree has not been built yet. Please run '
'|mach build| with no arguments.')
return False
return True
def get_build_vars(directory, cmd):
build_vars = {}
def on_line(line):
elements = [s.strip() for s in line.split('=', 1)]
if len(elements) != 2:
return
build_vars[elements[0]] = elements[1]
try:
old_logger = cmd.log_manager.replace_terminal_handler(None)
cmd._run_make(directory=directory, target='showbuild', log=False,
print_directory=False, allow_parallel=False, silent=True,
line_handler=on_line)
finally:
cmd.log_manager.replace_terminal_handler(old_logger)
return build_vars
def get_flags(topobjdir, make_dir, build_vars, name):
flags = ['-isystem', '-I', '-include', '-MF']
new_args = []
path = os.path.join(topobjdir, make_dir)
# Take case to handle things such as the following correctly:
# * -DMOZ_APP_VERSION='"40.0a1"'
# * -DR_PLATFORM_INT_TYPES='<stdint.h>'
# * -DAPP_ID='{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
# * -D__UNUSED__='__attribute__((unused))'
lex = shlex.shlex(build_vars[name])
lex.quotes = '"'
lex.wordchars += '+/\'"-=.*{}()[]<>'
for arg in list(lex):
if new_args and new_args[-1] in flags:
arg = os.path.normpath(os.path.join(path, arg))
else:
flag = [(f, arg[len(f):]) for f in flags + ['--sysroot=']
if arg.startswith(f)]
if flag:
flag, val = flag[0]
if val:
arg = flag + os.path.normpath(os.path.join(path, val))
new_args.append(arg)
return ' '.join(new_args)
@@ -12,6 +12,7 @@ import os
import re
from mozbuild.util import hash_file
import mozpack.path as mozpath
# Regular expression to strip ANSI color sequences from a string. This is
@@ -147,17 +148,19 @@ class WarningsDatabase(object):
for w in value['warnings']:
yield w
@property
def type_counts(self):
def type_counts(self, dirpath=None):
"""Returns a mapping of warning types to their counts."""
types = {}
for value in self._files.values():
for warning in value['warnings']:
count = types.get(warning['flag'], 0)
if dirpath and not mozpath.normsep(warning['filename']).startswith(dirpath):
continue
flag = warning['flag']
count = types.get(flag, 0)
count += 1
types[warning['flag']] = count
types[flag] = count
return types
+4 -1
View File
@@ -108,7 +108,7 @@ def config_status(topobjdir='.', topsrcdir='.',
help='print diffs of changed files.')
parser.add_argument('-b', '--backend', nargs='+',
choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
'VisualStudio', 'FasterMake'],
'VisualStudio', 'FasterMake', 'CompileDB'],
default=default_backends,
help='what backend to build (default: %s).' %
' '.join(default_backends))
@@ -145,6 +145,9 @@ def config_status(topobjdir='.', topsrcdir='.',
elif backend == 'FasterMake':
from mozbuild.backend.fastermake import FasterMakeBackend
backends_cls.append(FasterMakeBackend)
elif backend == 'CompileDB':
from mozbuild.compilation.database import CompileDBBackend
backends_cls.append(CompileDBBackend)
else:
backends_cls.append(RecursiveMakeBackend)
+222 -16
View File
@@ -18,7 +18,10 @@ from __future__ import absolute_import, unicode_literals
import os
from collections import OrderedDict
from collections import (
Counter,
OrderedDict,
)
from mozbuild.util import (
HierarchicalStringList,
HierarchicalStringListWithFlagsFactory,
@@ -32,9 +35,10 @@ from mozbuild.util import (
TypedList,
TypedNamedTuple,
)
from ..testing import all_test_flavors
import mozpack.path as mozpath
from types import FunctionType
from UserString import UserString
import itertools
@@ -43,6 +47,7 @@ class ContextDerivedValue(object):
"""Classes deriving from this one receive a special treatment in a
Context. See Context documentation.
"""
__slots__ = ()
class Context(KeyedDefaultDict):
@@ -326,8 +331,13 @@ class PathMeta(type):
assert isinstance(context, Context)
if isinstance(value, Path):
context = value.context
if not issubclass(cls, (SourcePath, ObjDirPath)):
cls = ObjDirPath if value.startswith('!') else SourcePath
if not issubclass(cls, (SourcePath, ObjDirPath, AbsolutePath)):
if value.startswith('!'):
cls = ObjDirPath
elif value.startswith('%'):
cls = AbsolutePath
else:
cls = SourcePath
return super(PathMeta, cls).__call__(context, value)
class Path(ContextDerivedValue, unicode):
@@ -339,6 +349,7 @@ class Path(ContextDerivedValue, unicode):
- 'srcdir/relative/paths'
- '!/topobjdir/relative/paths'
- '!objdir/relative/paths'
- '%/filesystem/absolute/paths'
"""
__metaclass__ = PathMeta
@@ -394,6 +405,8 @@ class SourcePath(Path):
def __init__(self, context, value):
if value.startswith('!'):
raise ValueError('Object directory paths are not allowed')
if value.startswith('%'):
raise ValueError('Filesystem absolute paths are not allowed')
super(SourcePath, self).__init__(context, value)
if value.startswith('/'):
@@ -425,7 +438,7 @@ class ObjDirPath(Path):
"""Like Path, but limited to paths in the object directory."""
def __init__(self, context, value=None):
if not value.startswith('!'):
raise ValueError('Source paths are not allowed')
raise ValueError('Object directory paths must start with ! prefix')
super(ObjDirPath, self).__init__(context, value)
if value.startswith('!/'):
@@ -435,6 +448,18 @@ class ObjDirPath(Path):
self.full_path = mozpath.normpath(path)
class AbsolutePath(Path):
"""Like Path, but allows arbitrary paths outside the source and object directories."""
def __init__(self, context, value=None):
if not value.startswith('%'):
raise ValueError('Absolute paths must start with % prefix')
if not os.path.isabs(value[1:]):
raise ValueError('Path \'%s\' is not absolute' % value[1:])
super(AbsolutePath, self).__init__(context, value)
self.full_path = mozpath.normpath(value[1:])
@memoize
def ContextDerivedTypedList(klass, base_class=List):
"""Specialized TypedList for use with ContextDerivedValue types.
@@ -464,6 +489,38 @@ def ContextDerivedTypedListWithItems(type, base_class=List):
return _TypedListWithItems
@memoize
def ContextDerivedTypedRecord(*fields):
"""Factory for objects with certain properties and dynamic
type checks.
This API is extremely similar to the TypedNamedTuple API,
except that properties may be mutated. This supports syntax like:
VARIABLE_NAME.property += [
'item1',
'item2',
]
"""
class _TypedRecord(ContextDerivedValue):
__slots__ = tuple([name for name, _ in fields])
def __init__(self, context):
for fname, ftype in self._fields.items():
if issubclass(ftype, ContextDerivedValue):
setattr(self, fname, self._fields[fname](context))
else:
setattr(self, fname, self._fields[fname]())
def __setattr__(self, name, value):
if name in self._fields and not isinstance(value, self._fields[name]):
value = self._fields[name](value)
object.__setattr__(self, name, value)
_TypedRecord._fields = dict(fields)
return _TypedRecord
BugzillaComponent = TypedNamedTuple('BugzillaComponent',
[('product', unicode), ('component', unicode)])
@@ -471,6 +528,14 @@ WebPlatformTestManifest = TypedNamedTuple("WebPlatformTestManifest",
[("manifest_path", unicode),
("test_root", unicode)])
OrderedSourceList = ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList)
OrderedTestFlavorList = TypedList(Enum(*all_test_flavors()),
StrictOrderingOnAppendList)
OrderedStringList = TypedList(unicode, StrictOrderingOnAppendList)
DependentTestsEntry = ContextDerivedTypedRecord(('files', OrderedSourceList),
('tags', OrderedStringList),
('flavors', OrderedTestFlavorList))
class Files(SubContext):
"""Metadata attached to files.
@@ -491,8 +556,8 @@ class Files(SubContext):
most one entity.
Patterns with ``*`` or ``**`` are wildcard matches. ``*`` matches files
within a single directory. ``**`` matches files across several directories.
Here are some examples:
at least within a single directory. ``**`` matches files across several
directories.
``foo.html``
Will match only the ``foo.html`` file in the current directory.
@@ -503,11 +568,18 @@ class Files(SubContext):
``foo/*.css``
Will match all ``.css`` files in the ``foo/`` directory.
``bar/*``
Will match all files in the ``bar/`` directory but not any files in
child directories of ``bar/``, such as ``bar/dir1/baz``.
``baz/**``
Will match all files in the ``baz/`` directory and all directories
underneath.
Will match all files in the ``bar/`` directory and all of its
children directories.
``bar/**``
This is equivalent to ``bar/*`` above.
``bar/**/foo``
Will match all ``foo`` files in the ``bar/`` directory and all of its
children directories.
The difference in behavior between ``*`` and ``**`` is only evident if
a pattern follows the ``*`` or ``**``. A pattern ending with ``*`` is
greedy. ``**`` is needed when you need an additional pattern after the
wildcard. e.g. ``**/foo``.
"""
VARIABLES = {
@@ -532,17 +604,79 @@ class Files(SubContext):
See :ref:`mozbuild_files_metadata_finalizing` for more info.
""", None),
'IMPACTED_TESTS': (DependentTestsEntry, list,
"""File patterns, tags, and flavors for tests relevant to these files.
Maps source files to the tests potentially impacted by those files.
Tests can be specified by file pattern, tag, or flavor.
For example:
with Files('runtests.py'):
IMPACTED_TESTS.files += [
'**',
]
in testing/mochitest/moz.build will suggest that any of the tests
under testing/mochitest may be impacted by a change to runtests.py.
File patterns may be made relative to the topsrcdir with a leading
'/', so
with Files('httpd.js'):
IMPACTED_TESTS.files += [
'/testing/mochitest/tests/Harness_sanity/**',
]
in netwerk/test/httpserver/moz.build will suggest that any change to httpd.js
will be relevant to the mochitest sanity tests.
Tags and flavors are sorted string lists (flavors are limited to valid
values).
For example:
with Files('toolkit/devtools/*'):
IMPACTED_TESTS.tags += [
'devtools',
]
in the root moz.build would suggest that any test tagged 'devtools' would
potentially be impacted by a change to a file under toolkit/devtools, and
with Files('dom/base/nsGlobalWindow.cpp'):
IMPACTED_TESTS.flavors += [
'mochitest',
]
Would suggest that nsGlobalWindow.cpp is potentially relevant to
any plain mochitest.
""", None),
}
def __init__(self, parent, pattern=None):
super(Files, self).__init__(parent)
self.pattern = pattern
self.finalized = set()
self.test_files = set()
self.test_tags = set()
self.test_flavors = set()
def __iadd__(self, other):
assert isinstance(other, Files)
self.test_files |= other.test_files
self.test_tags |= other.test_tags
self.test_flavors |= other.test_flavors
for k, v in other.items():
if k == 'IMPACTED_TESTS':
self.test_files |= set(mozpath.relpath(e.full_path, e.context.config.topsrcdir)
for e in v.files)
self.test_tags |= set(v.tags)
self.test_flavors |= set(v.flavors)
continue
# Ignore updates to finalized flags.
if k in self.finalized:
continue
@@ -568,6 +702,49 @@ class Files(SubContext):
return d
@staticmethod
def aggregate(files):
"""Given a mapping of path to Files, obtain aggregate results.
Consumers may want to extract useful information from a collection of
Files describing paths. e.g. given the files info data for N paths,
recommend a single bug component based on the most frequent one. This
function provides logic for deriving aggregate knowledge from a
collection of path File metadata.
Note: the intent of this function is to operate on the result of
:py:func:`mozbuild.frontend.reader.BuildReader.files_info`. The
:py:func:`mozbuild.frontend.context.Files` instances passed in are
thus the "collapsed" (``__iadd__``ed) results of all ``Files`` from all
moz.build files relevant to a specific path, not individual ``Files``
instances from a single moz.build file.
"""
d = {}
bug_components = Counter()
for f in files.values():
bug_component = f.get('BUG_COMPONENT')
if bug_component:
bug_components[bug_component] += 1
d['bug_component_counts'] = []
for c, count in bug_components.most_common():
component = (c.product, c.component)
d['bug_component_counts'].append((c, count))
if 'recommended_bug_component' not in d:
d['recommended_bug_component'] = component
recommended_count = count
elif count == recommended_count:
# Don't recommend a component if it doesn't have a clear lead.
d['recommended_bug_component'] = None
# In case no bug components.
d.setdefault('recommended_bug_component', None)
return d
# This defines functions that create sub-contexts.
#
@@ -626,12 +803,41 @@ VARIABLES = {
file.
""", 'export'),
'ANDROID_RES_DIRS': (List, list,
'ANDROID_APK_NAME': (unicode, unicode,
"""The name of an Android APK file to generate.
""", 'export'),
'ANDROID_APK_PACKAGE': (unicode, unicode,
"""The name of the Android package to generate R.java for, like org.mozilla.gecko.
""", 'export'),
'ANDROID_EXTRA_PACKAGES': (StrictOrderingOnAppendList, list,
"""The name of extra Android packages to generate R.java for, like ['org.mozilla.other'].
""", 'export'),
'ANDROID_EXTRA_RES_DIRS': (ContextDerivedTypedListWithItems(Path, List), list,
"""Android extra package resource directories.
This variable contains a list of directories containing static files
to package into a 'res' directory and merge into an APK file. These
directories are packaged into the APK but are assumed to be static
unchecked dependencies that should not be otherwise re-distributed.
""", 'export'),
'ANDROID_RES_DIRS': (ContextDerivedTypedListWithItems(Path, List), list,
"""Android resource directories.
This variable contains a list of directories, each relative to
the srcdir, containing static files to package into a 'res'
directory and merge into an APK file.
This variable contains a list of directories containing static
files to package into a 'res' directory and merge into an APK
file.
""", 'export'),
'ANDROID_ASSETS_DIRS': (ContextDerivedTypedListWithItems(Path, List), list,
"""Android assets directories.
This variable contains a list of directories containing static
files to package into an 'assets' directory and merge into an
APK file.
""", 'export'),
'ANDROID_ECLIPSE_PROJECT_TARGETS': (dict, dict,
+62 -9
View File
@@ -28,16 +28,14 @@ from ..util import (
group_unified_files,
)
from ..testing import (
all_test_flavors,
)
class TreeMetadata(object):
"""Base class for all data being captured."""
def __init__(self):
self._ack = False
def ack(self):
self._ack = True
class ContextDerived(TreeMetadata):
"""Build object derived from a single Context instance.
@@ -73,6 +71,12 @@ class ContextDerived(TreeMetadata):
self.config = context.config
self._context = context
@property
def install_target(self):
return self._context['FINAL_TARGET']
@property
def relobjdir(self):
return mozpath.relpath(self.objdir, self.topobjdir)
@@ -148,7 +152,6 @@ class XPIDLFile(ContextDerived):
__slots__ = (
'add_to_manifest',
'basename',
'install_target',
'source_path',
)
@@ -160,8 +163,6 @@ class XPIDLFile(ContextDerived):
self.module = module
self.add_to_manifest = add_to_manifest
self.install_target = context['FINAL_TARGET']
class BaseDefines(ContextDerived):
"""Context derived container object for DEFINES/HOST_DEFINES,
which are OrderedDicts.
@@ -619,6 +620,8 @@ class TestManifest(ContextDerived):
install_prefix=None, relpath=None, dupe_manifest=False):
ContextDerived.__init__(self, context)
assert flavor in all_test_flavors()
self.path = path
self.directory = mozpath.dirname(path)
self.manifest = manifest
@@ -959,3 +962,53 @@ class AndroidEclipseProjectData(object):
cpe.ignore_warnings = ignore_warnings
self._classpathentries.append(cpe)
return cpe
class AndroidResDirs(ContextDerived):
"""Represents Android resource directories."""
__slots__ = (
'paths',
)
def __init__(self, context, paths):
ContextDerived.__init__(self, context)
self.paths = paths
class AndroidAssetsDirs(ContextDerived):
"""Represents Android assets directories."""
__slots__ = (
'paths',
)
def __init__(self, context, paths):
ContextDerived.__init__(self, context)
self.paths = paths
class AndroidExtraResDirs(ContextDerived):
"""Represents Android extra resource directories.
Extra resources are resources provided by libraries and including in a
packaged APK, but not otherwise redistributed. In practice, this means
resources included in Fennec but not in GeckoView.
"""
__slots__ = (
'paths',
)
def __init__(self, context, paths):
ContextDerived.__init__(self, context)
self.paths = paths
class AndroidExtraPackages(ContextDerived):
"""Represents Android extra packages."""
__slots__ = (
'packages',
)
def __init__(self, context, packages):
ContextDerived.__init__(self, context)
self.packages = packages
+64 -51
View File
@@ -24,6 +24,10 @@ import reftest
import mozinfo
from .data import (
AndroidAssetsDirs,
AndroidExtraPackages,
AndroidExtraResDirs,
AndroidResDirs,
BrandingFiles,
ConfigFileSubstitution,
ContextWrapped,
@@ -75,9 +79,14 @@ from .data import (
from .reader import SandboxValidationError
from ..testing import (
TEST_MANIFESTS,
REFTEST_FLAVORS,
WEB_PATFORM_TESTS_FLAVORS,
)
from .context import (
Context,
ObjDirPath,
SourcePath,
ObjDirPath,
Path,
@@ -150,8 +159,6 @@ class TreeMetadataEmitter(LoggingMixin):
for o in objs:
self._object_count += 1
yield o
if not o._ack:
raise Exception('Unhandled object of type %s' % type(o))
for out in output:
# Nothing in sub-contexts is currently of interest to us. Filter
@@ -542,14 +549,26 @@ class TreeMetadataEmitter(LoggingMixin):
for obj in self._process_xpidl(context):
yield obj
# Check for manifest declarations in EXTRA_{PP_,}COMPONENTS.
extras = context.get('EXTRA_COMPONENTS', []) + context.get('EXTRA_PP_COMPONENTS', [])
if any(e.endswith('.js') for e in extras) and \
not any(e.endswith('.manifest') for e in extras) and \
not context.get('NO_JS_MANIFEST', False):
raise SandboxValidationError('A .js component was specified in EXTRA_COMPONENTS '
'or EXTRA_PP_COMPONENTS without a matching '
'.manifest file. See '
'https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0 .',
context);
# Proxy some variables as-is until we have richer classes to represent
# them. We should aim to keep this set small because it violates the
# desired abstraction of the build definition away from makefiles.
passthru = VariablePassthru(context)
varlist = [
'ALLOW_COMPILER_WARNINGS',
'ANDROID_APK_NAME',
'ANDROID_APK_PACKAGE',
'ANDROID_GENERATED_RESFILES',
'ANDROID_RES_DIRS',
'DISABLE_STL_WRAPPING',
'EXTRA_COMPONENTS',
'EXTRA_DSO_LDOPTS',
@@ -697,6 +716,24 @@ class TreeMetadataEmitter(LoggingMixin):
for name, data in context.get('ANDROID_ECLIPSE_PROJECT_TARGETS', {}).items():
yield ContextWrapped(context, data)
for (symbol, cls) in [
('ANDROID_RES_DIRS', AndroidResDirs),
('ANDROID_EXTRA_RES_DIRS', AndroidExtraResDirs),
('ANDROID_ASSETS_DIRS', AndroidAssetsDirs)]:
paths = context.get(symbol)
if not paths:
continue
for p in paths:
if isinstance(p, SourcePath) and not os.path.isdir(p.full_path):
raise SandboxValidationError('Directory listed in '
'%s is not a directory: \'%s\'' %
(symbol, p.full_path), context)
yield cls(context, paths)
android_extra_packages = context.get('ANDROID_EXTRA_PACKAGES')
if android_extra_packages:
yield AndroidExtraPackages(context, android_extra_packages)
if passthru.variables:
yield passthru
@@ -845,15 +882,15 @@ class TreeMetadataEmitter(LoggingMixin):
for f in generated_files:
flags = generated_files[f]
output = f
inputs = []
if flags.script:
method = "main"
script = SourcePath(context, flags.script).full_path
# Deal with cases like "C:\\path\\to\\script.py:function".
if not flags.script.endswith('.py') and ':' in flags.script:
script, method = flags.script.rsplit(':', 1)
else:
script = flags.script
script = mozpath.join(context.srcdir, script)
inputs = [mozpath.join(context.srcdir, i) for i in flags.inputs]
if '.py:' in script:
script, method = script.rsplit('.py:', 1)
script += '.py'
if not os.path.exists(script):
raise SandboxValidationError(
@@ -863,15 +900,18 @@ class TreeMetadataEmitter(LoggingMixin):
raise SandboxValidationError(
'Script for generating %s does not end in .py: %s'
% (f, script), context)
for i in inputs:
if not os.path.exists(i):
for i in flags.inputs:
p = Path(context, i)
if (isinstance(p, SourcePath) and
not os.path.exists(p.full_path)):
raise SandboxValidationError(
'Input for generating %s does not exist: %s'
% (f, i), context)
% (f, p.full_path), context)
inputs.append(p.full_path)
else:
script = None
method = None
inputs = []
yield GeneratedFile(context, script, method, output, inputs)
def _process_test_harness_files(self, context):
@@ -945,49 +985,21 @@ class TreeMetadataEmitter(LoggingMixin):
else 'USE_LIBS'))
def _process_test_manifests(self, context):
# While there are multiple test manifests, the behavior is very similar
# across them. We enforce this by having common handling of all
# manifests and outputting a single class type with the differences
# described inside the instance.
#
# Keys are variable prefixes and values are tuples describing how these
# manifests should be handled:
#
# (flavor, install_prefix, package_tests)
#
# flavor identifies the flavor of this test.
# install_prefix is the path prefix of where to install the files in
# the tests directory.
# package_tests indicates whether to package test files into the test
# package; suites that compile the test files should not install
# them into the test package.
#
test_manifests = dict(
A11Y=('a11y', 'testing/mochitest', 'a11y', True),
BROWSER_CHROME=('browser-chrome', 'testing/mochitest', 'browser', True),
ANDROID_INSTRUMENTATION=('instrumentation', 'instrumentation', '.', False),
JETPACK_PACKAGE=('jetpack-package', 'testing/mochitest', 'jetpack-package', True),
JETPACK_ADDON=('jetpack-addon', 'testing/mochitest', 'jetpack-addon', False),
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
MOCHITEST=('mochitest', 'testing/mochitest', 'tests', True),
MOCHITEST_CHROME=('chrome', 'testing/mochitest', 'chrome', True),
WEBRTC_SIGNALLING_TEST=('steeplechase', 'steeplechase', '.', True),
XPCSHELL_TESTS=('xpcshell', 'xpcshell', '.', True),
)
for prefix, info in test_manifests.items():
for prefix, info in TEST_MANIFESTS.items():
for path in context.get('%s_MANIFESTS' % prefix, []):
for obj in self._process_test_manifest(context, info, path):
yield obj
for flavor in ('crashtest', 'reftest'):
for flavor in REFTEST_FLAVORS:
for path in context.get('%s_MANIFESTS' % flavor.upper(), []):
for obj in self._process_reftest_manifest(context, flavor, path):
yield obj
for path in context.get("WEB_PLATFORM_TESTS_MANIFESTS", []):
for obj in self._process_web_platform_tests_manifest(context, path):
yield obj
for flavor in WEB_PATFORM_TESTS_FLAVORS:
for path in context.get("%s_MANIFESTS" % flavor.upper().replace('-', '_'), []):
for obj in self._process_web_platform_tests_manifest(context, path):
yield obj
def _process_test_manifest(self, context, info, manifest_path):
flavor, install_root, install_subdir, package_tests = info
@@ -1154,11 +1166,11 @@ class TreeMetadataEmitter(LoggingMixin):
relpath=mozpath.join(manifest_reldir,
mozpath.basename(manifest_path)))
for test in sorted(manifest.files):
for test, source_manifest in sorted(manifest.tests):
obj.tests.append({
'path': test,
'here': mozpath.dirname(test),
'manifest': manifest_full_path,
'manifest': source_manifest,
'name': mozpath.basename(test),
'head': '',
'tail': '',
@@ -1253,6 +1265,7 @@ class TreeMetadataEmitter(LoggingMixin):
# Some paths have a subconfigure, yet also have a moz.build. Those
# shouldn't end up in self._external_paths.
self._external_paths -= { o.relobjdir }
if o.objdir:
self._external_paths -= { o.relobjdir }
yield o
@@ -131,6 +131,34 @@ class MozbuildFileCommands(MachCommandBase):
print(e.message)
return 1
@SubCommand('file-info', 'dep-tests',
'Show test files marked as dependencies of these source files.')
@CommandArgument('-r', '--rev',
help='Version control revision to look up info from')
@CommandArgument('paths', nargs='+',
help='Paths whose data to query')
def file_info_test_deps(self, paths, rev=None):
try:
for p, m in self._get_files_info(paths, rev=rev).items():
print('%s:' % mozpath.relpath(p, self.topsrcdir))
if m.test_files:
print('\tTest file patterns:')
for p in m.test_files:
print('\t\t%s' % p)
if m.test_tags:
print('\tRelevant tags:')
for p in m.test_tags:
print('\t\t%s' % p)
if m.test_flavors:
print('\tRelevant flavors:')
for p in m.test_flavors:
print('\t\t%s' % p)
except InvalidPathException as e:
print(e.message)
return 1
def _get_reader(self, finder):
from mozbuild.frontend.reader import (
BuildReader,
+65 -3
View File
@@ -25,7 +25,6 @@ import os
import sys
import textwrap
import time
import tokenize
import traceback
import types
@@ -41,6 +40,12 @@ from mozbuild.util import (
ReadOnlyDefaultDict,
)
from mozbuild.testing import (
TEST_MANIFESTS,
REFTEST_FLAVORS,
WEB_PATFORM_TESTS_FLAVORS,
)
from mozbuild.backend.configenvironment import ConfigEnvironment
from mozpack.files import FileFinder
@@ -749,7 +754,7 @@ class BuildReaderError(Exception):
self._print_exception(inner, s)
def _print_keyerror(self, inner, s):
if inner.args[0] not in ('global_ns', 'local_ns'):
if not inner.args or inner.args[0] not in ('global_ns', 'local_ns'):
self._print_exception(inner, s)
return
@@ -808,7 +813,7 @@ class BuildReaderError(Exception):
s.write('variables and try again.\n')
def _print_valueerror(self, inner, s):
if inner.args[0] not in ('global_ns', 'local_ns'):
if not inner.args or inner.args[0] not in ('global_ns', 'local_ns'):
self._print_exception(inner, s)
return
@@ -1345,6 +1350,7 @@ class BuildReader(object):
paths, _ = self.read_relevant_mozbuilds(paths)
r = {}
test_ctx_reader = TestContextReader(self.config)
for path, ctxs in paths.items():
flags = Files(Context())
@@ -1363,6 +1369,62 @@ class BuildReader(object):
('*' in pattern and mozpath.match(relpath, pattern)):
flags += ctx
if not any([flags.test_tags, flags.test_files, flags.test_flavors]):
flags += test_ctx_reader.test_defaults_for_path(path, ctxs)
r[path] = flags
return r
class TestContextReader(object):
"""Helper to extract test patterns defaults from moz.build files.
Given paths of interest and relevant contexts, populates a Files
object with patterns matching all tests mentioned in the given
contexts.
"""
def __init__(self, config):
self.config = config
# This names the context keys that will end up emitting a test
# manifest.
self._test_manifest_contexts = set(
['%s_MANIFESTS' % key for key in TEST_MANIFESTS] +
['%s_MANIFESTS' % flavor.upper() for flavor in REFTEST_FLAVORS] +
['%s_MANIFESTS' % flavor.upper().replace('-', '_') for flavor in WEB_PATFORM_TESTS_FLAVORS] +
# The emitter requires JAR_MANIFESTS in contexts if they exist on
# disk, so include them here.
['JAR_MANIFESTS']
)
def test_defaults_for_path(self, path, ctxs):
# Using the emitter here creates a circular import (and crosses some
# abstraction boundaries), but it's a convenient way to get the build
# system's view of tests.
# Bug 1203266 tracks features that would allow improving this situation
# and removing this abuse of the TreeMetadataEmitter
from .emitter import TreeMetadataEmitter, TestManifest
emitter = TreeMetadataEmitter(self.config)
result_context = Files(Context())
for ctx in ctxs:
test_context = Context(VARIABLES, self.config)
test_context.main_path = ctx.main_path
# Clone just the keys that will result in test manifests.
manifest_keys = [key for key in ctx if key in self._test_manifest_contexts]
for key in manifest_keys:
test_context[key] = ctx[key]
for obj in emitter.emit_from_context(test_context):
if isinstance(obj, TestManifest):
for t in obj.tests:
if 'relpath' not in t:
# wpt manifests do not generate relpaths (bug 1207678).
t['relpath'] = mozpath.relpath(t['path'],
self.config.topsrcdir)
# Pull in the entire directory of tests.
result_context.test_files.add(mozpath.dirname(t['relpath']) + '/**')
return result_context
+49 -8
View File
@@ -528,7 +528,7 @@ class Build(MachCommandBase):
# conditions, but that is for another day.
@CommandArgument('-b', '--backend', nargs='+',
choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse',
'VisualStudio', 'FasterMake'],
'VisualStudio', 'FasterMake', 'CompileDB'],
help='Which backend to build.')
def build_backend(self, backend, diff=False):
python = self.virtualenv_manager.python_path
@@ -645,13 +645,22 @@ class Warnings(MachCommandBase):
@Command('warnings-summary', category='post-build',
description='Show a summary of compiler warnings.')
@CommandArgument('-C', '--directory', default=None,
help='Change to a subdirectory of the build directory first.')
@CommandArgument('report', default=None, nargs='?',
help='Warnings report to display. If not defined, show the most '
'recent report.')
def summary(self, report=None):
def summary(self, directory=None, report=None):
database = self.database
type_counts = database.type_counts
if directory:
dirpath = self.join_ensure_dir(self.topsrcdir, directory)
if not dirpath:
return 1
else:
dirpath = None
type_counts = database.type_counts(dirpath)
sorted_counts = sorted(type_counts.iteritems(),
key=operator.itemgetter(1))
@@ -664,19 +673,41 @@ class Warnings(MachCommandBase):
@Command('warnings-list', category='post-build',
description='Show a list of compiler warnings.')
@CommandArgument('-C', '--directory', default=None,
help='Change to a subdirectory of the build directory first.')
@CommandArgument('--flags', default=None, nargs='+',
help='Which warnings flags to match.')
@CommandArgument('report', default=None, nargs='?',
help='Warnings report to display. If not defined, show the most '
'recent report.')
def list(self, report=None):
def list(self, directory=None, flags=None, report=None):
database = self.database
by_name = sorted(database.warnings)
for warning in by_name:
filename = warning['filename']
topsrcdir = mozpath.normpath(self.topsrcdir)
if filename.startswith(self.topsrcdir):
filename = filename[len(self.topsrcdir) + 1:]
if directory:
directory = mozpath.normsep(directory)
dirpath = self.join_ensure_dir(topsrcdir, directory)
if not dirpath:
return 1
if flags:
# Flatten lists of flags.
flags = set(itertools.chain(*[flaglist.split(',') for flaglist in flags]))
for warning in by_name:
filename = mozpath.normsep(warning['filename'])
if filename.startswith(topsrcdir):
filename = filename[len(topsrcdir) + 1:]
if directory and not filename.startswith(directory):
continue
if flags and warning['flag'] not in flags:
continue
if warning['column'] is not None:
print('%s:%d:%d [%s] %s' % (filename, warning['line'],
@@ -685,6 +716,16 @@ class Warnings(MachCommandBase):
print('%s:%d [%s] %s' % (filename, warning['line'],
warning['flag'], warning['message']))
def join_ensure_dir(self, dir1, dir2):
dir1 = mozpath.normpath(dir1)
dir2 = mozpath.normsep(dir2)
joined_path = mozpath.join(dir1, dir2)
if os.path.isdir(joined_path):
return joined_path
else:
print('Specified directory not found.')
return None
@CommandProvider
class GTestCommands(MachCommandBase):
@Command('gtest', category='testing',
@@ -0,0 +1,14 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
BRANDING_FILES += [
'app.ico',
'bar.ico',
'sub/quux.png',
]
BRANDING_FILES['app.ico'].source = 'bar.ico'
BRANDING_FILES.icons += [
'foo.ico',
]
@@ -2,7 +2,7 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
EXTRA_COMPONENTS = ['bar.js', 'foo.js']
EXTRA_COMPONENTS = ['bar.js', 'dummy.manifest', 'foo.js']
EXTRA_PP_COMPONENTS = ['bar.pp.js', 'foo.pp.js']
NO_VISIBILITY_FLAGS = True
@@ -268,6 +268,7 @@ class TestRecursiveMakeBackend(BackendTester):
],
'EXTRA_COMPONENTS': [
'EXTRA_COMPONENTS += bar.js',
'EXTRA_COMPONENTS += dummy.manifest',
'EXTRA_COMPONENTS += foo.js',
],
'EXTRA_PP_COMPONENTS': [
@@ -417,6 +418,19 @@ class TestRecursiveMakeBackend(BackendTester):
self.assertIn('res/tests/test.manifest', m)
self.assertIn('res/tests/extra.manifest', m)
def test_branding_files(self):
"""Ensure BRANDING_FILES is handled properly."""
env = self._consume('branding-files', RecursiveMakeBackend)
#BRANDING_FILES should appear in the dist_branding install manifest.
m = InstallManifest(path=os.path.join(env.topobjdir,
'_build_manifests', 'install', 'dist_branding'))
self.assertEqual(len(m), 4)
self.assertIn('app.ico', m)
self.assertIn('bar.ico', m)
self.assertIn('quux.png', m)
self.assertIn('icons/foo.ico', m)
def test_js_preference_files(self):
"""Ensure PREF_JS_EXPORTS is written out correctly."""
env = self._consume('js_preference_files', RecursiveMakeBackend)
@@ -0,0 +1,9 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
ANDROID_RES_DIRS += [
'/dir1',
'!/dir2',
'%/dir3',
]
@@ -0,0 +1,15 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
BRANDING_FILES += [
'app.ico',
'bar.ico',
'baz.png',
'foo.xpm',
]
BRANDING_FILES['app.ico'].source = 'test/bar.ico'
BRANDING_FILES.icons += [
'quux.icns',
]
@@ -0,0 +1,5 @@
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
EXTRA_JS_MODULES += [
'module.js',
]

Some files were not shown because too many files have changed in this diff Show More