mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:11:03 +00:00
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:
@@ -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',
|
||||
]
|
||||
@@ -37,7 +37,6 @@ if test -z "$MOZ_ARCH"; then
|
||||
;;
|
||||
arm-Darwin)
|
||||
MOZ_ARCH=toolchain-default
|
||||
MOZ_THUMB=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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])
|
||||
])
|
||||
|
||||
@@ -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)
|
||||
])
|
||||
@@ -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>`.
|
||||
|
||||
@@ -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" >
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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/**']
|
||||
|
||||
@@ -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,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
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 \
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3937,6 +3937,8 @@ esac
|
||||
case "$MOZ_BUILD_APP" in
|
||||
browser)
|
||||
AC_DEFINE(MOZ_PHOENIX)
|
||||
|
||||
BUILD_BACKENDS="$BUILD_BACKENDS FasterMake"
|
||||
;;
|
||||
|
||||
xulrunner)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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 += [
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user