From 6e04efa087a2565dedbec79d779336080576cf0c Mon Sep 17 00:00:00 2001 From: Sebastian Kaspari Date: Fri, 19 Feb 2016 10:40:01 +0000 Subject: [PATCH 001/252] Bug 1249354 - configure.in: Remove --disable-android-include-fonts configuration option. r=nalexander This resembles what we are doing with MOZ_EXCLUDE_HYPHENATION_DICTIONARIES: We just have a flag without any --disable-* configuration option. MozReview-Commit-ID: ATxb5XAzp9k --- configure.in | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/configure.in b/configure.in index 35e0865ed7d..77ebc9da0b3 100644 --- a/configure.in +++ b/configure.in @@ -3851,18 +3851,6 @@ MOZ_ARG_WITH_STRING(gcm-senderid-keyfile, MOZ_ANDROID_GCM_SENDERID=`cat $withval`) AC_SUBST(MOZ_ANDROID_GCM_SENDERID) -# Whether to include optional-but-large font files in the final APK. -# We want this in mobile/android/confvars.sh, so it goes early. -MOZ_ARG_DISABLE_BOOL(android-include-fonts, -[ --disable-android-include-fonts - Disable the inclusion of fonts into the final APK], - MOZ_ANDROID_EXCLUDE_FONTS=1) - -if test -n "$MOZ_ANDROID_EXCLUDE_FONTS"; then - AC_DEFINE(MOZ_ANDROID_EXCLUDE_FONTS) -fi -AC_SUBST(MOZ_ANDROID_EXCLUDE_FONTS) - # Whether this APK is destined for resource constrained devices. # We want this in mobile/android/confvars.sh, so it goes early. MOZ_ARG_ENABLE_BOOL(android-resource-constrained, @@ -4775,6 +4763,13 @@ if test -n "$MOZ_ANDROID_MLS_STUMBLER"; then AC_DEFINE(MOZ_ANDROID_MLS_STUMBLER) fi +dnl ========================================================= +dnl = Whether to exclude font files in the build +dnl ========================================================= +if test -n "$MOZ_ANDROID_EXCLUDE_FONTS"; then + AC_DEFINE(MOZ_ANDROID_EXCLUDE_FONTS) +fi + dnl ========================================================= dnl = Whether to exclude hyphenations files in the build dnl ========================================================= @@ -8457,6 +8452,7 @@ AC_SUBST(MOZ_ANDROID_APPLICATION_CLASS) AC_SUBST(MOZ_ANDROID_BROWSER_INTENT_CLASS) AC_SUBST(MOZ_ANDROID_SEARCH_INTENT_CLASS) AC_SUBST(MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE) +AC_SUBST(MOZ_ANDROID_EXCLUDE_FONTS) AC_SUBST(MOZ_EXCLUDE_HYPHENATION_DICTIONARIES) AC_SUBST(MOZ_INSTALL_TRACKING) AC_SUBST(MOZ_SWITCHBOARD) From 571fda333d51251528d200af423a2944a104029c Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Tue, 23 Feb 2016 12:09:44 +0100 Subject: [PATCH 002/252] Bug 1249365 - Store Loops permission to use the camera so we can check later. r=jesup --- dom/media/MediaManager.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index e0990b2a34e..c1470948eb1 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -2052,6 +2052,17 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow, RemoveFromWindowList(windowID, listener); return NS_OK; } + } else if (loop) { + // Record that we gave Loop permission to use camera access. + nsCOMPtr permManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = permManager->Add(docURI, "camera", + nsIPermissionManager::ALLOW_ACTION, + nsIPermissionManager::EXPIRE_SESSION, + 0); + NS_ENSURE_SUCCESS(rv, rv); } #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) From 03a6e3b724b22c81356fb012b86ec941f52a6624 Mon Sep 17 00:00:00 2001 From: Johan Lorenzo Date: Mon, 22 Feb 2016 17:16:04 +0100 Subject: [PATCH 003/252] Bug 1250178 - [e2e-py] Delete the tasks r=garndt MozReview-Commit-ID: 4OsTFbTESLe --- .../tasks/b2g_e2e_tests_base_definition.yml | 103 ------------------ .../tasks/branches/b2g-inbound/job_flags.yml | 14 --- .../tasks/branches/base_job_flags.yml | 6 - .../tasks/tests/b2g_e2e_api_tests.yml | 16 --- .../tasks/tests/b2g_e2e_dsds_tests.yml | 21 ---- .../taskcluster/tasks/tests/b2g_e2e_tests.yml | 21 ---- 6 files changed, 181 deletions(-) delete mode 100644 testing/taskcluster/tasks/b2g_e2e_tests_base_definition.yml delete mode 100644 testing/taskcluster/tasks/tests/b2g_e2e_api_tests.yml delete mode 100644 testing/taskcluster/tasks/tests/b2g_e2e_dsds_tests.yml delete mode 100644 testing/taskcluster/tasks/tests/b2g_e2e_tests.yml diff --git a/testing/taskcluster/tasks/b2g_e2e_tests_base_definition.yml b/testing/taskcluster/tasks/b2g_e2e_tests_base_definition.yml deleted file mode 100644 index 50af40536d8..00000000000 --- a/testing/taskcluster/tasks/b2g_e2e_tests_base_definition.yml +++ /dev/null @@ -1,103 +0,0 @@ -task: - created: '{{now}}' - deadline: '{{#from_now}}24 hours{{/from_now}}' - metadata: - source: '{{source}}' - owner: mozilla-taskcluster-maintenance@mozilla.com - tags: - createdForUser: {{owner}} - workerType: b2gtest - provisionerId: aws-provisioner-v1 - schedulerId: task-graph-scheduler - - scopes: - - 'docker-worker:image:{{#docker_image}}tester-device{{/docker_image}}' - - 'queue:create-task:aws-provisioner-v1/testdroid-device' - - 'docker-worker:cache:level-{{level}}-{{project}}-tc-vcs' - - 'docker-worker:capability:device:phone' - - payload: - image: '{{#docker_image}}tester-device{{/docker_image}}' - maxRunTime: 7200 - cache: - level-{{level}}-{{project}}-tc-vcs: '/home/worker/.tc-vcs' - env: - MOZ_BUILD_DATE: '{{pushdate}}' - GAIA_HEAD_REPOSITORY: '{{{gaia_head_repository}}}' - GAIA_BASE_REPOSITORY: '{{{gaia_base_repository}}}' - GAIA_REF: '{{{gaia_ref}}}' - GAIA_REV: '{{{gaia_rev}}}' - TESTS_TIMEOUT_IN_MS: 30000 - MANIFEST_PATH: gaia/source/tests/python/gaia-ui-tests/gaiatest/tests/functional/manifest.ini - MANIFEST_INCLUDE_EXCLUDE: b2g-dsds - - log: 'private/b2g/logs/live.log' - - # All builds share a common artifact directory for ease of uploading. - artifacts: - 'private/b2g/device.json': - type: file - path: '/home/worker/data/device.json' - expires: '{{#from_now}}1 year{{/from_now}}' - - 'private/b2g/logs': - type: directory - path: '/home/worker/upload/logs/' - expires: '{{#from_now}}1 year{{/from_now}}' - - 'private/b2g/videos': - type: directory - path: '/home/worker/upload/videos/' - expires: '{{#from_now}}3 months{{/from_now}}' - - features: - testdroidProxy: true - - capabilities: - devices: - phone: - type: 'flame' - memory: '512' - sims: '0' - build: '{{{img_url}}}' - - command: - - > - adb - -H $PROXY_HOST - -P $ADB_PORT - -s $SERIAL_ID - logcat - -v threadtime - &> /home/worker/upload/logs/logcat.log - & - - - > - gaiatest - --total-chunks={{total_chunks}} - --this-chunk={{chunk}} - --testvars=/home/worker/data/gaia_testvars.json - --testvars=/home/worker/data/device.json - --adb-host=$PROXY_HOST - --adb-port=$ADB_PORT - --address=$PROXY_HOST:$MARIONETTE_PORT - --device $SERIAL_ID - --xml-output=/home/worker/upload/logs/xml_output.xml - --log-html=/home/worker/upload/logs/index.html - --log-mach=- - --log-raw=/home/worker/upload/logs/raw.log - --capture=whenfail - --capturefolder=/home/worker/upload/videos/ - --restart - --timeout=$TESTS_TIMEOUT_IN_MS - --type=$MANIFEST_INCLUDE_EXCLUDE - $MANIFEST_PATH - - extra: - treeherder: - groupName: B2G end-to-end tests (Python) - groupSymbol: e2e-py - productName: b2g - chunks: - total: 1 - current: {{chunk}} diff --git a/testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml b/testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml index b7c85516fd3..ff3b8b988d2 100644 --- a/testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml +++ b/testing/taskcluster/tasks/branches/b2g-inbound/job_flags.yml @@ -4,17 +4,3 @@ $inherits: from: tasks/branches/base_jobs.yml - -tests: - gaia-ui-test-functional: - allowed_build_tasks: - tasks/builds/b2g_flame_kk_eng.yml: - task: tasks/tests/b2g_e2e_tests.yml - gaia-ui-test-functional-dsds: - allowed_build_tasks: - tasks/builds/b2g_flame_kk_eng.yml: - task: tasks/tests/b2g_e2e_dsds_tests.yml - gaia-ui-test-unit: - allowed_build_tasks: - tasks/builds/b2g_flame_kk_eng.yml: - task: tasks/tests/b2g_e2e_api_tests.yml diff --git a/testing/taskcluster/tasks/branches/base_job_flags.yml b/testing/taskcluster/tasks/branches/base_job_flags.yml index ca2ec1a97e0..d59e4d56751 100644 --- a/testing/taskcluster/tasks/branches/base_job_flags.yml +++ b/testing/taskcluster/tasks/branches/base_job_flags.yml @@ -31,7 +31,6 @@ flags: crashtest-e10s: /crashtest-e10s.*/ e10s: /.*e10s.*/ gaia-js-integration: /.*gaia-js-integration.*/ - gaia-ui-test: /.*gaia-ui-test.*/ gtest: /gtest.*/ jittest: /jittest.*/ jittests: /jittest.*/ @@ -121,10 +120,6 @@ flags: - gaia-linter - gaia-unit - gaia-unit-oop - - gaia-ui-test-sanity - - gaia-ui-test-functional - - gaia-ui-test-functional-dsds - - gaia-ui-test-unit - gtest - jetpack - jittests @@ -159,4 +154,3 @@ flags: - web-platform-tests-reftests - web-platform-tests-reftests-e10s - xpcshell - diff --git a/testing/taskcluster/tasks/tests/b2g_e2e_api_tests.yml b/testing/taskcluster/tasks/tests/b2g_e2e_api_tests.yml deleted file mode 100644 index 44dcafa32e6..00000000000 --- a/testing/taskcluster/tasks/tests/b2g_e2e_api_tests.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -$inherits: - from: tasks/b2g_e2e_tests_base_definition.yml -task: - metadata: - name: B2G gecko APIs tests (on device) - description: Tests which verifies the APIs needed for setting up the e2e tests - workerType: flame-kk-0-sim - - payload: - env: - MANIFEST_PATH: gaia/source/tests/python/gaia-ui-tests/gaiatest/tests/unit/manifest.ini - - extra: - treeherder: - symbol: 'a' diff --git a/testing/taskcluster/tasks/tests/b2g_e2e_dsds_tests.yml b/testing/taskcluster/tasks/tests/b2g_e2e_dsds_tests.yml deleted file mode 100644 index 0d730134801..00000000000 --- a/testing/taskcluster/tasks/tests/b2g_e2e_dsds_tests.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -$inherits: - from: tasks/b2g_e2e_tests_base_definition.yml -task: - metadata: - name: B2G end-to-end DSDS tests - description: Tests which require 2 SIM cards - workerType: flame-kk-2-sim - - payload: - env: - MANIFEST_INCLUDE_EXCLUDE: b2g+dsds - - capabilities: - devices: - phone: - sims: '2' - - extra: - treeherder: - symbol: 'dsds' diff --git a/testing/taskcluster/tasks/tests/b2g_e2e_tests.yml b/testing/taskcluster/tasks/tests/b2g_e2e_tests.yml deleted file mode 100644 index d00869800d6..00000000000 --- a/testing/taskcluster/tasks/tests/b2g_e2e_tests.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -$inherits: - from: tasks/b2g_e2e_tests_base_definition.yml -task: - metadata: - name: B2G end-to-end tests - description: Regular end-to-end tests - workerType: flame-kk-1-sim - - payload: - capabilities: - devices: - phone: - sims: '1' - - extra: - chunks: - total: 6 - - treeherder: - symbol: '{{chunk}}' From 4b6edbd3aced9bd75d9bb401bcb209b73604dddd Mon Sep 17 00:00:00 2001 From: Dan Minor Date: Tue, 2 Feb 2016 09:32:49 -0500 Subject: [PATCH 004/252] Bug 1244160 - Create json-schema for build telemetry data r=gps This adds a simple schema for build telemetry data. We can make it more restrictive once we have a better feeling for what kind of data we want to submit. This also moves more common data about the system to the telemetry handler. We leave psutil derivied information in the resource usage data as not every system will have psutil installed. MozReview-Commit-ID: CFRq1Ow6AOf --- build/mach_bootstrap.py | 20 +++++++++++++++- build/telemetry-schema.json | 24 +++++++++++++++++++ .../mozbuild/mozbuild/controller/building.py | 24 +++---------------- .../resources/html-build-viewer/index.html | 2 +- 4 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 build/telemetry-schema.json diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py index 325bfacabd3..27e26975d3b 100644 --- a/build/mach_bootstrap.py +++ b/build/mach_bootstrap.py @@ -254,8 +254,26 @@ def bootstrap(topsrcdir, mozilla_dir=None): raise # Add common metadata to help submit sorted data later on. - # For now, we'll just record the mach command that was invoked. data['argv'] = sys.argv + data.setdefault('system', {}).update(dict( + architecture=list(platform.architecture()), + machine=platform.machine(), + python_version=platform.python_version(), + release=platform.release(), + system=platform.system(), + version=platform.version(), + )) + + if platform.system() == 'Linux': + dist = list(platform.linux_distribution()) + data['system']['linux_distribution'] = dist + elif platform.system() == 'Windows': + win32_ver=list((platform.win32_ver())), + data['system']['win32_ver'] = win32_ver + elif platform.system() == 'Darwin': + # mac version is a special Cupertino snowflake + r, v, m = platform.mac_ver() + data['system']['mac_ver'] = [r, list(v), m] with open(os.path.join(outgoing_dir, str(uuid.uuid4()) + '.json'), 'w') as f: diff --git a/build/telemetry-schema.json b/build/telemetry-schema.json new file mode 100644 index 00000000000..6157bf9d556 --- /dev/null +++ b/build/telemetry-schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "argv": {"type": "array"}, + "system": { + "type": "object", + "properties": { + "architecture": {"type": "array"}, + "linux_distribution": {"type": "array"}, + "mac_ver": {"type": "array"}, + "machine": {"type": "string"}, + "python_version": {"type": "string"}, + "release": {"type": "string"}, + "system": {"type": "string"}, + "version": {"type": "string"}, + "win_ver": {"type": "array"} + }, + "required": ["architecture", "machine", "python_version", + "release", "system", "version"] + } + }, + "required": ["argv", "system"] +} diff --git a/python/mozbuild/mozbuild/controller/building.py b/python/mozbuild/mozbuild/controller/building.py index d9c4b26c797..f7191eaca76 100644 --- a/python/mozbuild/mozbuild/controller/building.py +++ b/python/mozbuild/mozbuild/controller/building.py @@ -377,7 +377,7 @@ class BuildMonitor(MozbuildObject): 'Swap in/out (MB): {sin}/{sout}') o = dict( - version=2, + version=3, argv=sys.argv, start=self.start_time, end=self.end_time, @@ -411,22 +411,15 @@ class BuildMonitor(MozbuildObject): o['resources'].append(entry) - # TODO: it would be nice to collect data on the storage device as well - o['system'] = dict( - architecture=list(platform.architecture()), - machine=platform.machine(), - python_version=platform.python_version(), - release=platform.release(), - system=platform.system(), - version=platform.version(), - ) # If the imports for this file ran before the in-tree virtualenv # was bootstrapped (for instance, for a clobber build in automation), # psutil might not be available. # # Treat psutil as optional to avoid an outright failure to log resources + # TODO: it would be nice to collect data on the storage device as well # in this case. + o['system'] = {} if psutil: o['system'].update(dict( logical_cpu_count=psutil.cpu_count(), @@ -435,17 +428,6 @@ class BuildMonitor(MozbuildObject): vmem_total=psutil.virtual_memory()[0], )) - if platform.system() == 'Linux': - dist = list(platform.linux_distribution()) - o['system']['linux_distribution'] = dist - elif platform.system() == 'Windows': - win32_ver=list((platform.win32_ver())), - o['system']['win32_ver'] = win32_ver - elif platform.system() == 'Darwin': - # mac version is a special Cupertino snowflake - r, v, m = platform.mac_ver() - o['system']['mac_ver'] = [r, list(v), m] - return o def _log_resource_usage(self, prefix, m_type, duration, cpu_percent, diff --git a/python/mozbuild/mozbuild/resources/html-build-viewer/index.html b/python/mozbuild/mozbuild/resources/html-build-viewer/index.html index 026cdbbc040..290098112ef 100644 --- a/python/mozbuild/mozbuild/resources/html-build-viewer/index.html +++ b/python/mozbuild/mozbuild/resources/html-build-viewer/index.html @@ -56,7 +56,7 @@ var currentResources; * Interface for a build resources JSON file. */ function BuildResources(data) { - if (data.version != 1 && data.version != 2) { + if (data.version < 1 || data.version > 3) { throw new Error("Unsupported version of the JSON format: " + data.version); } From 5f24863a07e9fab4b8af8f73fd7d11a41ed55197 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:47 +0900 Subject: [PATCH 005/252] Bug 1249896 - Part 1: Remove unused AndOrLeft, AndOrRight, RelationalLeft, and RelationalRight. r=jwalden --- js/src/asmjs/AsmJS.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index 881c79383f3..db51a1fc49d 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -653,30 +653,6 @@ ComparisonRight(ParseNode* pn) return BinaryOpRight(pn); } -static inline ParseNode* -AndOrLeft(ParseNode* pn) -{ - return BinaryOpLeft(pn); -} - -static inline ParseNode* -AndOrRight(ParseNode* pn) -{ - return BinaryOpRight(pn); -} - -static inline ParseNode* -RelationalLeft(ParseNode* pn) -{ - return BinaryOpLeft(pn); -} - -static inline ParseNode* -RelationalRight(ParseNode* pn) -{ - return BinaryOpRight(pn); -} - static inline bool IsExpressionStatement(ParseNode* pn) { From b02d2b3731352bb0e90ecca05e0c2a892dd10089 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 006/252] Bug 1249896 - Part 2: Remove unused type member from SIMD Int8x16Defn etc. r=bbouvier --- js/src/builtin/SIMD.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index e033d3b2f33..abc24c525ae 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -200,7 +200,6 @@ namespace { #define DEFINE_DEFN_(TypeName) \ class TypeName##Defn { \ public: \ - static const SimdType type = SimdType::TypeName; \ static const JSFunctionSpec Methods[]; \ }; From 819b1846e6cbb1eef13a5b12fee6abbca176ccba Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 007/252] Bug 1249896 - Part 3: Add JS namespace for GenericNaN. r=luke --- js/src/jit/MCallOptimize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 12e4bab1a77..c333179ab90 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -3306,7 +3306,7 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) defVal = constant(DoubleNaNValue()); } else { MOZ_ASSERT(laneType == MIRType_Float32); - defVal = MConstant::NewFloat32(alloc(), GenericNaN()); + defVal = MConstant::NewFloat32(alloc(), JS::GenericNaN()); current->add(defVal); } } From f21deceeca583ee73ba0ae08568c8be67a99a613 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 008/252] Bug 1249896 - Part 4: Avoid declaring variable between cases in switch. r=luke --- js/src/jsopcode.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 9b0dc99a314..32f1d62303f 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -830,6 +830,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, Sprint(sp, "%4u", PCToLineNumber(script, pc)); Sprint(sp, " %s", CodeName[op]); + int i; switch (JOF_TYPE(cs->format)) { case JOF_BYTE: // Scan the trynotes to find the associated catch block @@ -946,9 +947,6 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, Sprint(sp, " %u", GET_UINT32(pc)); break; - { - int i; - case JOF_UINT16: i = (int)GET_UINT16(pc); goto print_int; @@ -972,7 +970,6 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, print_int: Sprint(sp, " %d", i); break; - } default: { char numBuf[12]; From 8c2d7ab4f4a3cd835c540a8e9dc463c3dd8f6eb8 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 009/252] Bug 1249896 - Part 5: Remove unused ReportInvalidTrapResult. r=efaust --- js/src/proxy/ScriptedDirectProxyHandler.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/js/src/proxy/ScriptedDirectProxyHandler.cpp b/js/src/proxy/ScriptedDirectProxyHandler.cpp index d3fb6824e42..25a68438eab 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.cpp +++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp @@ -128,17 +128,6 @@ GetDirectProxyHandlerObject(JSObject* proxy) return proxy->as().extra(ScriptedDirectProxyHandler::HANDLER_EXTRA).toObjectOrNull(); } -static inline void -ReportInvalidTrapResult(JSContext* cx, JSObject* proxy, JSAtom* atom) -{ - RootedValue v(cx, ObjectOrNullValue(proxy)); - JSAutoByteString bytes; - if (!AtomToPrintableString(cx, atom, &bytes)) - return; - ReportValueError2(cx, JSMSG_INVALID_TRAP_RESULT, JSDVG_IGNORE_STACK, v, - nullptr, bytes.ptr()); -} - // ES6 implements both getPrototype and setPrototype traps. We don't have them yet (see bug // 888969). For now, use these, to account for proxy revocation. bool From adb7fe37fbc76fbb6907c87bceb45033603a297e Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 010/252] Bug 1249896 - Part 6: Add gc namespace for Arena::thingsSpan. r=terrence --- js/src/vm/MemoryMetrics.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index 6be0fde81c1..645cef1595e 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -14,6 +14,7 @@ #include "jsobj.h" #include "jsscript.h" +#include "gc/Heap.h" #include "jit/BaselineJIT.h" #include "jit/Ion.h" #include "vm/ArrayObject.h" @@ -356,7 +357,7 @@ StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena, // The admin space includes (a) the header and (b) the padding between the // end of the header and the start of the first GC thing. - size_t allocationSpace = Arena::thingsSpan(arena->aheader.getAllocKind()); + size_t allocationSpace = gc::Arena::thingsSpan(arena->aheader.getAllocKind()); rtStats->currZoneStats->gcHeapArenaAdmin += gc::ArenaSize - allocationSpace; // We don't call the callback on unused things. So we compute the From 4d9e0977e3ef6811b4e9eabe1832175ba9713691 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 011/252] Bug 1249896 - Part 7: Remove unnecessary static from my_ErrorReporter. r=sfink --- js/src/shell/jsshell.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/shell/jsshell.h b/js/src/shell/jsshell.h index 368af57e37a..e29faa6a042 100644 --- a/js/src/shell/jsshell.h +++ b/js/src/shell/jsshell.h @@ -23,7 +23,7 @@ enum JSShellErrNum { const JSErrorFormatString* my_GetErrorMessage(void* userRef, const unsigned errorNumber); -static void +void my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report); JSString* From 3a3482617ccf51441cc6b05050e0c4c2699029ac Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:48 +0900 Subject: [PATCH 012/252] Bug 1249896 - Part 8: Remove unreachable code from GetLine. r=jwalden --- js/src/shell/js.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index c8179eae359..b60dac030fa 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -359,7 +359,7 @@ GetLine(FILE* file, const char * prompt) return nullptr; char* current = buffer; - while (true) { + do { while (true) { if (fgets(current, size - len, file)) break; @@ -387,11 +387,7 @@ GetLine(FILE* file, const char * prompt) buffer = tmp; } current = buffer + len; - } - - if (len && !ferror(file)) - return buffer; - free(buffer); + } while (true); return nullptr; } From 72ff58a5eb3402eb3cc1ad592cc1edef1704f8ba Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 013/252] Bug 1249896 - Part 9: Include shell/jsshell.h in js.cpp. r=sfink --- js/src/shell/js.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index b60dac030fa..7cdd2717627 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -75,6 +75,7 @@ #include "js/TrackedOptimizationInfo.h" #include "perf/jsperf.h" #include "shell/jsoptparse.h" +#include "shell/jsshell.h" #include "shell/OSObject.h" #include "vm/ArgumentsObject.h" #include "vm/Compression.h" From 9d8284bb256a40044b7e8b5906453c07c7921382 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 014/252] Bug 1245112 - Part 12: Move MacroAssembler::branchPtrWithPatch into generic macro assembler. r=nbp --- js/src/jit/MacroAssembler.h | 5 ++++ js/src/jit/arm/MacroAssembler-arm-inl.h | 18 +++++++++++++ js/src/jit/arm/MacroAssembler-arm.h | 12 --------- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 23 +++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 17 ------------- .../MacroAssembler-mips-shared-inl.h | 25 +++++++++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 21 ---------------- js/src/jit/mips64/MacroAssembler-mips64.h | 21 ---------------- js/src/jit/none/MacroAssembler-none.h | 2 -- js/src/jit/x64/MacroAssembler-x64.h | 5 ---- .../MacroAssembler-x86-shared-inl.h | 16 ++++++++++++ js/src/jit/x86/MacroAssembler-x86.h | 5 ---- 12 files changed, 87 insertions(+), 83 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index bb6f1f968e1..50d293c73cd 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -824,6 +824,11 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label) DEFINED_ON(arm, arm64, mips_shared, x86, x64); + template + inline CodeOffsetJump branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH; + template + inline CodeOffsetJump branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH; + // This function compares a Value (lhs) which is having a private pointer // boxed inside a js::Value, with a raw pointer (rhs). inline void branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) PER_ARCH; diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index de1adb1b7bd..898ebe4b304 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -585,6 +585,24 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh branchPtr(cond, scratch, rhs, label); } +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) +{ + ma_cmp(lhs, rhs); + return jumpWithPatch(label, cond); +} + +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) +{ + AutoRegisterScope scratch2(*this, secondScratchReg_); + ma_ldr(lhs, scratch2); + ma_cmp(scratch2, rhs); + return jumpWithPatch(label, cond); +} + void MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 8cd4fd5a050..36abc00058c 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -845,18 +845,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) { return jumpWithPatch(label, Always, documentation); } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel* label) { - ma_cmp(reg, ptr); - return jumpWithPatch(label, cond); - } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel* label) { - AutoRegisterScope scratch2(asMasm(), secondScratchReg_); - ma_ldr(addr, scratch2); - ma_cmp(scratch2, ptr); - return jumpWithPatch(label, cond); - } void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) { if (dest.isFloat()) diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 0ae3ff114a4..7259b1da007 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -654,6 +654,29 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh branchPtr(cond, scratch, rhs, label); } +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) +{ + cmpPtr(lhs, rhs); + return jumpWithPatch(label, cond); +} + +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) +{ + // The scratch register is unused after the condition codes are set. + { + vixl::UseScratchRegisterScope temps(this); + const Register scratch = temps.AcquireX().asUnsized(); + MOZ_ASSERT(scratch != lhs.base); + loadPtr(lhs, scratch); + cmpPtr(scratch, rhs); + } + return jumpWithPatch(label, cond); +} + void MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index b5ca6a4c7d2..169ac4c8d22 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1350,23 +1350,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) { return jumpWithPatch(label, Always, documentation); } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel* label) { - cmpPtr(reg, ptr); - return jumpWithPatch(label, cond); - } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel* label) { - // The scratch register is unused after the condition codes are set. - { - vixl::UseScratchRegisterScope temps(this); - const Register scratch = temps.AcquireX().asUnsized(); - MOZ_ASSERT(scratch != addr.base); - loadPtr(addr, scratch); - cmpPtr(scratch, ptr); - } - return jumpWithPatch(label, cond); - } void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { Subs(ARMRegister(lhs, 64), ARMRegister(lhs, 64), Operand(imm.value)); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 725a681a6f3..569f6e5fd3c 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -346,6 +346,31 @@ MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rh branchPtr(cond, SecondScratchReg, rhs, label); } +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) +{ + movePtr(rhs, ScratchRegister); + Label skipJump; + ma_b(lhs, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); + CodeOffsetJump off = jumpWithPatch(label); + bind(&skipJump); + return off; +} + +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) +{ + loadPtr(lhs, SecondScratchReg); + movePtr(rhs, ScratchRegister); + Label skipJump; + ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); + CodeOffsetJump off = jumpWithPatch(label); + bind(&skipJump); + return off; +} + void MacroAssembler::branchFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index bfc110c1bed..49c1e753569 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -462,27 +462,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr); CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr); - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel* label) { - movePtr(ptr, ScratchRegister); - Label skipJump; - ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); - CodeOffsetJump off = jumpWithPatch(label); - bind(&skipJump); - return off; - } - - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel* label) { - loadPtr(addr, SecondScratchReg); - movePtr(ptr, ScratchRegister); - Label skipJump; - ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); - CodeOffsetJump off = jumpWithPatch(label); - bind(&skipJump); - return off; - } - void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) { if (dest.isFloat()) loadInt32OrDouble(address, dest.fpu()); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 7833e041fd5..e267cd6be05 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -493,27 +493,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr); CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr); - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel* label) { - movePtr(ptr, ScratchRegister); - Label skipJump; - ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); - CodeOffsetJump off = jumpWithPatch(label); - bind(&skipJump); - return off; - } - - template - CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel* label) { - loadPtr(addr, SecondScratchReg); - movePtr(ptr, ScratchRegister); - Label skipJump; - ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); - CodeOffsetJump off = jumpWithPatch(label); - bind(&skipJump); - return off; - } - template void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) { if (dest.isFloat()) diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 34ccb0171ca..029d0d0279e 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -233,8 +233,6 @@ class MacroAssemblerNone : public Assembler CodeOffsetJump jumpWithPatch(RepatchLabel*, Label* doc = nullptr) { MOZ_CRASH(); } CodeOffsetJump jumpWithPatch(RepatchLabel*, Condition, Label* doc = nullptr) { MOZ_CRASH(); } CodeOffsetJump backedgeJump(RepatchLabel* label, Label* doc = nullptr) { MOZ_CRASH(); } - template - CodeOffsetJump branchPtrWithPatch(Condition, T, S, RepatchLabel*) { MOZ_CRASH(); } template void branchTestValue(Condition, T, S, Label*) { MOZ_CRASH(); } void testNullSet(Condition, ValueOperand, Register) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index f603b49cd61..d8e72e85370 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -545,11 +545,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared return jumpWithPatch(label); } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) { - cmpPtr(lhs, ptr); - return jumpWithPatch(label, cond); - } void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { subq(imm, lhs); j(cond, label); diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index d79cb053be1..acd92e6309d 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -295,6 +295,22 @@ MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label branchPtrImpl(cond, lhs, rhs, label); } +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) +{ + cmpPtr(lhs, rhs); + return jumpWithPatch(label, cond); +} + +template +CodeOffsetJump +MacroAssembler::branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) +{ + cmpPtr(lhs, rhs); + return jumpWithPatch(label, cond); +} + void MacroAssembler::branchFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label* label) diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 8da217010ac..9e99af1960b 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -575,11 +575,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared return jumpWithPatch(label); } - template - CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) { - branchPtr(cond, lhs, ptr, label); - return CodeOffsetJump(size()); - } void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) { cmpPtr(lhs, rhs); j(cond, label); From 7ceeb5ed8a3896367f282d43268e86280a579a5d Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 015/252] Bug 1245112 - Part 13: Move MacroAssembler::branchPtrInNurseryRange into generic macro assembler. r=jonco --- js/src/jit/MacroAssembler.h | 3 ++ js/src/jit/arm/MacroAssembler-arm.cpp | 43 ++++++++++--------- js/src/jit/arm/MacroAssembler-arm.h | 1 - js/src/jit/arm64/MacroAssembler-arm64.cpp | 35 ++++++++------- js/src/jit/arm64/MacroAssembler-arm64.h | 1 - .../MacroAssembler-mips-shared.cpp | 15 +++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 17 +------- js/src/jit/mips32/MacroAssembler-mips32.h | 1 - js/src/jit/mips64/MacroAssembler-mips64.cpp | 15 ------- js/src/jit/mips64/MacroAssembler-mips64.h | 1 - js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64.cpp | 35 ++++++++------- js/src/jit/x64/MacroAssembler-x64.h | 1 - js/src/jit/x86/MacroAssembler-x86.cpp | 35 ++++++++------- js/src/jit/x86/MacroAssembler-x86.h | 1 - 15 files changed, 99 insertions(+), 106 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 50d293c73cd..1d8c463d632 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -829,6 +829,9 @@ class MacroAssembler : public MacroAssemblerSpecific template inline CodeOffsetJump branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH; + void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label) + DEFINED_ON(arm, arm64, mips_shared, x86, x64); + // This function compares a Value (lhs) which is having a private pointer // boxed inside a js::Value, with a raw pointer (rhs). inline void branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) PER_ARCH; diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 4cc9a0e3111..00d4a534ecb 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4011,25 +4011,6 @@ MacroAssemblerARMCompat::jumpWithPatch(RepatchLabel* label, Condition cond, Labe return ret; } -void -MacroAssemblerARMCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, - Label* label) -{ - AutoRegisterScope scratch2(asMasm(), secondScratchReg_); - - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(ptr != scratch2); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - uintptr_t startChunk = nursery.start() >> Nursery::ChunkShift; - - ma_mov(Imm32(startChunk), scratch2); - as_rsb(scratch2, scratch2, lsr(ptr, Nursery::ChunkShift)); - asMasm().branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - scratch2, Imm32(nursery.numChunks()), label); -} - void MacroAssemblerARMCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) @@ -4039,7 +4020,7 @@ MacroAssemblerARMCompat::branchValueIsNurseryObject(Condition cond, ValueOperand Label done; branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); bind(&done); } @@ -5065,4 +5046,26 @@ MacroAssembler::pushFakeReturnAddress(Register scratch) return pseudoReturnOffset; } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label* label) +{ + AutoRegisterScope scratch2(*this, secondScratchReg_); + + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(ptr != scratch2); + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + uintptr_t startChunk = nursery.start() >> Nursery::ChunkShift; + + ma_mov(Imm32(startChunk), scratch2); + as_rsb(scratch2, scratch2, lsr(ptr, Nursery::ChunkShift)); + branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + scratch2, Imm32(nursery.numChunks()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 36abc00058c..5d668be7ce5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1536,7 +1536,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay()); } - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); void loadWasmActivation(Register dest) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index 51662f68fb7..39e4fec443d 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -217,22 +217,6 @@ MacroAssemblerCompat::handleFailureWithHandlerTail(void* handler) Br(x1); } -void -MacroAssemblerCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(ptr != ScratchReg && ptr != ScratchReg2); // Both may be used internally. - MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - asMasm().addPtr(ptr, temp); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - temp, ImmWord(nursery.nurserySize()), label); -} - void MacroAssemblerCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) @@ -720,6 +704,25 @@ MacroAssembler::pushFakeReturnAddress(Register scratch) return pseudoReturnOffset; } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(ptr != ScratchReg && ptr != ScratchReg2); // Both may be used internally. + MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + temp, ImmWord(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style } // namespace jit diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 169ac4c8d22..27fb88d07bf 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2176,7 +2176,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler storeValue(JSVAL_TYPE_INT32, scratch, dest); } - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); void profilerEnterFrame(Register framePtr, Register scratch) { diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp index 5f31477c0c0..0892a7c9dc8 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp @@ -1276,4 +1276,19 @@ MacroAssembler::pushFakeReturnAddress(Register scratch) return retAddr; } +void +MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(ptr != SecondScratchReg); + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg); + addPtr(ptr, SecondScratchReg); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + SecondScratchReg, Imm32(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 177e7efe0fb..336b6621db8 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -2327,21 +2327,6 @@ MacroAssemblerMIPSCompat::toggledCall(JitCode* target, bool enabled) return offset; } -void -MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(ptr != SecondScratchReg); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg); - asMasm().addPtr(ptr, SecondScratchReg); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - SecondScratchReg, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerMIPSCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) @@ -2351,7 +2336,7 @@ MacroAssemblerMIPSCompat::branchValueIsNurseryObject(Condition cond, ValueOperan Label done; branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); bind(&done); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 49c1e753569..bcf433007c8 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1111,7 +1111,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS as_movs(dest, src); } - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index b889f230fde..96b94eaef47 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -2499,21 +2499,6 @@ MacroAssemblerMIPS64Compat::toggledCall(JitCode* target, bool enabled) return offset; } -void -MacroAssemblerMIPS64Compat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(ptr != SecondScratchReg); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg); - asMasm().addPtr(ptr, SecondScratchReg); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - SecondScratchReg, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerMIPS64Compat::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index e267cd6be05..c18b9d237d4 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -1119,7 +1119,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 as_movs(dest, src); } - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 029d0d0279e..ae8c41e8fd7 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -413,7 +413,6 @@ class MacroAssemblerNone : public Assembler void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); } void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); } - void branchPtrInNurseryRange(Condition, Register, Register, Label*) { MOZ_CRASH(); } void branchValueIsNurseryObject(Condition, ValueOperand, Register, Label*) { MOZ_CRASH(); } void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 9a8313df86d..5c922c93dd5 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -264,22 +264,6 @@ template void MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); -void -MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label) -{ - ScratchRegisterScope scratch(asMasm()); - - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(ptr != scratch); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), scratch); - asMasm().addPtr(ptr, scratch); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - scratch, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) @@ -464,4 +448,23 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result) callWithABIPost(stackAdjust, result); } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label) +{ + ScratchRegisterScope scratch(*this); + + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(ptr != scratch); + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), scratch); + addPtr(ptr, scratch); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + scratch, Imm32(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index d8e72e85370..a5532e6cd33 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1195,7 +1195,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared storeValue(JSVAL_TYPE_INT32, scratch, Dest); } - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); // Instrumentation for entering and leaving the profiler. diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 0cd7f224a82..79353574fc8 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -328,21 +328,6 @@ template void MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); -void -MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(ptr != temp); - MOZ_ASSERT(temp != InvalidReg); // A temp register is required for x86. - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - asMasm().addPtr(ptr, temp); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - temp, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) @@ -352,7 +337,7 @@ MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value Label done; branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); bind(&done); } @@ -498,4 +483,22 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result) callWithABIPost(stackAdjust, result); } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(ptr != temp); + MOZ_ASSERT(temp != InvalidReg); // A temp register is required for x86. + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + temp, Imm32(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 9e99af1960b..f0de78bf441 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -949,7 +949,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared // Used from within an Exit frame to handle a pending exception. void handleFailureWithHandlerTail(void* handler); - void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); // Instrumentation for entering and leaving the profiler. From a24f0b6e183f27052ba55e96d8b60149f20efc7a Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 016/252] Bug 1245112 - Part 14: Move MacroAssembler::branchValueIsNurseryObject into generic macro assembler. r=jonco --- js/src/jit/MacroAssembler.h | 1 + js/src/jit/arm/MacroAssembler-arm.cpp | 28 ++++++------- js/src/jit/arm/MacroAssembler-arm.h | 2 - js/src/jit/arm64/MacroAssembler-arm64.cpp | 44 ++++++++++----------- js/src/jit/arm64/MacroAssembler-arm64.h | 2 - js/src/jit/mips32/MacroAssembler-mips32.cpp | 31 ++++++++------- js/src/jit/mips32/MacroAssembler-mips32.h | 3 -- js/src/jit/mips64/MacroAssembler-mips64.cpp | 35 ++++++++-------- js/src/jit/mips64/MacroAssembler-mips64.h | 3 -- js/src/jit/none/MacroAssembler-none.h | 2 - js/src/jit/x64/MacroAssembler-x64.cpp | 44 ++++++++++----------- js/src/jit/x64/MacroAssembler-x64.h | 2 - js/src/jit/x86/MacroAssembler-x86.cpp | 28 ++++++------- js/src/jit/x86/MacroAssembler-x86.h | 2 - 14 files changed, 109 insertions(+), 118 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 1d8c463d632..f2af77bf8fb 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -831,6 +831,7 @@ class MacroAssembler : public MacroAssemblerSpecific void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label) DEFINED_ON(arm, arm64, mips_shared, x86, x64); + void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) PER_ARCH; // This function compares a Value (lhs) which is having a private pointer // boxed inside a js::Value, with a raw pointer (rhs). diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 00d4a534ecb..2b219650306 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4011,20 +4011,6 @@ MacroAssemblerARMCompat::jumpWithPatch(RepatchLabel* label, Condition cond, Labe return ret; } -void -MacroAssemblerARMCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, - Register temp, Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - - Label done; - - branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); - - bind(&done); -} - namespace js { namespace jit { @@ -5068,4 +5054,18 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t scratch2, Imm32(nursery.numChunks()), label); } +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, + Register temp, Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + Label done; + + branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); + branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + + bind(&done); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 5d668be7ce5..692f0a036d4 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1536,8 +1536,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay()); } - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); - void loadWasmActivation(Register dest) { loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index 39e4fec443d..72c90645a3d 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -217,28 +217,6 @@ MacroAssemblerCompat::handleFailureWithHandlerTail(void* handler) Br(x1); } -void -MacroAssemblerCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); // Both may be used internally. - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - - // Avoid creating a bogus ObjectValue below. - if (!nursery.exists()) - return; - - // 'Value' representing the start of the nursery tagged as a JSObject - Value start = ObjectValue(*reinterpret_cast(nursery.start())); - - movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), temp); - asMasm().addPtr(value.valueReg(), temp); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - temp, ImmWord(nursery.nurserySize()), label); -} - void MacroAssemblerCompat::breakpoint() { @@ -723,6 +701,28 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t temp, ImmWord(nursery.nurserySize()), label); } +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); // Both may be used internally. + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + + // Avoid creating a bogus ObjectValue below. + if (!nursery.exists()) + return; + + // 'Value' representing the start of the nursery tagged as a JSObject + Value start = ObjectValue(*reinterpret_cast(nursery.start())); + + movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), temp); + addPtr(value.valueReg(), temp); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + temp, ImmWord(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style } // namespace jit diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 27fb88d07bf..88383c350ef 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2176,8 +2176,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler storeValue(JSVAL_TYPE_INT32, scratch, dest); } - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); - void profilerEnterFrame(Register framePtr, Register scratch) { AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation()); loadPtr(activation, scratch); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 336b6621db8..ef1000f7a07 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -2327,20 +2327,6 @@ MacroAssemblerMIPSCompat::toggledCall(JitCode* target, bool enabled) return offset; } -void -MacroAssemblerMIPSCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, - Register temp, Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - - Label done; - - branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); - - bind(&done); -} - void MacroAssemblerMIPSCompat::profilerEnterFrame(Register framePtr, Register scratch) { @@ -2526,4 +2512,21 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result) callWithABIPost(stackAdjust, result); } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, + Register temp, Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + Label done; + + branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); + branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + + bind(&done); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index bcf433007c8..f5bf0cd2665 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1111,9 +1111,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS as_movs(dest, src); } - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, - Label* label); - void loadWasmActivation(Register dest) { loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); } diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 96b94eaef47..cd197cec58c 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -2499,22 +2499,6 @@ MacroAssemblerMIPS64Compat::toggledCall(JitCode* target, bool enabled) return offset; } -void -MacroAssemblerMIPS64Compat::branchValueIsNurseryObject(Condition cond, ValueOperand value, - Register temp, Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - - // 'Value' representing the start of the nursery tagged as a JSObject - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - Value start = ObjectValue(*reinterpret_cast(nursery.start())); - - movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), SecondScratchReg); - asMasm().addPtr(value.valueReg(), SecondScratchReg); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - SecondScratchReg, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerMIPS64Compat::profilerEnterFrame(Register framePtr, Register scratch) { @@ -2683,4 +2667,23 @@ MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result) callWithABIPost(stackAdjust, result); } +// =============================================================== +// Branch functions + +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, + Register temp, Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + // 'Value' representing the start of the nursery tagged as a JSObject + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + Value start = ObjectValue(*reinterpret_cast(nursery.start())); + + movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), SecondScratchReg); + addPtr(value.valueReg(), SecondScratchReg); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + SecondScratchReg, Imm32(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index c18b9d237d4..11ca5d419c5 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -1119,9 +1119,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 as_movs(dest, src); } - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, - Label* label); - void loadWasmActivation(Register dest) { loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); } diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index ae8c41e8fd7..c3c78d452d1 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -413,8 +413,6 @@ class MacroAssemblerNone : public Assembler void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); } void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); } - void branchValueIsNurseryObject(Condition, ValueOperand, Register, Label*) { MOZ_CRASH(); } - void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); } bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); } void loadWasmActivation(Register) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 5c922c93dd5..0fd81b97592 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -264,28 +264,6 @@ template void MacroAssemblerX64::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); -void -MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - - const Nursery& nursery = GetJitContext()->runtime->gcNursery(); - - // Avoid creating a bogus ObjectValue below. - if (!nursery.exists()) - return; - - // 'Value' representing the start of the nursery tagged as a JSObject - Value start = ObjectValue(*reinterpret_cast(nursery.start())); - - ScratchRegisterScope scratch(asMasm()); - movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), scratch); - asMasm().addPtr(value.valueReg(), scratch); - asMasm().branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, - scratch, Imm32(nursery.nurserySize()), label); -} - void MacroAssemblerX64::profilerEnterFrame(Register framePtr, Register scratch) { @@ -467,4 +445,26 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t scratch, Imm32(nursery.nurserySize()), label); } +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + const Nursery& nursery = GetJitContext()->runtime->gcNursery(); + + // Avoid creating a bogus ObjectValue below. + if (!nursery.exists()) + return; + + // 'Value' representing the start of the nursery tagged as a JSObject + Value start = ObjectValue(*reinterpret_cast(nursery.start())); + + ScratchRegisterScope scratch(*this); + movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), scratch); + addPtr(value.valueReg(), scratch); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + scratch, Imm32(nursery.nurserySize()), label); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index a5532e6cd33..982696878dc 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1195,8 +1195,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared storeValue(JSVAL_TYPE_INT32, scratch, Dest); } - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); - // Instrumentation for entering and leaving the profiler. void profilerEnterFrame(Register framePtr, Register scratch); void profilerExitFrame(); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 79353574fc8..5705ec9e748 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -328,20 +328,6 @@ template void MacroAssemblerX86::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); -void -MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, - Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - - Label done; - - branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); - asMasm().branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); - - bind(&done); -} - void MacroAssemblerX86::profilerEnterFrame(Register framePtr, Register scratch) { @@ -501,4 +487,18 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t temp, Imm32(nursery.nurserySize()), label); } +void +MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, + Label* label) +{ + MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + + Label done; + + branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); + branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); + + bind(&done); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index f0de78bf441..8e8c365fa1d 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -949,8 +949,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared // Used from within an Exit frame to handle a pending exception. void handleFailureWithHandlerTail(void* handler); - void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); - // Instrumentation for entering and leaving the profiler. void profilerEnterFrame(Register framePtr, Register scratch); void profilerExitFrame(); From cabefd7e420c9d4d5c7219cb438b0bfc2a4da462 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 017/252] Bug 1245112 - Part 15: Move MacroAssembler::branchAdd32 into generic macro assembler. r=lth --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 16 ++++++++-------- js/src/jit/arm/MacroAssembler-arm.h | 1 - js/src/jit/arm64/MacroAssembler-arm64-inl.h | 8 ++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 6 ------ .../mips-shared/MacroAssembler-mips-shared-inl.h | 13 +++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 10 ---------- js/src/jit/mips64/MacroAssembler-mips64.h | 10 ---------- js/src/jit/none/MacroAssembler-none.h | 1 - .../x86-shared/MacroAssembler-x86-shared-inl.h | 8 ++++++++ .../jit/x86-shared/MacroAssembler-x86-shared.h | 5 ----- 11 files changed, 40 insertions(+), 41 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index f2af77bf8fb..a1462921daa 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -847,6 +847,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchTruncateDouble(FloatRegister src, Register dest, Label* fail) DEFINED_ON(arm, arm64, mips_shared, x86, x64); + template + inline void branchAdd32(Condition cond, T src, Register dest, Label* label) PER_SHARED_ARCH; + template inline void branchTest32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH; template diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 898ebe4b304..5e219868b2c 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -689,6 +689,14 @@ MacroAssembler::branchTruncateDouble(FloatRegister src, Register dest, Label* fa ma_b(fail, Assembler::Equal); } +template +void +MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) +{ + add32(src, dest); + j(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) @@ -765,14 +773,6 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg //}}} check_macroassembler_style // =============================================================== -template -void -MacroAssemblerARMCompat::branchAdd32(Condition cond, T src, Register dest, Label* label) -{ - asMasm().add32(src, dest); - j(cond, label); -} - void MacroAssemblerARMCompat::incrementInt32Value(const Address& addr) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 692f0a036d4..72cede379e6 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -973,7 +973,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Common interface. ///////////////////////////////////////////////////////////////// public: - template inline void branchAdd32(Condition cond, T src, Register dest, Label* label); template void branchSub32(Condition cond, T src, Register dest, Label* label) { ma_sub(src, dest, SetCC); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 7259b1da007..1bfd1ff5a7c 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -772,6 +772,14 @@ MacroAssembler::branchTruncateDouble(FloatRegister src, Register dest, Label* fa And(dest64, dest64, Operand(0xffffffff)); } +template +void +MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) +{ + adds32(src, dest); + branch(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 88383c350ef..92f15a0fe64 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2538,12 +2538,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Ucvtf(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64)); } - template - void branchAdd32(Condition cond, T src, Register dest, Label* label) { - adds32(src, dest); - branch(cond, label); - } - template void branchSub32(Condition cond, T src, Register dest, Label* label) { subs32(src, dest); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 569f6e5fd3c..0c9421acd72 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -410,6 +410,19 @@ MacroAssembler::branchTruncateDouble(FloatRegister src, Register dest, Label* fa ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal); } +template +void +MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* overflow) +{ + switch (cond) { + case Overflow: + ma_addTestOverflow(dest, dest, src, overflow); + break; + default: + MOZ_CRASH("NYI"); + } +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index f5bf0cd2665..415f3b70251 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -887,16 +887,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS inline void incrementInt32Value(const Address& addr); - template - void branchAdd32(Condition cond, T src, Register dest, Label* overflow) { - switch (cond) { - case Overflow: - ma_addTestOverflow(dest, dest, src, overflow); - break; - default: - MOZ_CRASH("NYI"); - } - } template void branchSub32(Condition cond, T src, Register dest, Label* overflow) { switch (cond) { diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 11ca5d419c5..e57671338d0 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -901,16 +901,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 inline void incrementInt32Value(const Address& addr); - template - void branchAdd32(Condition cond, T src, Register dest, Label* overflow) { - switch (cond) { - case Overflow: - ma_addTestOverflow(dest, dest, src, overflow); - break; - default: - MOZ_CRASH("NYI"); - } - } template void branchSub32(Condition cond, T src, Register dest, Label* overflow) { switch (cond) { diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index c3c78d452d1..d24f45e5dcc 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -242,7 +242,6 @@ class MacroAssemblerNone : public Assembler template void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); } template void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); } - template void branchAdd32(Condition, T, S, Label*) { MOZ_CRASH(); } template void branchSub32(Condition, T, S, Label*) { MOZ_CRASH(); } template void decBranchPtr(Condition, T, S, Label*) { MOZ_CRASH(); } template void mov(T, S) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index acd92e6309d..5f26e55bf6c 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -358,6 +358,14 @@ MacroAssembler::branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegis j(ConditionFromDoubleCondition(cond), label); } +template +void +MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) +{ + addl(src, dest); + j(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 2a136a042c2..246512f0715 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -166,11 +166,6 @@ class MacroAssemblerX86Shared : public Assembler return cmplWithPatch(rhs, lhs); } template - void branchAdd32(Condition cond, T src, Register dest, Label* label) { - addl(src, dest); - j(cond, label); - } - template void branchSub32(Condition cond, T src, Register dest, Label* label) { subl(src, dest); j(cond, label); From 5a5df0ad7f4d084fe4c6049cc092dd50eee832c8 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:49 +0900 Subject: [PATCH 018/252] Bug 1245112 - Part 16: Move MacroAssembler::branchSub32 into generic macro assembler. r=lth --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 8 ++++++++ js/src/jit/arm/MacroAssembler-arm.h | 6 ------ js/src/jit/arm64/MacroAssembler-arm64-inl.h | 8 ++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 5 ----- .../MacroAssembler-mips-shared-inl.h | 18 ++++++++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 16 ---------------- js/src/jit/mips64/MacroAssembler-mips64.h | 16 ---------------- js/src/jit/none/MacroAssembler-none.h | 1 - .../x86-shared/MacroAssembler-x86-shared-inl.h | 8 ++++++++ .../jit/x86-shared/MacroAssembler-x86-shared.h | 5 ----- 11 files changed, 44 insertions(+), 49 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index a1462921daa..120fc994ae0 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -849,6 +849,8 @@ class MacroAssembler : public MacroAssemblerSpecific template inline void branchAdd32(Condition cond, T src, Register dest, Label* label) PER_SHARED_ARCH; + template + inline void branchSub32(Condition cond, T src, Register dest, Label* label) PER_SHARED_ARCH; template inline void branchTest32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH; diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 5e219868b2c..41ae66d5cd9 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -697,6 +697,14 @@ MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) j(cond, label); } +template +void +MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) +{ + ma_sub(src, dest, SetCC); + j(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 72cede379e6..8d1467a1913 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -973,12 +973,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Common interface. ///////////////////////////////////////////////////////////////// public: - template - void branchSub32(Condition cond, T src, Register dest, Label* label) { - ma_sub(src, dest, SetCC); - j(cond, label); - } - void not32(Register reg); void move32(Imm32 imm, Register dest); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 1bfd1ff5a7c..57d22e086d5 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -780,6 +780,14 @@ MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) branch(cond, label); } +template +void +MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) +{ + subs32(src, dest); + branch(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 92f15a0fe64..77c1cdffa2c 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2538,11 +2538,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Ucvtf(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64)); } - template - void branchSub32(Condition cond, T src, Register dest, Label* label) { - subs32(src, dest); - branch(cond, label); - } void clampCheck(Register r, Label* handleNotAnInt) { MOZ_CRASH("clampCheck"); } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 0c9421acd72..82055083671 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -423,6 +423,24 @@ MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* overflo } } +template +void +MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* overflow) +{ + switch (cond) { + case Overflow: + ma_subTestOverflow(dest, dest, src, overflow); + break; + case NonZero: + case Zero: + ma_subu(dest, src); + ma_b(dest, dest, overflow, cond); + break; + default: + MOZ_CRASH("NYI"); + } +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 415f3b70251..9e06b48069a 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -887,22 +887,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS inline void incrementInt32Value(const Address& addr); - template - void branchSub32(Condition cond, T src, Register dest, Label* overflow) { - switch (cond) { - case Overflow: - ma_subTestOverflow(dest, dest, src, overflow); - break; - case NonZero: - case Zero: - ma_subu(dest, src); - ma_b(dest, dest, overflow, cond); - break; - default: - MOZ_CRASH("NYI"); - } - } - void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index e57671338d0..751481d01e9 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -901,22 +901,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 inline void incrementInt32Value(const Address& addr); - template - void branchSub32(Condition cond, T src, Register dest, Label* overflow) { - switch (cond) { - case Overflow: - ma_subTestOverflow(dest, dest, src, overflow); - break; - case NonZero: - case Zero: - ma_subu(dest, src); - ma_b(dest, dest, overflow, cond); - break; - default: - MOZ_CRASH("NYI"); - } - } - void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index d24f45e5dcc..364354ace4c 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -242,7 +242,6 @@ class MacroAssemblerNone : public Assembler template void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); } template void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); } - template void branchSub32(Condition, T, S, Label*) { MOZ_CRASH(); } template void decBranchPtr(Condition, T, S, Label*) { MOZ_CRASH(); } template void mov(T, S) { MOZ_CRASH(); } template void movq(T, S) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 5f26e55bf6c..438c5f11118 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -366,6 +366,14 @@ MacroAssembler::branchAdd32(Condition cond, T src, Register dest, Label* label) j(cond, label); } +template +void +MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) +{ + subl(src, dest); + j(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 246512f0715..963191e5da3 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -165,11 +165,6 @@ class MacroAssemblerX86Shared : public Assembler CodeOffset cmp32WithPatch(Register lhs, Imm32 rhs) { return cmplWithPatch(rhs, lhs); } - template - void branchSub32(Condition cond, T src, Register dest, Label* label) { - subl(src, dest); - j(cond, label); - } void atomic_inc32(const Operand& addr) { lock_incl(addr); } From da4b7c920c9ba1d3bbc5288868ef9c97cdb66996 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:50 +0900 Subject: [PATCH 019/252] Bug 1245112 - Part 17: Move MacroAssembler::decBranchPtr into generic macro assembler. r=nbp --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 7 +++++++ js/src/jit/arm/MacroAssembler-arm.h | 4 ---- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 7 +++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 5 ----- js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h | 7 +++++++ js/src/jit/mips32/MacroAssembler-mips32-inl.h | 7 ------- js/src/jit/mips32/MacroAssembler-mips32.h | 2 -- js/src/jit/mips64/MacroAssembler-mips64-inl.h | 7 ------- js/src/jit/mips64/MacroAssembler-mips64.h | 2 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64.h | 5 ----- js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h | 7 +++++++ js/src/jit/x86/MacroAssembler-x86.h | 4 ---- 14 files changed, 30 insertions(+), 37 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 120fc994ae0..d2a519e8a2d 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -852,6 +852,8 @@ class MacroAssembler : public MacroAssemblerSpecific template inline void branchSub32(Condition cond, T src, Register dest, Label* label) PER_SHARED_ARCH; + inline void decBranchPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH; + template inline void branchTest32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH; template diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 41ae66d5cd9..8305fc97c89 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -705,6 +705,13 @@ MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) j(cond, label); } +void +MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) +{ + ma_sub(rhs, lhs, SetCC); + as_b(label, cond); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 8d1467a1913..7d37845f153 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -834,10 +834,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM Condition c = testStringTruthy(truthy, value); ma_b(label, c); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - ma_sub(imm, lhs, SetCC); - as_b(label, cond); - } void moveValue(const Value& val, Register type, Register data); CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always, diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 57d22e086d5..3299be8bef6 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -788,6 +788,13 @@ MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) branch(cond, label); } +void +MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) +{ + Subs(ARMRegister(lhs, 64), ARMRegister(lhs, 64), Operand(rhs.value)); + B(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 77c1cdffa2c..6b6b82372af 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1351,11 +1351,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler return jumpWithPatch(label, Always, documentation); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - Subs(ARMRegister(lhs, 64), ARMRegister(lhs, 64), Operand(imm.value)); - B(cond, label); - } - void branchTestUndefined(Condition cond, Register tag, Label* label) { Condition c = testUndefined(cond, tag); B(label, c); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 82055083671..85cd1e1aa00 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -441,6 +441,13 @@ MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* overflo } } +void +MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) +{ + subPtr(rhs, lhs); + branchPtr(cond, lhs, Imm32(0), label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 4697fc06154..36fe1bcbdcd 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -300,13 +300,6 @@ MacroAssemblerMIPSCompat::retn(Imm32 n) { as_nop(); } -void -MacroAssemblerMIPSCompat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) -{ - asMasm().subPtr(imm, lhs); - asMasm().branchPtr(cond, lhs, Imm32(0), label); -} - } // namespace jit } // namespace js diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 9e06b48069a..3acfdde227f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -440,8 +440,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void branchTestBooleanTruthy(bool b, const ValueOperand& operand, Label* label); - inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label); - // higher level tag testing code Operand ToPayload(Operand base); Address ToPayload(Address base) { diff --git a/js/src/jit/mips64/MacroAssembler-mips64-inl.h b/js/src/jit/mips64/MacroAssembler-mips64-inl.h index b9a7e357e87..bf6b7fb1132 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h +++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h @@ -237,13 +237,6 @@ MacroAssemblerMIPS64Compat::retn(Imm32 n) as_nop(); } -void -MacroAssemblerMIPS64Compat::decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) -{ - asMasm().subPtr(imm, lhs); - asMasm().branchPtr(cond, lhs, Imm32(0), label); -} - } // namespace jit } // namespace js diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 751481d01e9..f3ca1c01ae1 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -481,8 +481,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void branchTestBooleanTruthy(bool b, const ValueOperand& operand, Label* label); - inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label); - // higher level tag testing code Address ToPayload(Address value) { return value; diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 364354ace4c..c6ad8c6dd60 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -242,7 +242,6 @@ class MacroAssemblerNone : public Assembler template void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); } template void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); } - template void decBranchPtr(Condition, T, S, Label*) { MOZ_CRASH(); } template void mov(T, S) { MOZ_CRASH(); } template void movq(T, S) { MOZ_CRASH(); } template void movePtr(T, S) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 982696878dc..5d450094891 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -545,11 +545,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared return jumpWithPatch(label); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subq(imm, lhs); - j(cond, label); - } - void movePtr(Register src, Register dest) { movq(src, dest); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 438c5f11118..5266458374b 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -374,6 +374,13 @@ MacroAssembler::branchSub32(Condition cond, T src, Register dest, Label* label) j(cond, label); } +void +MacroAssembler::decBranchPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) +{ + subPtr(rhs, lhs); + j(cond, label); +} + template void MacroAssembler::branchTest32(Condition cond, Register lhs, Register rhs, L label) diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 8e8c365fa1d..7a2eb70b235 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -579,10 +579,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared cmpPtr(lhs, rhs); j(cond, label); } - void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { - subl(imm, lhs); - j(cond, label); - } void movePtr(ImmWord imm, Register dest) { movl(Imm32(imm.value), dest); From 7600970a24586028e37f451df518cb0f99b521bc Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:50 +0900 Subject: [PATCH 020/252] Bug 1245112 - Part 18: Move MacroAssembler::branchTestInt32 into generic macro assembler. r=jandem --- js/src/jit/MacroAssembler-inl.h | 15 ++++ js/src/jit/MacroAssembler.h | 25 +++--- js/src/jit/arm/MacroAssembler-arm-inl.h | 24 ++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 8 +- js/src/jit/arm/MacroAssembler-arm.h | 2 +- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 67 +++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 57 ++----------- .../MacroAssembler-mips-shared-inl.h | 23 ++++++ js/src/jit/mips32/MacroAssembler-mips32-inl.h | 7 ++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 38 +-------- js/src/jit/mips32/MacroAssembler-mips32.h | 5 -- js/src/jit/mips64/MacroAssembler-mips64-inl.h | 8 ++ js/src/jit/mips64/MacroAssembler-mips64.cpp | 39 +-------- js/src/jit/mips64/MacroAssembler-mips64.h | 5 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 79 ++++++++++++++++++ js/src/jit/x64/MacroAssembler-x64.h | 63 +------------- js/src/jit/x86/MacroAssembler-x86-inl.h | 82 +++++++++++++++++++ js/src/jit/x86/MacroAssembler-x86.h | 54 ++---------- 19 files changed, 347 insertions(+), 255 deletions(-) diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 2eb7447a64f..9ccd45209e8 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -619,6 +619,21 @@ MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 * #endif } +void +MacroAssembler::storeCallResultValue(AnyRegister dest) +{ + unboxValue(JSReturnOperand, dest); +} + +void +MacroAssembler::storeCallResultValue(TypedOrValueRegister dest) +{ + if (dest.hasValue()) + storeCallResultValue(dest.valueReg()); + else + storeCallResultValue(dest.typedReg()); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index d2a519e8a2d..dd4f778c7f7 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -918,6 +918,14 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchTestNeedsIncrementalBarrier(Condition cond, Label* label); + inline void branchTestInt32(Condition cond, Register tag, Label* label) + DEFINED_ON(arm, arm64, mips_shared, x86, x64); + inline void branchTestInt32(Condition cond, const Address& address, Label* label) + DEFINED_ON(arm, arm64, mips_shared, x86, x64); + inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) + DEFINED_ON(arm, arm64, mips_shared, x86, x64); + inline void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) PER_ARCH; + //}}} check_macroassembler_style public: @@ -1028,15 +1036,7 @@ class MacroAssembler : public MacroAssemblerSpecific moveDouble(ReturnDoubleReg, reg); } - void storeCallResultValue(AnyRegister dest) { -#if defined(JS_NUNBOX32) - unboxValue(ValueOperand(JSReturnReg_Type, JSReturnReg_Data), dest); -#elif defined(JS_PUNBOX64) - unboxValue(ValueOperand(JSReturnReg), dest); -#else -#error "Bad architecture" -#endif - } + inline void storeCallResultValue(AnyRegister dest); void storeCallResultValue(ValueOperand dest) { #if defined(JS_NUNBOX32) @@ -1067,12 +1067,7 @@ class MacroAssembler : public MacroAssemblerSpecific #endif } - void storeCallResultValue(TypedOrValueRegister dest) { - if (dest.hasValue()) - storeCallResultValue(dest.valueReg()); - else - storeCallResultValue(dest.typedReg()); - } + inline void storeCallResultValue(TypedOrValueRegister dest); template Register extractString(const T& source, Register scratch) { diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 8305fc97c89..c69f47e0317 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -785,6 +785,30 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg } } +void +MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) +{ + branchTestInt32Impl(cond, tag, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label) +{ + branchTestInt32Impl(cond, src, label); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 2b219650306..3d9b14af981 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2942,7 +2942,7 @@ MacroAssemblerARMCompat::unboxValue(const ValueOperand& src, AnyRegister dest) { if (dest.isFloat()) { Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); convertInt32ToDouble(src.payloadReg(), dest.fpu()); ma_b(&end); bind(¬Int32); @@ -3031,7 +3031,7 @@ MacroAssemblerARMCompat::loadInt32OrDouble(const Address& src, FloatRegister des ScratchRegisterScope scratch(asMasm()); ma_ldr(ToType(src), scratch); - branchTestInt32(Assembler::NotEqual, scratch, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, scratch, ¬Int32); ma_ldr(ToPayload(src), scratch); convertInt32ToDouble(scratch, dest); ma_b(&end); @@ -3059,7 +3059,7 @@ MacroAssemblerARMCompat::loadInt32OrDouble(Register base, Register index, // Since we only have one scratch register, we need to stomp over it with // the tag. ma_ldr(Address(scratch, NUNBOX32_TYPE_OFFSET), scratch); - branchTestInt32(Assembler::NotEqual, scratch, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, scratch, ¬Int32); // Implicitly requires NUNBOX32_PAYLOAD_OFFSET == 0: no offset provided ma_ldr(DTRAddr(base, DtrRegImmShift(index, LSL, shift)), scratch); @@ -3449,7 +3449,7 @@ MacroAssemblerARMCompat::ensureDouble(const ValueOperand& source, FloatRegister { Label isDouble, done; branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); - branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); + asMasm().branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); convertInt32ToDouble(source.payloadReg(), dest); jump(&done); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 7d37845f153..15076fdcc3a 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -763,7 +763,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void loadConstantFloat32(float f, FloatRegister dest); template - void branchTestInt32(Condition cond, const T & t, Label* label) { + void branchTestInt32Impl(Condition cond, const T & t, Label* label) { Condition c = testInt32(cond, t); ma_b(label, c); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 3299be8bef6..faebbe3e91b 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -868,6 +868,30 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg branchTestPtr(cond, lhs.reg, rhs.reg, label); } +void +MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) +{ + branchTestInt32Impl(cond, tag, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label) +{ + branchTestInt32Impl(cond, src, label); +} + //}}} check_macroassembler_style // =============================================================== @@ -935,6 +959,49 @@ MacroAssemblerCompat::branchTestStackPtr(Condition cond, T t, Label* label) asMasm().branchTestPtr(cond, getStackPointer(), t, label); } +// If source is a double, load into dest. +// If source is int32, convert to double and store in dest. +// Else, branch to failure. +void +MacroAssemblerCompat::ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) +{ + Label isDouble, done; + + // TODO: splitTagForTest really should not leak a scratch register. + Register tag = splitTagForTest(source); + { + vixl::UseScratchRegisterScope temps(this); + temps.Exclude(ARMRegister(tag, 64)); + + branchTestDouble(Assembler::Equal, tag, &isDouble); + asMasm().branchTestInt32(Assembler::NotEqual, tag, failure); + } + + convertInt32ToDouble(source.valueReg(), dest); + jump(&done); + + bind(&isDouble); + unboxDouble(source, dest); + + bind(&done); +} + +void +MacroAssemblerCompat::unboxValue(const ValueOperand& src, AnyRegister dest) +{ + if (dest.isFloat()) { + Label notInt32, end; + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); + convertInt32ToDouble(src.valueReg(), dest.fpu()); + jump(&end); + bind(¬Int32); + unboxDouble(src, dest.fpu()); + bind(&end); + } else { + unboxNonDouble(src, dest.gpr()); + } +} + } // namespace jit } // namespace js diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 6b6b82372af..9729472dd0e 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -439,30 +439,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler return scratch; } - // If source is a double, load into dest. - // If source is int32, convert to double and store in dest. - // Else, branch to failure. - void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) { - Label isDouble, done; - - // TODO: splitTagForTest really should not leak a scratch register. - Register tag = splitTagForTest(source); - { - vixl::UseScratchRegisterScope temps(this); - temps.Exclude(ARMRegister(tag, 64)); - - branchTestDouble(Assembler::Equal, tag, &isDouble); - branchTestInt32(Assembler::NotEqual, tag, failure); - } - - convertInt32ToDouble(source.valueReg(), dest); - jump(&done); - - bind(&isDouble); - unboxDouble(source, dest); - - bind(&done); - } + inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); void emitSet(Condition cond, Register dest) { Cset(ARMRegister(dest, 64), cond); @@ -1355,8 +1332,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Condition c = testUndefined(cond, tag); B(label, c); } - void branchTestInt32(Condition cond, Register tag, Label* label) { - Condition c = testInt32(cond, tag); + + template + void branchTestInt32Impl(Condition cond, T& t, Label* label) { + Condition c = testInt32(cond, t); B(label, c); } void branchTestDouble(Condition cond, Register tag, Label* label) { @@ -1392,10 +1371,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Condition c = testUndefined(cond, address); B(label, c); } - void branchTestInt32(Condition cond, const Address& address, Label* label) { - Condition c = testInt32(cond, address); - B(label, c); - } void branchTestDouble(Condition cond, const Address& address, Label* label) { Condition c = testDouble(cond, address); B(label, c); @@ -1431,10 +1406,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Condition c = testUndefined(cond, src); B(label, c); } - void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) { - Condition c = testInt32(cond, src); - B(label, c); - } void branchTestBoolean(Condition cond, const ValueOperand& src, Label* label) { Condition c = testBoolean(cond, src); B(label, c); @@ -1470,10 +1441,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Condition c = testUndefined(cond, address); B(label, c); } - void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) { - Condition c = testInt32(cond, address); - B(label, c); - } void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) { Condition c = testBoolean(cond, address); B(label, c); @@ -1627,20 +1594,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler unboxNonDouble(dest, dest); } - void unboxValue(const ValueOperand& src, AnyRegister dest) { - if (dest.isFloat()) { - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); - convertInt32ToDouble(src.valueReg(), dest.fpu()); - jump(&end); - bind(¬Int32); - unboxDouble(src, dest.fpu()); - bind(&end); - } else { - unboxNonDouble(src, dest.gpr()); - } + inline void unboxValue(const ValueOperand& src, AnyRegister dest); - } void unboxString(const ValueOperand& operand, Register dest) { unboxNonDouble(operand, dest); } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 85cd1e1aa00..944511cc0f7 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -509,6 +509,29 @@ MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Lab branchTestPtr(cond, SecondScratchReg, rhs, label); } +void +MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(tag, ImmTag(JSVAL_TAG_INT32), label, cond); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, SecondScratchReg); + ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, SecondScratchReg); + ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 36fe1bcbdcd..204d33cfa07 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -274,6 +274,13 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg } } +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + ma_b(value.typeReg(), ImmType(JSVAL_TYPE_INT32), label, cond); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index ef1000f7a07..e0ba07eec22 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1126,36 +1126,6 @@ MacroAssemblerMIPSCompat::branchTestPrimitive(Condition cond, Register tag, Labe (cond == Equal) ? Below : AboveOrEqual); } -void -MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const ValueOperand& value, Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - ma_b(value.typeReg(), ImmType(JSVAL_TYPE_INT32), label, cond); -} - -void -MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, Register tag, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - ma_b(tag, ImmTag(JSVAL_TAG_INT32), label, cond); -} - -void -MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const Address& address, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - extractTag(address, SecondScratchReg); - ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); -} - -void -MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const BaseIndex& src, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - extractTag(src, SecondScratchReg); - ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); -} - void MacroAssemblerMIPSCompat:: branchTestBoolean(Condition cond, const ValueOperand& value, Label* label) @@ -1549,7 +1519,7 @@ MacroAssemblerMIPSCompat::unboxValue(const ValueOperand& src, AnyRegister dest) { if (dest.isFloat()) { Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); convertInt32ToDouble(src.payloadReg(), dest.fpu()); ma_b(&end, ShortJump); bind(¬Int32); @@ -1624,7 +1594,7 @@ MacroAssemblerMIPSCompat::loadInt32OrDouble(const Address& src, FloatRegister de Label notInt32, end; // If it's an int, convert it to double. ma_lw(SecondScratchReg, Address(src.base, src.offset + TAG_OFFSET)); - branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); ma_lw(SecondScratchReg, Address(src.base, src.offset + PAYLOAD_OFFSET)); convertInt32ToDouble(SecondScratchReg, dest); ma_b(&end, ShortJump); @@ -1646,7 +1616,7 @@ MacroAssemblerMIPSCompat::loadInt32OrDouble(Register base, Register index, computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg); // Since we only have one scratch, we need to stomp over it with the tag. load32(Address(SecondScratchReg, TAG_OFFSET), SecondScratchReg); - branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg); load32(Address(SecondScratchReg, PAYLOAD_OFFSET), SecondScratchReg); @@ -2052,7 +2022,7 @@ MacroAssemblerMIPSCompat::ensureDouble(const ValueOperand& source, FloatRegister { Label isDouble, done; branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); - branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); + asMasm().branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); convertInt32ToDouble(source.payloadReg(), dest); jump(&done); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 3acfdde227f..971ec65f4db 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -375,11 +375,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest); void loadConstantFloat32(float f, FloatRegister dest); - void branchTestInt32(Condition cond, const ValueOperand& value, Label* label); - void branchTestInt32(Condition cond, Register tag, Label* label); - void branchTestInt32(Condition cond, const Address& address, Label* label); - void branchTestInt32(Condition cond, const BaseIndex& src, Label* label); - void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label); void branchTestBoolean(Condition cond, Register tag, Label* label); void branchTestBoolean(Condition cond, const Address& address, Label* label); diff --git a/js/src/jit/mips64/MacroAssembler-mips64-inl.h b/js/src/jit/mips64/MacroAssembler-mips64-inl.h index bf6b7fb1132..bc749cea7a6 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h +++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h @@ -210,6 +210,14 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg branchTestPtr(cond, lhs.reg, rhs.reg, label); } +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + splitTag(value, SecondScratchReg); + ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index cd197cec58c..0510dd52f50 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -1254,37 +1254,6 @@ MacroAssemblerMIPS64Compat::branchTestPrimitive(Condition cond, Register tag, La (cond == Equal) ? Below : AboveOrEqual); } -void -MacroAssemblerMIPS64Compat::branchTestInt32(Condition cond, const ValueOperand& value, Label* label) -{ - MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); - splitTag(value, SecondScratchReg); - ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); -} - -void -MacroAssemblerMIPS64Compat::branchTestInt32(Condition cond, Register tag, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - ma_b(tag, ImmTag(JSVAL_TAG_INT32), label, cond); -} - -void -MacroAssemblerMIPS64Compat::branchTestInt32(Condition cond, const Address& address, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - extractTag(address, SecondScratchReg); - ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); -} - -void -MacroAssemblerMIPS64Compat::branchTestInt32(Condition cond, const BaseIndex& src, Label* label) -{ - MOZ_ASSERT(cond == Equal || cond == NotEqual); - extractTag(src, SecondScratchReg); - ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); -} - void MacroAssemblerMIPS64Compat:: branchTestBoolean(Condition cond, const ValueOperand& value, Label* label) @@ -1775,7 +1744,7 @@ MacroAssemblerMIPS64Compat::unboxValue(const ValueOperand& src, AnyRegister dest { if (dest.isFloat()) { Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); convertInt32ToDouble(src.valueReg(), dest.fpu()); ma_b(&end, ShortJump); bind(¬Int32); @@ -1849,7 +1818,7 @@ MacroAssemblerMIPS64Compat::loadInt32OrDouble(const Address& src, FloatRegister // If it's an int, convert it to double. loadPtr(Address(src.base, src.offset), ScratchRegister); ma_dsrl(SecondScratchReg, ScratchRegister, Imm32(JSVAL_TAG_SHIFT)); - branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); loadPtr(Address(src.base, src.offset), SecondScratchReg); convertInt32ToDouble(SecondScratchReg, dest); ma_b(&end, ShortJump); @@ -1870,7 +1839,7 @@ MacroAssemblerMIPS64Compat::loadInt32OrDouble(const BaseIndex& addr, FloatRegist // Since we only have one scratch, we need to stomp over it with the tag. loadPtr(Address(SecondScratchReg, 0), ScratchRegister); ma_dsrl(SecondScratchReg, ScratchRegister, Imm32(JSVAL_TAG_SHIFT)); - branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); + asMasm().branchTestInt32(Assembler::NotEqual, SecondScratchReg, ¬Int32); computeScaledAddress(addr, SecondScratchReg); loadPtr(Address(SecondScratchReg, 0), SecondScratchReg); @@ -2213,7 +2182,7 @@ MacroAssemblerMIPS64Compat::ensureDouble(const ValueOperand& source, FloatRegist Label isDouble, done; Register tag = splitTagForTest(source); branchTestDouble(Assembler::Equal, tag, &isDouble); - branchTestInt32(Assembler::NotEqual, tag, failure); + asMasm().branchTestInt32(Assembler::NotEqual, tag, failure); unboxInt32(source, ScratchRegister); convertInt32ToDouble(ScratchRegister, dest); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index f3ca1c01ae1..b03c64f1314 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -416,11 +416,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest); void loadConstantFloat32(float f, FloatRegister dest); - void branchTestInt32(Condition cond, const ValueOperand& value, Label* label); - void branchTestInt32(Condition cond, Register tag, Label* label); - void branchTestInt32(Condition cond, const Address& address, Label* label); - void branchTestInt32(Condition cond, const BaseIndex& src, Label* label); - void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label); void branchTestBoolean(Condition cond, Register tag, Label* label); void branchTestBoolean(Condition cond, const Address& address, Label* label); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index c6ad8c6dd60..948eca76fe9 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -346,7 +346,6 @@ class MacroAssemblerNone : public Assembler Register splitTagForTest(ValueOperand) { MOZ_CRASH(); } template void branchTestUndefined(Condition, T, Label*) { MOZ_CRASH(); } - template void branchTestInt32(Condition, T, Label*) { MOZ_CRASH(); } template void branchTestBoolean(Condition, T, Label*) { MOZ_CRASH(); } template void branchTestDouble(Condition, T, Label*) { MOZ_CRASH(); } template void branchTestNull(Condition, T, Label*) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 8ca67393af0..63f679878dc 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -356,6 +356,36 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg branchTestPtr(cond, lhs.reg, rhs.reg, label); } +void +MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) +{ + cond = testInt32(cond, tag); + j(cond, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) +{ + MOZ_ASSERT(cond == Equal || cond == NotEqual); + branchTestInt32Impl(cond, Operand(address), label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) +{ + ScratchRegisterScope scratch(*this); + splitTag(address, scratch); + branchTestInt32(cond, scratch, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label) +{ + ScratchRegisterScope scratch(*this); + splitTag(src, scratch); + branchTestInt32(cond, scratch, label); +} + //}}} check_macroassembler_style // =============================================================== @@ -381,6 +411,55 @@ MacroAssemblerX64::branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Lab j(cond, label); } +void +MacroAssemblerX64::unboxValue(const ValueOperand& src, AnyRegister dest) +{ + if (dest.isFloat()) { + Label notInt32, end; + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); + convertInt32ToDouble(src.valueReg(), dest.fpu()); + jump(&end); + bind(¬Int32); + unboxDouble(src, dest.fpu()); + bind(&end); + } else { + unboxNonDouble(src, dest.gpr()); + } +} + +void +MacroAssemblerX64::loadInt32OrDouble(const Operand& operand, FloatRegister dest) +{ + Label notInt32, end; + branchTestInt32Impl(Assembler::NotEqual, operand, ¬Int32); + convertInt32ToDouble(operand, dest); + jump(&end); + bind(¬Int32); + loadDouble(operand, dest); + bind(&end); +} + +// If source is a double, load it into dest. If source is int32, +// convert it to double. Else, branch to failure. +void +MacroAssemblerX64::ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) +{ + Label isDouble, done; + Register tag = splitTagForTest(source); + branchTestDouble(Assembler::Equal, tag, &isDouble); + asMasm().branchTestInt32(Assembler::NotEqual, tag, failure); + + ScratchRegisterScope scratch(asMasm()); + unboxInt32(source, scratch); + convertInt32ToDouble(scratch, dest); + jump(&done); + + bind(&isDouble); + unboxDouble(source, dest); + + bind(&done); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 5d450094891..4133e9d08f1 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -681,10 +681,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared cond = testUndefined(cond, tag); j(cond, label); } - void branchTestInt32(Condition cond, Register tag, Label* label) { - cond = testInt32(cond, tag); - j(cond, label); - } void branchTestDouble(Condition cond, Register tag, Label* label) { cond = testDouble(cond, tag); j(cond, label); @@ -726,15 +722,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared MOZ_ASSERT(cond == Equal || cond == NotEqual); branchTestUndefined(cond, Operand(address), label); } - void branchTestInt32(Condition cond, const Operand& operand, Label* label) { + void branchTestInt32Impl(Condition cond, const Operand& operand, Label* label) { MOZ_ASSERT(cond == Equal || cond == NotEqual); cmp32(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); j(cond, label); } - void branchTestInt32(Condition cond, const Address& address, Label* label) { - MOZ_ASSERT(cond == Equal || cond == NotEqual); - branchTestInt32(cond, Operand(address), label); - } void branchTestDouble(Condition cond, const Operand& operand, Label* label) { MOZ_ASSERT(cond == Equal || cond == NotEqual); ScratchRegisterScope scratch(asMasm()); @@ -776,11 +768,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared cond = testUndefined(cond, src); j(cond, label); } - void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) { - ScratchRegisterScope scratch(asMasm()); - splitTag(src, scratch); - branchTestInt32(cond, scratch, label); - } void branchTestBoolean(Condition cond, const ValueOperand& src, Label* label) { ScratchRegisterScope scratch(asMasm()); splitTag(src, scratch); @@ -817,11 +804,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared cond = testUndefined(cond, address); j(cond, label); } - void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) { - ScratchRegisterScope scratch(asMasm()); - splitTag(address, scratch); - branchTestInt32(cond, scratch, label); - } void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) { ScratchRegisterScope scratch(asMasm()); splitTag(address, scratch); @@ -1036,19 +1018,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared return scratch; } - void unboxValue(const ValueOperand& src, AnyRegister dest) { - if (dest.isFloat()) { - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); - convertInt32ToDouble(src.valueReg(), dest.fpu()); - jump(&end); - bind(¬Int32); - unboxDouble(src, dest.fpu()); - bind(&end); - } else { - unboxNonDouble(src, dest.gpr()); - } - } + inline void unboxValue(const ValueOperand& src, AnyRegister dest); // These two functions use the low 32-bits of the full value register. void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) { @@ -1093,15 +1063,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared j(cond, label); } - void loadInt32OrDouble(const Operand& operand, FloatRegister dest) { - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, operand, ¬Int32); - convertInt32ToDouble(operand, dest); - jump(&end); - bind(¬Int32); - loadDouble(operand, dest); - bind(&end); - } + inline void loadInt32OrDouble(const Operand& operand, FloatRegister dest); template void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { @@ -1153,24 +1115,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared inline void incrementInt32Value(const Address& addr); - // If source is a double, load it into dest. If source is int32, - // convert it to double. Else, branch to failure. - void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) { - Label isDouble, done; - Register tag = splitTagForTest(source); - branchTestDouble(Assembler::Equal, tag, &isDouble); - branchTestInt32(Assembler::NotEqual, tag, failure); - - ScratchRegisterScope scratch(asMasm()); - unboxInt32(source, scratch); - convertInt32ToDouble(scratch, dest); - jump(&done); - - bind(&isDouble); - unboxDouble(source, dest); - - bind(&done); - } + inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); public: void handleFailureWithHandlerTail(void* handler); diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index a7afdfaa681..19d17c16036 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -365,6 +365,30 @@ MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Reg } } +void +MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label) +{ + branchTestInt32Impl(cond, tag, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label) +{ + branchTestInt32Impl(cond, address, label); +} + +void +MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label) +{ + branchTestInt32Impl(cond, src, label); +} + //}}} check_macroassembler_style // =============================================================== @@ -416,6 +440,64 @@ MacroAssemblerX86::branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Lab j(cond, label); } +void +MacroAssemblerX86::unboxValue(const ValueOperand& src, AnyRegister dest) +{ + if (dest.isFloat()) { + Label notInt32, end; + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); + convertInt32ToDouble(src.payloadReg(), dest.fpu()); + jump(&end); + bind(¬Int32); + unboxDouble(src, dest.fpu()); + bind(&end); + } else { + if (src.payloadReg() != dest.gpr()) + movl(src.payloadReg(), dest.gpr()); + } +} + +template +void +MacroAssemblerX86::loadInt32OrDouble(const T& src, FloatRegister dest) +{ + Label notInt32, end; + asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32); + convertInt32ToDouble(ToPayload(src), dest); + jump(&end); + bind(¬Int32); + loadDouble(src, dest); + bind(&end); +} + +template +void +MacroAssemblerX86::loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) +{ + if (dest.isFloat()) + loadInt32OrDouble(src, dest.fpu()); + else + movl(Operand(src), dest.gpr()); +} + +// If source is a double, load it into dest. If source is int32, +// convert it to double. Else, branch to failure. +void +MacroAssemblerX86::ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) +{ + Label isDouble, done; + branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); + asMasm().branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); + + convertInt32ToDouble(source.payloadReg(), dest); + jump(&done); + + bind(&isDouble); + unboxDouble(source, dest); + + bind(&done); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 7a2eb70b235..8c67a59f383 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -72,6 +72,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared Address ToPayload(Address base) { return base; } + BaseIndex ToPayload(BaseIndex base) { + return base; + } Operand ToType(Operand base) { switch (base.kind()) { case Operand::MEM_REG_DISP: @@ -658,7 +661,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared j(cond, label); } template - void branchTestInt32(Condition cond, const T& t, Label* label) { + void branchTestInt32Impl(Condition cond, const T& t, Label* label) { cond = testInt32(cond, t); j(cond, label); } @@ -787,20 +790,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared vunpcklps(ScratchDoubleReg, dest, dest); } } - void unboxValue(const ValueOperand& src, AnyRegister dest) { - if (dest.isFloat()) { - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, src, ¬Int32); - convertInt32ToDouble(src.payloadReg(), dest.fpu()); - jump(&end); - bind(¬Int32); - unboxDouble(src, dest.fpu()); - bind(&end); - } else { - if (src.payloadReg() != dest.gpr()) - movl(src.payloadReg(), dest.gpr()); - } - } + inline void unboxValue(const ValueOperand& src, AnyRegister dest); void unboxPrivate(const ValueOperand& src, Register dest) { if (src.payloadReg() != dest) movl(src.payloadReg(), dest); @@ -874,23 +864,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared j(cond, label); } - void loadInt32OrDouble(const Operand& operand, FloatRegister dest) { - Label notInt32, end; - branchTestInt32(Assembler::NotEqual, operand, ¬Int32); - convertInt32ToDouble(ToPayload(operand), dest); - jump(&end); - bind(¬Int32); - loadDouble(operand, dest); - bind(&end); - } + template + inline void loadInt32OrDouble(const T& src, FloatRegister dest); template - void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { - if (dest.isFloat()) - loadInt32OrDouble(Operand(src), dest.fpu()); - else - movl(Operand(src), dest.gpr()); - } + inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest); template void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, @@ -925,21 +903,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared addl(Imm32(1), payloadOf(addr)); } - // If source is a double, load it into dest. If source is int32, - // convert it to double. Else, branch to failure. - void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) { - Label isDouble, done; - branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); - branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); - - convertInt32ToDouble(source.payloadReg(), dest); - jump(&done); - - bind(&isDouble); - unboxDouble(source, dest); - - bind(&done); - } + inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); public: // Used from within an Exit frame to handle a pending exception. From d1e1da5cbab38fc2732cbba97c2535ae210fa84e Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:50 +0900 Subject: [PATCH 021/252] Bug 1245112 - Part 19: Move MacroAssembler::branchTestInt32Truthy into generic macro assembler. r=jandem --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 7 +++++++ js/src/jit/arm/MacroAssembler-arm.h | 4 ---- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 7 +++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 4 ---- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 8 ++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 7 ------- js/src/jit/mips32/MacroAssembler-mips32.h | 2 -- js/src/jit/mips64/MacroAssembler-mips64-inl.h | 7 +++++++ js/src/jit/mips64/MacroAssembler-mips64.cpp | 7 ------- js/src/jit/mips64/MacroAssembler-mips64.h | 2 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64.h | 4 ---- js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h | 7 +++++++ js/src/jit/x86/MacroAssembler-x86.h | 4 ---- 15 files changed, 39 insertions(+), 35 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index dd4f778c7f7..74e121cf6a4 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -926,6 +926,9 @@ class MacroAssembler : public MacroAssemblerSpecific DEFINED_ON(arm, arm64, mips_shared, x86, x64); inline void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) PER_ARCH; + inline void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) + DEFINED_ON(arm, arm64, mips32, mips64, x86_shared); + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index c69f47e0317..ef33c8f1b75 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -809,6 +809,13 @@ MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* branchTestInt32Impl(cond, src, label); } +void +MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) +{ + Condition c = testInt32Truthy(truthy, operand); + ma_b(label, c); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 15076fdcc3a..92405f1a018 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -818,10 +818,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM MOZ_ASSERT(cond == Equal || cond == NotEqual); branchTestValue(cond, val, MagicValue(why), label); } - void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) { - Condition c = testInt32Truthy(truthy, operand); - ma_b(label, c); - } void branchTestBooleanTruthy(bool truthy, const ValueOperand& operand, Label* label) { Condition c = testBooleanTruthy(truthy, operand); ma_b(label, c); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index faebbe3e91b..512c0867b2f 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -892,6 +892,13 @@ MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* branchTestInt32Impl(cond, src, label); } +void +MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) +{ + Condition c = testInt32Truthy(truthy, operand); + B(label, c); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 9729472dd0e..b0b90f0e4a2 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1969,10 +1969,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Tst(payload32, payload32); return truthy ? NonZero : Zero; } - void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) { - Condition c = testInt32Truthy(truthy, operand); - B(label, c); - } void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) { Fcmp(ARMFPRegister(reg, 64), 0.0); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 204d33cfa07..79f5c056579 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -281,6 +281,14 @@ MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label ma_b(value.typeReg(), ImmType(JSVAL_TYPE_INT32), label, cond); } + +void +MacroAssembler::branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label) +{ + as_and(ScratchRegister, value.payloadReg(), value.payloadReg()); + ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index e0ba07eec22..e3d4d8ec31f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1638,13 +1638,6 @@ MacroAssemblerMIPSCompat::loadConstantDouble(double dp, FloatRegister dest) ma_lid(dest, dp); } -void -MacroAssemblerMIPSCompat::branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label) -{ - as_and(ScratchRegister, value.payloadReg(), value.payloadReg()); - ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); -} - void MacroAssemblerMIPSCompat::branchTestStringTruthy(bool b, const ValueOperand& value, Label* label) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 971ec65f4db..2098a0db84a 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -427,8 +427,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS branchTestValue(cond, val, MagicValue(why), label); } - void branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label); - void branchTestStringTruthy(bool b, const ValueOperand& value, Label* label); void branchTestDoubleTruthy(bool b, FloatRegister value, Label* label); diff --git a/js/src/jit/mips64/MacroAssembler-mips64-inl.h b/js/src/jit/mips64/MacroAssembler-mips64-inl.h index bc749cea7a6..9cfff66458b 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h +++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h @@ -218,6 +218,13 @@ MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond); } +void +MacroAssembler::branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label) +{ + ma_dext(ScratchRegister, value.valueReg(), Imm32(0), Imm32(32)); + ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 0510dd52f50..6e03c1edb6b 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -1861,13 +1861,6 @@ MacroAssemblerMIPS64Compat::loadConstantDouble(double dp, FloatRegister dest) ma_lid(dest, dp); } -void -MacroAssemblerMIPS64Compat::branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label) -{ - ma_dext(ScratchRegister, value.valueReg(), Imm32(0), Imm32(32)); - ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero); -} - void MacroAssemblerMIPS64Compat::branchTestStringTruthy(bool b, const ValueOperand& value, Label* label) { diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index b03c64f1314..4fc79faf3cb 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -468,8 +468,6 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 branchTestValue(cond, val, MagicValue(why), label); } - void branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label); - void branchTestStringTruthy(bool b, const ValueOperand& value, Label* label); void branchTestDoubleTruthy(bool b, FloatRegister value, Label* label); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 948eca76fe9..718043a17aa 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -394,7 +394,6 @@ class MacroAssemblerNone : public Assembler void loadConstantFloat32(float, FloatRegister) { MOZ_CRASH(); } Condition testInt32Truthy(bool, ValueOperand) { MOZ_CRASH(); } Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); } - void branchTestInt32Truthy(bool, ValueOperand, Label*) { MOZ_CRASH(); } void branchTestBooleanTruthy(bool, ValueOperand, Label*) { MOZ_CRASH(); } void branchTestStringTruthy(bool, ValueOperand, Label*) { MOZ_CRASH(); } void branchTestDoubleTruthy(bool, FloatRegister, Label*) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 4133e9d08f1..33d6735dba8 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1044,10 +1044,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared test32(operand.valueReg(), operand.valueReg()); return truthy ? NonZero : Zero; } - void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) { - Condition cond = testInt32Truthy(truthy, operand); - j(cond, label); - } void branchTestBooleanTruthy(bool truthy, const ValueOperand& operand, Label* label) { test32(operand.valueReg(), operand.valueReg()); j(truthy ? NonZero : Zero, label); diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 5266458374b..4f2b27bd55f 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -428,6 +428,13 @@ MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Lab j(cond, label); } +void +MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) +{ + Condition cond = testInt32Truthy(truthy, operand); + j(cond, label); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 8c67a59f383..6a49fb460c4 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -846,10 +846,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared test32(operand.payloadReg(), operand.payloadReg()); return truthy ? NonZero : Zero; } - void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) { - Condition cond = testInt32Truthy(truthy, operand); - j(cond, label); - } void branchTestBooleanTruthy(bool truthy, const ValueOperand& operand, Label* label) { test32(operand.payloadReg(), operand.payloadReg()); j(truthy ? NonZero : Zero, label); From df3a609f99462b83d309da1f98622d7ac82da294 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:50 +0900 Subject: [PATCH 022/252] Bug 1249954 - Handle OOM in SingleStepCallback. r=terrence --- js/src/shell/js.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 7cdd2717627..9e5f1e4d731 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4404,6 +4404,7 @@ SingleStepCallback(void* arg, jit::Simulator* sim, void* pc) mozilla::DebugOnly lastStackAddress = nullptr; StackChars stack; uint32_t frameNo = 0; + AutoEnterOOMUnsafeRegion oomUnsafe; for (JS::ProfilingFrameIterator i(rt, state); !i.done(); ++i) { MOZ_ASSERT(i.stackAddress() != nullptr); MOZ_ASSERT(lastStackAddress <= i.stackAddress()); @@ -4411,9 +4412,12 @@ SingleStepCallback(void* arg, jit::Simulator* sim, void* pc) JS::ProfilingFrameIterator::Frame frames[16]; uint32_t nframes = i.extractStack(frames, 0, 16); for (uint32_t i = 0; i < nframes; i++) { - if (frameNo > 0) - stack.append(",", 1); - stack.append(frames[i].label, strlen(frames[i].label)); + if (frameNo > 0) { + if (!stack.append(",", 1)) + oomUnsafe.crash("stack.append"); + } + if (!stack.append(frames[i].label, strlen(frames[i].label))) + oomUnsafe.crash("stack.append"); frameNo++; } } @@ -4423,7 +4427,8 @@ SingleStepCallback(void* arg, jit::Simulator* sim, void* pc) stacks.back().length() != stack.length() || !PodEqual(stacks.back().begin(), stack.begin(), stack.length())) { - stacks.append(Move(stack)); + if (!stacks.append(Move(stack))) + oomUnsafe.crash("stacks.append"); } } #endif From bc82ddd21565505f23c9e13273a0c4b1db97e378 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 23 Feb 2016 23:45:50 +0900 Subject: [PATCH 023/252] Bug 1249895 - Replace unsigned __int128_t with __uint128_t. r=hev --- js/src/jit/mips64/Simulator-mips64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/mips64/Simulator-mips64.cpp b/js/src/jit/mips64/Simulator-mips64.cpp index 6f2585ef614..59fc5faf081 100644 --- a/js/src/jit/mips64/Simulator-mips64.cpp +++ b/js/src/jit/mips64/Simulator-mips64.cpp @@ -47,7 +47,7 @@ #define I64(v) static_cast(v) #define U64(v) static_cast(v) #define I128(v) static_cast<__int128_t>(v) -#define U128(v) static_cast(v) +#define U128(v) static_cast<__uint128_t>(v) namespace js { namespace jit { From 68175f13d13156103bdd8bfdda486e42b2b8e7af Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Fri, 19 Feb 2016 11:56:00 +0100 Subject: [PATCH 024/252] Bug 1050613 - Make sure force-valid for HTTP cache entries is removed when entries are removed, r=michal --- netwerk/cache2/CacheEntry.cpp | 33 +++++++-- netwerk/cache2/CacheEntry.h | 3 + netwerk/cache2/CacheStorage.cpp | 2 - netwerk/cache2/CacheStorageService.cpp | 99 +++++++++++++++++++------- netwerk/cache2/CacheStorageService.h | 24 +++++-- 5 files changed, 122 insertions(+), 39 deletions(-) diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 55f0371151f..16de01ae9eb 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -545,7 +545,6 @@ already_AddRefed CacheEntry::ReopenTruncated(bool aMemoryOnly, mUseDisk && !aMemoryOnly, mSkipSizeCheck, mPinned, - true, // always create true, // truncate existing (this one) getter_AddRefs(handle)); @@ -1072,13 +1071,12 @@ NS_IMETHODIMP CacheEntry::GetIsForcedValid(bool *aIsForcedValid) } nsAutoCString key; - - nsresult rv = HashingKeyWithStorage(key); + nsresult rv = HashingKey(key); if (NS_FAILED(rv)) { return rv; } - *aIsForcedValid = CacheStorageService::Self()->IsForcedValidEntry(key); + *aIsForcedValid = CacheStorageService::Self()->IsForcedValidEntry(mStorageID, key); LOG(("CacheEntry::GetIsForcedValid [this=%p, IsForcedValid=%d]", this, *aIsForcedValid)); return NS_OK; @@ -1089,12 +1087,12 @@ NS_IMETHODIMP CacheEntry::ForceValidFor(uint32_t aSecondsToTheFuture) LOG(("CacheEntry::ForceValidFor [this=%p, aSecondsToTheFuture=%d]", this, aSecondsToTheFuture)); nsAutoCString key; - nsresult rv = HashingKeyWithStorage(key); + nsresult rv = HashingKey(key); if (NS_FAILED(rv)) { return rv; } - CacheStorageService::Self()->ForceEntryValidFor(key, aSecondsToTheFuture); + CacheStorageService::Self()->ForceEntryValidFor(mStorageID, key, aSecondsToTheFuture); return NS_OK; } @@ -1325,6 +1323,8 @@ NS_IMETHODIMP CacheEntry::AsyncDoom(nsICacheEntryDoomCallback *aCallback) if (mIsDoomed || mDoomCallback) return NS_ERROR_IN_PROGRESS; // to aggregate have DOOMING state + RemoveForcedValidity(); + mIsDoomed = true; mDoomCallback = aCallback; } @@ -1623,6 +1623,8 @@ void CacheEntry::DoomAlreadyRemoved() mozilla::MutexAutoLock lock(mLock); + RemoveForcedValidity(); + mIsDoomed = true; // Pretend pinning is know. This entry is now doomed for good, so don't @@ -1666,6 +1668,25 @@ void CacheEntry::DoomFile() OnFileDoomed(rv); } +void CacheEntry::RemoveForcedValidity() +{ + mLock.AssertCurrentThreadOwns(); + + nsresult rv; + + if (mIsDoomed) { + return; + } + + nsAutoCString entryKey; + rv = HashingKey(entryKey); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + CacheStorageService::Self()->RemoveEntryForceValid(mStorageID, entryKey); +} + void CacheEntry::BackgroundOp(uint32_t aOperations, bool aForceAsync) { mLock.AssertCurrentThreadOwns(); diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index 32aa5115e07..1aeed08117c 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -266,6 +266,9 @@ private: // Called only from DoomAlreadyRemoved() void DoomFile(); + // When this entry is doomed the first time, this method removes + // any force-valid timing info for this entry. + void RemoveForcedValidity(); already_AddRefed ReopenTruncated(bool aMemoryOnly, nsICacheEntryOpenCallback* aCallback); diff --git a/netwerk/cache2/CacheStorage.cpp b/netwerk/cache2/CacheStorage.cpp index 5630071cce9..d3fd4ca2369 100644 --- a/netwerk/cache2/CacheStorage.cpp +++ b/netwerk/cache2/CacheStorage.cpp @@ -104,7 +104,6 @@ NS_IMETHODIMP CacheStorage::AsyncOpenURI(nsIURI *aURI, RefPtr entry; rv = CacheStorageService::Self()->AddStorageEntry( this, noRefURI, aIdExtension, - true, // create always truncate, // replace any existing one? getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); @@ -131,7 +130,6 @@ NS_IMETHODIMP CacheStorage::OpenTruncate(nsIURI *aURI, const nsACString & aIdExt RefPtr handle; rv = CacheStorageService::Self()->AddStorageEntry( this, noRefURI, aIdExtension, - true, // create always true, // replace any existing one getter_AddRefs(handle)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index 22cce5cff8e..34e7ee41037 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -769,6 +769,11 @@ NS_IMETHODIMP CacheStorageService::Clear() { mozilla::MutexAutoLock lock(mLock); + { + mozilla::MutexAutoLock forcedValidEntriesLock(mForcedValidEntriesLock); + mForcedValidEntries.Clear(); + } + NS_ENSURE_TRUE(!mShutdown, NS_ERROR_NOT_INITIALIZED); nsTArray keys; @@ -1021,7 +1026,7 @@ CacheStorageService::RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced) return false; } - if (!aEntry->IsUsingDisk() && IsForcedValidEntry(entryKey)) { + if (!aEntry->IsUsingDisk() && IsForcedValidEntry(aEntry->GetStorageID(), entryKey)) { LOG((" forced valid, not removing")); return false; } @@ -1094,13 +1099,19 @@ CacheStorageService::RecordMemoryOnlyEntry(CacheEntry* aEntry, // Checks if a cache entry is forced valid (will be loaded directly from cache // without further validation) - see nsICacheEntry.idl for further details -bool CacheStorageService::IsForcedValidEntry(nsACString &aCacheEntryKey) +bool CacheStorageService::IsForcedValidEntry(nsACString const &aContextKey, + nsACString const &aEntryKey) +{ + return IsForcedValidEntry(aContextKey + aEntryKey); +} + +bool CacheStorageService::IsForcedValidEntry(nsACString const &aContextEntryKey) { mozilla::MutexAutoLock lock(mForcedValidEntriesLock); TimeStamp validUntil; - if (!mForcedValidEntries.Get(aCacheEntryKey, &validUntil)) { + if (!mForcedValidEntries.Get(aContextEntryKey, &validUntil)) { return false; } @@ -1114,13 +1125,14 @@ bool CacheStorageService::IsForcedValidEntry(nsACString &aCacheEntryKey) } // Entry timeout has been reached - mForcedValidEntries.Remove(aCacheEntryKey); + mForcedValidEntries.Remove(aContextEntryKey); return false; } // Allows a cache entry to be loaded directly from cache without further // validation - see nsICacheEntry.idl for further details -void CacheStorageService::ForceEntryValidFor(nsACString &aCacheEntryKey, +void CacheStorageService::ForceEntryValidFor(nsACString const &aContextKey, + nsACString const &aEntryKey, uint32_t aSecondsToTheFuture) { mozilla::MutexAutoLock lock(mForcedValidEntriesLock); @@ -1131,7 +1143,15 @@ void CacheStorageService::ForceEntryValidFor(nsACString &aCacheEntryKey, // This will be the timeout TimeStamp validUntil = now + TimeDuration::FromSeconds(aSecondsToTheFuture); - mForcedValidEntries.Put(aCacheEntryKey, validUntil); + mForcedValidEntries.Put(aContextKey + aEntryKey, validUntil); +} + +void CacheStorageService::RemoveEntryForceValid(nsACString const &aContextKey, + nsACString const &aEntryKey) +{ + mozilla::MutexAutoLock lock(mForcedValidEntriesLock); + + mForcedValidEntries.Remove(aContextKey + aEntryKey); } // Cleans out the old entries in mForcedValidEntries @@ -1378,7 +1398,6 @@ nsresult CacheStorageService::AddStorageEntry(CacheStorage const* aStorage, nsIURI* aURI, const nsACString & aIdExtension, - bool aCreateIfNotExist, bool aReplace, CacheEntryHandle** aResult) { @@ -1393,7 +1412,7 @@ CacheStorageService::AddStorageEntry(CacheStorage const* aStorage, aStorage->WriteToDisk(), aStorage->SkipSizeCheck(), aStorage->Pinning(), - aCreateIfNotExist, aReplace, + aReplace, aResult); } @@ -1404,7 +1423,6 @@ CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey, bool aWriteToDisk, bool aSkipSizeCheck, bool aPin, - bool aCreateIfNotExist, bool aReplace, CacheEntryHandle** aResult) { @@ -1440,7 +1458,7 @@ CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey, if (entryExists && !aReplace) { // check whether we want to turn this entry to a memory-only. if (MOZ_UNLIKELY(!aWriteToDisk) && MOZ_LIKELY(entry->IsUsingDisk())) { - LOG((" entry is persistnet but we want mem-only, replacing it")); + LOG((" entry is persistent but we want mem-only, replacing it")); aReplace = true; } } @@ -1457,10 +1475,20 @@ CacheStorageService::AddStorageEntry(nsCSubstring const& aContextKey, entry = nullptr; entryExists = false; + + // Would only lead to deleting force-valid timestamp again. We don't need the + // replace information anymore after this point anyway. + aReplace = false; } - // Ensure entry for the particular URL, if not read/only - if (!entryExists && (aCreateIfNotExist || aReplace)) { + // Ensure entry for the particular URL + if (!entryExists) { + // When replacing with a new entry, always remove the current force-valid timestamp, + // this is the only place to do it. + if (aReplace) { + RemoveEntryForceValid(aContextKey, entryKey); + } + // Entry is not in the hashtable or has just been truncated... entry = new CacheEntry(aContextKey, aURI, aIdExtension, aWriteToDisk, aSkipSizeCheck, aPin); entries->Put(entryKey, entry); @@ -1639,6 +1667,10 @@ CacheStorageService::DoomStorageEntry(CacheStorage const* aStorage, } } } + + if (!entry) { + RemoveEntryForceValid(contextKey, entryKey); + } } if (entry) { @@ -1764,6 +1796,21 @@ CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, } } + { + mozilla::MutexAutoLock lock(mForcedValidEntriesLock); + + for (auto iter = mForcedValidEntries.Iter(); !iter.Done(); iter.Next()) { + bool matches; + DebugOnly rv = CacheFileUtils::KeyMatchesLoadContextInfo( + iter.Key(), aContext, &matches); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + if (matches) { + iter.Remove(); + } + } + } + // An artificial callback. This is a candidate for removal tho. In the new // cache any 'doom' or 'evict' function ensures that the entry or entries // being doomed is/are not accessible after the function returns. So there is @@ -1824,24 +1871,28 @@ CacheStorageService::CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo, mozilla::MutexAutoLock lock(mLock); - if (mShutdown) + if (mShutdown) { return; + } CacheEntryTable* entries; - if (!sGlobalEntryTables->Get(contextKey, &entries)) - return; - RefPtr entry; - if (!entries->Get(entryKey, getter_AddRefs(entry))) - return; - if (!entry->IsFileDoomed()) - return; + if (sGlobalEntryTables->Get(contextKey, &entries) && + entries->Get(entryKey, getter_AddRefs(entry))) { + if (entry->IsFileDoomed()) { + // Need to remove under the lock to avoid possible race leading + // to duplication of the entry per its key. + RemoveExactEntry(entries, entryKey, entry, false); + entry->DoomAlreadyRemoved(); + } - // Need to remove under the lock to avoid possible race leading - // to duplication of the entry per its key. - RemoveExactEntry(entries, entryKey, entry, false); - entry->DoomAlreadyRemoved(); + // Entry found, but it's not the entry that has been found doomed + // by the lower eviction layer. Just leave everything unchanged. + return; + } + + RemoveEntryForceValid(contextKey, entryKey); } bool diff --git a/netwerk/cache2/CacheStorageService.h b/netwerk/cache2/CacheStorageService.h index 7da8297067e..921d081b6a9 100644 --- a/netwerk/cache2/CacheStorageService.h +++ b/netwerk/cache2/CacheStorageService.h @@ -158,23 +158,35 @@ private: * directly from cache) for the given number of seconds * See nsICacheEntry.idl for more details */ - void ForceEntryValidFor(nsACString &aCacheEntryKey, + void ForceEntryValidFor(nsACString const &aContextKey, + nsACString const &aEntryKey, uint32_t aSecondsToTheFuture); + /** + * Remove the validity info + */ + void RemoveEntryForceValid(nsACString const &aContextKey, + nsACString const &aEntryKey); + + /** + * Retrieves the status of the cache entry to see if it has been forced valid + * (so it will loaded directly from cache without further validation) + */ + bool IsForcedValidEntry(nsACString const &aContextKey, + nsACString const &aEntryKey); + private: friend class CacheIndex; /** - * Retrieves the status of the cache entry to see if it has been forced valid - * (so it will loaded directly from cache without further validation) * CacheIndex uses this to prevent a cache entry from being prememptively * thrown away when forced valid * See nsICacheEntry.idl for more details */ - bool IsForcedValidEntry(nsACString &aCacheEntryKey); + bool IsForcedValidEntry(nsACString const &aEntryKeyWithContext); private: - // These are helpers for telemetry monitorying of the memory pools. + // These are helpers for telemetry monitoring of the memory pools. void TelemetryPrune(TimeStamp &now); void TelemetryRecordEntryCreation(CacheEntry const* entry); void TelemetryRecordEntryRemoval(CacheEntry const* entry); @@ -190,7 +202,6 @@ private: nsresult AddStorageEntry(CacheStorage const* aStorage, nsIURI* aURI, const nsACString & aIdExtension, - bool aCreateIfNotExist, bool aReplace, CacheEntryHandle** aResult); @@ -286,7 +297,6 @@ private: bool aWriteToDisk, bool aSkipSizeCheck, bool aPin, - bool aCreateIfNotExist, bool aReplace, CacheEntryHandle** aResult); From 3d78cfb1a74d3f0ad224d13f22aa34240df6edaa Mon Sep 17 00:00:00 2001 From: Jeremy Chen Date: Mon, 22 Feb 2016 04:19:00 +0100 Subject: [PATCH 025/252] Bug 1239564 - Post translate maskSurface to renderTarget. r=roc --- gfx/layers/basic/BasicCompositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 241dfb4e143..9c7c9585141 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -434,7 +434,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect, MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!"); MOZ_ASSERT(!effectMask->mIs3D); maskTransform = effectMask->mMaskTransform.As2D(); - maskTransform.PreTranslate(-offset.x, -offset.y); + maskTransform.PostTranslate(-offset.x, -offset.y); } CompositionOp blendMode = CompositionOp::OP_OVER; From af708c163c9e8bd1dc9c104496da38df63798d30 Mon Sep 17 00:00:00 2001 From: Jeremy Chen Date: Mon, 22 Feb 2016 04:21:00 +0100 Subject: [PATCH 026/252] Bug 1239564 - Add reftest for mask layer composition. r=roc --- layout/reftests/bugs/1239564-ref.html | 21 +++++++++++++++++++ layout/reftests/bugs/1239564.html | 29 +++++++++++++++++++++++++++ layout/reftests/bugs/reftest.list | 1 + 3 files changed, 51 insertions(+) create mode 100644 layout/reftests/bugs/1239564-ref.html create mode 100644 layout/reftests/bugs/1239564.html diff --git a/layout/reftests/bugs/1239564-ref.html b/layout/reftests/bugs/1239564-ref.html new file mode 100644 index 00000000000..5b5dbcd066a --- /dev/null +++ b/layout/reftests/bugs/1239564-ref.html @@ -0,0 +1,21 @@ + + +Testcase for bug 1239564 + + +
+ \ No newline at end of file diff --git a/layout/reftests/bugs/1239564.html b/layout/reftests/bugs/1239564.html new file mode 100644 index 00000000000..2acf80f3e92 --- /dev/null +++ b/layout/reftests/bugs/1239564.html @@ -0,0 +1,29 @@ + + +Testcase for bug 1239564 + + +
+ + \ No newline at end of file diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 13e075312cd..ee85d432716 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1944,3 +1944,4 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html == 1222226-1.html 1222226-1-ref.html pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html == 1230466.html about:blank +fuzzy(100,2000) == 1239564.html 1239564-ref.html From ef1a6ec42a2ff4eb62b2284218e1c863ed40aa1d Mon Sep 17 00:00:00 2001 From: Andi-Bogdan Postelnicu Date: Mon, 14 Dec 2015 00:00:00 +0100 Subject: [PATCH 027/252] Bug 1230911 - modified asseert in order to prevent null pointer dereference. r=roc --- gfx/layers/client/TextureClient.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index c866e35ad83..b9df7574f9f 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -820,7 +820,8 @@ TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator, TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) { - MOZ_ASSERT(aAllocator->IPCOpen()); + // also test the validity of aAllocator + MOZ_ASSERT(aAllocator && aAllocator->IPCOpen()); if (!aAllocator || !aAllocator->IPCOpen()) { return nullptr; } From 92a86dab62305930f7a9cea4700a292fae7776a5 Mon Sep 17 00:00:00 2001 From: Bruce Sun Date: Mon, 22 Feb 2016 11:41:07 +0800 Subject: [PATCH 028/252] Bug 1222956: Use |BluetoothUuid| in |BluetoothDiscoveryHandle|, r=tzimmermann --- dom/bluetooth/common/BluetoothCommon.cpp | 23 ++++ dom/bluetooth/common/BluetoothCommon.h | 34 +++--- dom/bluetooth/common/BluetoothUtils.cpp | 80 ++++++++++++++ dom/bluetooth/common/BluetoothUtils.h | 54 ++++++++++ .../common/webapi/BluetoothAdapter.cpp | 45 ++++---- .../common/webapi/BluetoothAdapter.h | 2 +- .../common/webapi/BluetoothDevice.cpp | 100 ++++++++---------- dom/bluetooth/common/webapi/BluetoothDevice.h | 12 ++- .../webapi/BluetoothDiscoveryHandle.cpp | 10 +- .../common/webapi/BluetoothDiscoveryHandle.h | 16 +-- 10 files changed, 254 insertions(+), 122 deletions(-) diff --git a/dom/bluetooth/common/BluetoothCommon.cpp b/dom/bluetooth/common/BluetoothCommon.cpp index 28161db8dea..b9f89a38d4f 100644 --- a/dom/bluetooth/common/BluetoothCommon.cpp +++ b/dom/bluetooth/common/BluetoothCommon.cpp @@ -25,4 +25,27 @@ const BluetoothAddress BluetoothAddress::ALL(0xff, 0xff, 0xff, const BluetoothAddress BluetoothAddress::LOCAL(0x00, 0x00, 0x00, 0xff, 0xff, 0xff); +// +// |BluetoothUuid| +// + +const BluetoothUuid BluetoothUuid::ZERO(0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + +/* + * [Bluetooth Specification Version 4.2, Volume 3, Part B, Section 2.5.1] + * + * To reduce the burden of storing and transferring 128-bit UUID values, a + * range of UUID values has been pre-allocated for assignment to often-used, + * registered purposes. The first UUID in this pre-allocated range is known as + * the Bluetooth Base UUID and has the value 00000000-0000-1000-8000- + * 00805F9B34FB, from the Bluetooth Assigned Numbers document. + */ +const BluetoothUuid BluetoothUuid::BASE(0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, + 0x5f, 0x9b, 0x34, 0xfb); + END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/common/BluetoothCommon.h b/dom/bluetooth/common/BluetoothCommon.h index 823657ab658..a38d52ca991 100644 --- a/dom/bluetooth/common/BluetoothCommon.h +++ b/dom/bluetooth/common/BluetoothCommon.h @@ -550,11 +550,13 @@ enum BluetoothServiceClass { }; struct BluetoothUuid { + static const BluetoothUuid ZERO; + static const BluetoothUuid BASE; - uint8_t mUuid[16]; + uint8_t mUuid[16]; // store 128-bit UUID value in big-endian order BluetoothUuid() - : BluetoothUuid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + : BluetoothUuid(ZERO) { } MOZ_IMPLICIT BluetoothUuid(const BluetoothUuid&) = default; @@ -608,7 +610,7 @@ struct BluetoothUuid { */ void Clear() { - operator=(BluetoothUuid()); + operator=(ZERO); } /** @@ -617,7 +619,7 @@ struct BluetoothUuid { */ bool IsCleared() const { - return operator==(BluetoothUuid()); + return operator==(ZERO); } bool operator==(const BluetoothUuid& aRhs) const @@ -631,30 +633,25 @@ struct BluetoothUuid { return !operator==(aRhs); } + /* This less-than operator is used for sorted insertion of nsTArray */ + bool operator<(const BluetoothUuid& aUuid) const + { + return memcmp(mUuid, aUuid.mUuid, sizeof(aUuid.mUuid)) < 0; + }; + /* * Getter-setter methods for short UUIDS. The first 4 bytes in the * UUID are represented by the short notation UUID32, and bytes 3 * and 4 (indices 2 and 3) are represented by UUID16. The rest of - * the UUID is filled with the SDP base UUID. + * the UUID is filled with the Bluetooth Base UUID. * * Below are helpers for accessing these values. */ void SetUuid32(uint32_t aUuid32) { + operator=(BASE); BigEndian::writeUint32(&mUuid[0], aUuid32); - mUuid[4] = 0x00; - mUuid[5] = 0x00; - mUuid[6] = 0x10; - mUuid[7] = 0x00; - mUuid[8] = 0x80; - mUuid[9] = 0x00; - mUuid[10] = 0x00; - mUuid[11] = 0x80; - mUuid[12] = 0x5f; - mUuid[13] = 0x9b; - mUuid[14] = 0x34; - mUuid[15] = 0xfb; } uint32_t GetUuid32() const @@ -664,7 +661,8 @@ struct BluetoothUuid { void SetUuid16(uint16_t aUuid16) { - SetUuid32(aUuid16); // MSB is 0x0000 + operator=(BASE); + BigEndian::writeUint16(&mUuid[2], aUuid16); } uint16_t GetUuid16() const diff --git a/dom/bluetooth/common/BluetoothUtils.cpp b/dom/bluetooth/common/BluetoothUtils.cpp index 2bb796d9a93..138afd4b0e2 100644 --- a/dom/bluetooth/common/BluetoothUtils.cpp +++ b/dom/bluetooth/common/BluetoothUtils.cpp @@ -277,6 +277,86 @@ StringToUuid(const nsAString& aString, BluetoothUuid& aUuid) return NS_OK; } +nsresult +BytesToUuid(const nsTArray& aArray, + nsTArray::index_type aOffset, + BluetoothUuidType aType, + BluetoothProfileEndian aEndian, + BluetoothUuid& aUuid) +{ + MOZ_ASSERT(aType == UUID_16_BIT || + aType == UUID_32_BIT || + aType == UUID_128_BIT); + MOZ_ASSERT(aEndian == ENDIAN_BIG || aEndian == ENDIAN_LITTLE); + + size_t index = (aType == UUID_16_BIT) ? 2 : 0; + size_t length = 0; + + if (aType == UUID_16_BIT) { + length = sizeof(uint16_t); + } else if (aType == UUID_32_BIT) { + length = sizeof(uint32_t); + } else { + length = MOZ_ARRAY_LENGTH(aUuid.mUuid); + } + + if (aArray.Length() < aOffset + length) { + return NS_ERROR_ILLEGAL_VALUE; + } + + aUuid = BluetoothUuid::BASE; + + if (aEndian == ENDIAN_BIG) { + for (size_t i = 0; i < length; ++i) { + aUuid.mUuid[index + i] = aArray[aOffset + i]; + } + } else { + for (size_t i = 0; i < length; ++i) { + aUuid.mUuid[index + i] = aArray[aOffset + length - i - 1]; + } + } + + return NS_OK; +} + +nsresult +UuidToBytes(const BluetoothUuid& aUuid, + BluetoothUuidType aType, + BluetoothProfileEndian aEndian, + nsTArray& aArray, + nsTArray::index_type aOffset) +{ + MOZ_ASSERT(aType == UUID_16_BIT || + aType == UUID_32_BIT || + aType == UUID_128_BIT); + MOZ_ASSERT(aEndian == ENDIAN_BIG || aEndian == ENDIAN_LITTLE); + + size_t index = (aType == UUID_16_BIT) ? 2 : 0; + size_t length = 0; + + if (aType == UUID_16_BIT) { + length = sizeof(uint16_t); + } else if (aType == UUID_32_BIT) { + length = sizeof(uint32_t); + } else { + length = MOZ_ARRAY_LENGTH(aUuid.mUuid); + } + + aArray.SetCapacity(aOffset + length); + + if (aEndian == ENDIAN_BIG) { + for (size_t i = 0; i < length; ++i) { + aArray[aOffset + i] = aUuid.mUuid[index + i]; + } + } else { + for (size_t i = 0; i < length; ++i) { + aArray[aOffset + length - i - 1] = aUuid.mUuid[index + i]; + } + } + + return NS_OK; +} + nsresult GenerateUuid(BluetoothUuid &aUuid) { diff --git a/dom/bluetooth/common/BluetoothUtils.h b/dom/bluetooth/common/BluetoothUtils.h index b9b0dc0ff37..3444ee1bf26 100644 --- a/dom/bluetooth/common/BluetoothUtils.h +++ b/dom/bluetooth/common/BluetoothUtils.h @@ -24,6 +24,30 @@ class BluetoothNamedValue; class BluetoothReplyRunnable; class BluetoothValue; +/* + * Each profile has its distinct endianness for multi-byte values + */ +enum BluetoothProfileEndian { + ENDIAN_BIG, + ENDIAN_LITTLE, + ENDIAN_SDP = ENDIAN_BIG, // SDP uses big endian + ENDIAN_GAP = ENDIAN_LITTLE, // GAP uses little endian + ENDIAN_GATT = ENDIAN_LITTLE, // GATT uses little endian +}; + +/* + * A UUID is a 128-bit value. To reduce the burden of storing and transferring + * 128-bit UUID values, a range of UUID values has been pre-allocated for + * assignment to often-used, registered purposes. UUID values in the + * pre-allocated range have aliases that are represented as 16-bit or 32-bit + * values. + */ +enum BluetoothUuidType { + UUID_16_BIT, + UUID_32_BIT, + UUID_128_BIT, +}; + // // Address/String conversion // @@ -104,6 +128,36 @@ UuidToString(const BluetoothUuid& aUuid, nsAString& aString); nsresult StringToUuid(const nsAString& aString, BluetoothUuid& aUuid); +/** + * Convert continuous bytes from nsTArray to BluetoothUuid object. + * @param aArray [in] The byte array. + * @param aOffset [in] The offset of continuous bytes of UUID value. + * @param aType [in] The type of UUID. + * @param aEndian [in] The endianness of UUID value. + * @param aUuid [out] The BluetoothUuid object. + */ +nsresult +BytesToUuid(const nsTArray& aArray, + nsTArray::index_type aOffset, + BluetoothUuidType aType, + BluetoothProfileEndian aEndian, + BluetoothUuid& aUuid); + +/** + * Convert BluetoothUuid object to nsTArray with continuous bytes. + * @param aUuid [in] The BluetoothUuid object. + * @param aType [in] The type of UUID. + * @param aEndian [in] The endianness of UUID value. + * @param aArray [out] The byte array. + * @param aOffset [in] The offset of continuous bytes of UUID value. + */ +nsresult +UuidToBytes(const BluetoothUuid& aUuid, + BluetoothUuidType aType, + BluetoothProfileEndian aEndian, + nsTArray& aArray, + nsTArray::index_type aOffset); + /** * Generate a random uuid. * diff --git a/dom/bluetooth/common/webapi/BluetoothAdapter.cpp b/dom/bluetooth/common/webapi/BluetoothAdapter.cpp index 091259333d3..7e3660eea3b 100644 --- a/dom/bluetooth/common/webapi/BluetoothAdapter.cpp +++ b/dom/bluetooth/common/webapi/BluetoothAdapter.cpp @@ -131,7 +131,7 @@ class StartLeScanTask final : public BluetoothReplyRunnable { public: StartLeScanTask(BluetoothAdapter* aAdapter, Promise* aPromise, - const nsTArray& aServiceUuids) + const nsTArray& aServiceUuids) : BluetoothReplyRunnable(nullptr, aPromise) , mAdapter(aAdapter) , mServiceUuids(aServiceUuids) @@ -150,7 +150,7 @@ public: JSContext* cx = jsapi.cx(); const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); - NS_ENSURE_TRUE(v.type() == BluetoothValue::TnsString, false); + NS_ENSURE_TRUE(v.type() == BluetoothValue::TBluetoothUuid, false); /** * Create a new discovery handle and wrap it to return. Each @@ -158,7 +158,7 @@ public: */ RefPtr discoveryHandle = BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject(), - mServiceUuids, v.get_nsString()); + mServiceUuids, v.get_BluetoothUuid()); if (!ToJSValue(cx, discoveryHandle, aValue)) { JS_ClearPendingException(cx); @@ -180,7 +180,7 @@ public: private: RefPtr mAdapter; - nsTArray mServiceUuids; + nsTArray mServiceUuids; }; class StopLeScanTask final : public BluetoothReplyRunnable @@ -188,14 +188,14 @@ class StopLeScanTask final : public BluetoothReplyRunnable public: StopLeScanTask(BluetoothAdapter* aAdapter, Promise* aPromise, - const nsAString& aScanUuid) + const BluetoothUuid& aScanUuid) : BluetoothReplyRunnable(nullptr, aPromise) , mAdapter(aAdapter) , mScanUuid(aScanUuid) { MOZ_ASSERT(aPromise); MOZ_ASSERT(aAdapter); - MOZ_ASSERT(!aScanUuid.IsEmpty()); + MOZ_ASSERT(!aScanUuid.IsCleared()); } protected: @@ -216,7 +216,7 @@ protected: private: RefPtr mAdapter; - nsString mScanUuid; + BluetoothUuid mScanUuid; }; class GetDevicesTask : public BluetoothReplyRunnable @@ -366,16 +366,12 @@ BluetoothAdapter::Cleanup() BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE_VOID(bs); - nsString uuidStr; - for (uint32_t i = 0; i < mLeScanHandleArray.Length(); ++i) { - mLeScanHandleArray[i]->GetLeScanUuid(uuidStr); + for (size_t i = 0; i < mLeScanHandleArray.Length(); ++i) { + BluetoothUuid uuid; + mLeScanHandleArray[i]->GetLeScanUuid(uuid); RefPtr results = new BluetoothVoidReplyRunnable(nullptr); - - BluetoothUuid uuid; - if (NS_SUCCEEDED(StringToUuid(uuidStr, uuid))) { - bs->StopLeScanInternal(uuid, results); - } + bs->StopLeScanInternal(uuid, results); } mLeScanHandleArray.Clear(); } @@ -606,12 +602,12 @@ BluetoothAdapter::AppendLeScanHandle( } void -BluetoothAdapter::RemoveLeScanHandle(const nsAString& aScanUuid) +BluetoothAdapter::RemoveLeScanHandle(const BluetoothUuid& aScanUuid) { - nsString uuid; - for (uint32_t i = 0; i < mLeScanHandleArray.Length(); ++i) { + for (size_t i = 0; i < mLeScanHandleArray.Length(); ++i) { + BluetoothUuid uuid; mLeScanHandleArray[i]->GetLeScanUuid(uuid); - if (aScanUuid.Equals(uuid)) { + if (aScanUuid == uuid) { mLeScanHandleArray.RemoveElementAt(i); break; } @@ -718,7 +714,7 @@ BluetoothAdapter::StartLeScan(const nsTArray& aServiceUuids, BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE); RefPtr result = - new StartLeScanTask(this, promise, aServiceUuids); + new StartLeScanTask(this, promise, serviceUuids); bs->StartLeScanInternal(serviceUuids, result); return promise.forget(); @@ -749,16 +745,11 @@ BluetoothAdapter::StopLeScan(BluetoothDiscoveryHandle& aDiscoveryHandle, promise, NS_ERROR_DOM_BLUETOOTH_DONE); - nsString scanUuidStr; - aDiscoveryHandle.GetLeScanUuid(scanUuidStr); - BluetoothUuid scanUuid; - BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(StringToUuid(scanUuidStr, scanUuid)), - promise, - NS_ERROR_DOM_OPERATION_ERR); + aDiscoveryHandle.GetLeScanUuid(scanUuid); RefPtr result = - new StopLeScanTask(this, promise, scanUuidStr); + new StopLeScanTask(this, promise, scanUuid); bs->StopLeScanInternal(scanUuid, result); return promise.forget(); diff --git a/dom/bluetooth/common/webapi/BluetoothAdapter.h b/dom/bluetooth/common/webapi/BluetoothAdapter.h index b0a93a0dfbf..0272005c257 100644 --- a/dom/bluetooth/common/webapi/BluetoothAdapter.h +++ b/dom/bluetooth/common/webapi/BluetoothAdapter.h @@ -220,7 +220,7 @@ public: * * @param aScanUuid [in] The UUID of the LE scan task. */ - void RemoveLeScanHandle(const nsAString& aScanUuid); + void RemoveLeScanHandle(const BluetoothUuid& aScanUuid); private: BluetoothAdapter(nsPIDOMWindowInner* aOwner, const BluetoothValue& aValue); diff --git a/dom/bluetooth/common/webapi/BluetoothDevice.cpp b/dom/bluetooth/common/webapi/BluetoothDevice.cpp index 820a50f638c..9d9846877fe 100644 --- a/dom/bluetooth/common/webapi/BluetoothDevice.cpp +++ b/dom/bluetooth/common/webapi/BluetoothDevice.cpp @@ -117,6 +117,17 @@ BluetoothDevice::~BluetoothDevice() UnregisterBluetoothSignalHandler(mAddress, this); } +void +BluetoothDevice::GetUuids(nsTArray& aUuids) const +{ + aUuids.Clear(); + for (size_t i = 0; i < mUuids.Length(); ++i) { + nsAutoString uuidStr; + UuidToString(mUuids[i], uuidStr); + aUuids.AppendElement(uuidStr); + } +} + void BluetoothDevice::DisconnectFromOwner() { @@ -158,19 +169,15 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue) } else if (name.EqualsLiteral("Paired")) { mPaired = value.get_bool(); } else if (name.EqualsLiteral("UUIDs")) { - // While converting to strings, we sort the received UUIDs and remove - // any duplicates. + // We sort the received UUIDs and remove any duplicates. const nsTArray& uuids = value.get_ArrayOfBluetoothUuid(); nsTArray uuidStrs; + mUuids.Clear(); for (uint32_t index = 0; index < uuids.Length(); ++index) { - nsAutoString uuidStr; - UuidToString(uuids[index], uuidStr); - - if (!uuidStrs.Contains(uuidStr)) { // filter out duplicate UUIDs - uuidStrs.InsertElementSorted(uuidStr); + if (!mUuids.Contains(uuids[index])) { // filter out duplicate UUIDs + mUuids.InsertElementSorted(uuids[index]); } } - mUuids = Move(uuidStrs); BluetoothDeviceBinding::ClearCachedUuidsValue(this); } else if (name.EqualsLiteral("Type")) { mType = ConvertUint32ToDeviceType(value.get_uint32_t()); @@ -275,23 +282,14 @@ BluetoothDevice::IsDeviceAttributeChanged(BluetoothDeviceAttribute aType, case BluetoothDeviceAttribute::Uuids: { MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothUuid); const auto& uuids = aValue.get_ArrayOfBluetoothUuid(); - - nsTArray uuidStrs; - - // Construct a sorted uuid set + nsTArray sortedUuids; + // Construct a sorted UUID set for (size_t index = 0; index < uuids.Length(); ++index) { - nsAutoString uuidStr; - UuidToString(uuids[index], uuidStr); - - if (!uuidStrs.Contains(uuidStr)) { // filter out duplicate uuids - uuidStrs.InsertElementSorted(uuidStr); + if (!sortedUuids.Contains(uuids[index])) { // filter out duplicate uuids + sortedUuids.InsertElementSorted(uuids[index]); } } - - // We assume the received uuids array is sorted without duplicate items. - // If it's not, we require additional processing before comparing it - // directly. - return mUuids != uuidStrs; + return mUuids != sortedUuids; } default: BT_WARNING("Type %d is not handled", uint32_t(aType)); @@ -386,7 +384,8 @@ BluetoothDevice::UpdatePropertiesFromAdvData(const nsTArray& aAdvData) } // Update UUIDs and name of BluetoothDevice. - int type = aAdvData[offset++]; + BluetoothGapDataType type = + static_cast(aAdvData[offset++]); switch (type) { case GAP_INCOMPLETE_UUID16: case GAP_COMPLETE_UUID16: @@ -396,48 +395,33 @@ BluetoothDevice::UpdatePropertiesFromAdvData(const nsTArray& aAdvData) case GAP_COMPLETE_UUID128: { mUuids.Clear(); - // The length of uint16_t UUID array - uint8_t len = 0; - if (GAP_INCOMPLETE_UUID16 && GAP_COMPLETE_UUID16) { - len = 1; - } else if (GAP_INCOMPLETE_UUID32 && GAP_COMPLETE_UUID32) { - len = 2; - } else { - len = 8; - } - uint16_t uuid[len]; - while (dataLength > 0) { - // Read (len * 2) bytes from the data buffer and compose a 16-bits - // UUID array. - for (uint8_t i = 0; i < len; ++i) { - uuid[i] = aAdvData[offset++]; - uuid[i] += (aAdvData[offset++] << 8); - dataLength -= 2; - } - - char uuidStr[37]; // one more char to be null-terminated + BluetoothUuid uuid; + size_t length = 0; if (type == GAP_INCOMPLETE_UUID16 || type == GAP_COMPLETE_UUID16) { - // Convert 16-bits UUID into string. - snprintf(uuidStr, sizeof(uuidStr), - "0000%04x-0000-1000-8000-00805f9b34fb", uuid[0]); + length = 2; + if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_16_BIT, + ENDIAN_GAP, uuid))) { + break; + } } else if (type == GAP_INCOMPLETE_UUID32 || type == GAP_COMPLETE_UUID32) { - // Convert 32-bits UUID into string. - snprintf(uuidStr, sizeof(uuidStr), - "%04x%04x-0000-1000-8000-00805f9b34fb", uuid[1], uuid[0]); + length = 4; + if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_32_BIT, + ENDIAN_GAP, uuid))) { + break; + } } else if (type == GAP_INCOMPLETE_UUID128 || type == GAP_COMPLETE_UUID128) { - // Convert 128-bits UUID into string. - snprintf(uuidStr, sizeof(uuidStr), - "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - uuid[7], uuid[6], uuid[5], uuid[4], - uuid[3], uuid[2], uuid[1], uuid[0]); + length = 16; + if (NS_FAILED(BytesToUuid(aAdvData, offset, UUID_128_BIT, + ENDIAN_GAP, uuid))) { + break; + } } - nsString uuidNsString; - uuidNsString.AssignLiteral(uuidStr); - - mUuids.AppendElement(uuidNsString); + mUuids.AppendElement(uuid); + offset += length; + dataLength -= length; } BluetoothDeviceBinding::ClearCachedUuidsValue(this); diff --git a/dom/bluetooth/common/webapi/BluetoothDevice.h b/dom/bluetooth/common/webapi/BluetoothDevice.h index fbf449f255b..5350ae872e3 100644 --- a/dom/bluetooth/common/webapi/BluetoothDevice.h +++ b/dom/bluetooth/common/webapi/BluetoothDevice.h @@ -59,10 +59,7 @@ public: return mPaired; } - void GetUuids(nsTArray& aUuids) const - { - aUuids = mUuids; - } + void GetUuids(nsTArray& aUuids) const; BluetoothDeviceType Type() const { @@ -97,6 +94,11 @@ public: JS::Handle aGivenProto) override; virtual void DisconnectFromOwner() override; + void GetUuids(nsTArray& aUuids) const + { + aUuids = mUuids; + } + private: BluetoothDevice(nsPIDOMWindowInner* aOwner, const BluetoothValue& aValue); ~BluetoothDevice(); @@ -188,7 +190,7 @@ private: /** * Cached UUID list of services which this device provides. */ - nsTArray mUuids; + nsTArray mUuids; /** * Type of this device. Can be unknown/classic/le/dual. diff --git a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp index fbfb2a47467..eea7ac1da3c 100644 --- a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp +++ b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.cpp @@ -29,8 +29,8 @@ BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow) BluetoothDiscoveryHandle::BluetoothDiscoveryHandle( nsPIDOMWindowInner* aWindow, - const nsTArray& aServiceUuids, - const nsAString& aLeScanUuid) + const nsTArray& aServiceUuids, + const BluetoothUuid& aLeScanUuid) : DOMEventTargetHelper(aWindow) , mLeScanUuid(aLeScanUuid) , mServiceUuids(aServiceUuids) @@ -57,8 +57,8 @@ BluetoothDiscoveryHandle::Create(nsPIDOMWindowInner* aWindow) already_AddRefed BluetoothDiscoveryHandle::Create( nsPIDOMWindowInner* aWindow, - const nsTArray& aServiceUuids, - const nsAString& aLeScanUuid) + const nsTArray& aServiceUuids, + const BluetoothUuid& aLeScanUuid) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aWindow); @@ -89,7 +89,7 @@ BluetoothDiscoveryHandle::DispatchLeDeviceEvent(BluetoothDevice* aLeDevice, { MOZ_ASSERT(aLeDevice); - nsTArray remoteUuids; + nsTArray remoteUuids; aLeDevice->GetUuids(remoteUuids); bool hasUuidsFilter = !mServiceUuids.IsEmpty(); diff --git a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h index 3b5c31c6157..e5866b00cd9 100644 --- a/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h +++ b/dom/bluetooth/common/webapi/BluetoothDiscoveryHandle.h @@ -28,8 +28,8 @@ public: static already_AddRefed Create(nsPIDOMWindowInner* aWindow, - const nsTArray& aServiceUuids, - const nsAString& aLeScanUuid); + const nsTArray& aServiceUuids, + const BluetoothUuid& aLeScanUuid); void DispatchDeviceEvent(BluetoothDevice* aDevice); @@ -39,7 +39,7 @@ public: IMPL_EVENT_HANDLER(devicefound); - void GetLeScanUuid(nsString& aLeScanUuid) const + void GetLeScanUuid(BluetoothUuid& aLeScanUuid) const { aLeScanUuid = mLeScanUuid; } @@ -51,8 +51,8 @@ private: BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow); BluetoothDiscoveryHandle(nsPIDOMWindowInner* aWindow, - const nsTArray& aServiceUuids, - const nsAString& aLeScanUuid); + const nsTArray& aServiceUuids, + const BluetoothUuid& aLeScanUuid); ~BluetoothDiscoveryHandle(); @@ -63,15 +63,15 @@ private: * If BluetoothDiscoveryHandle is built for classic discovery, the value would * remain empty string during the entire life cycle. */ - nsString mLeScanUuid; + BluetoothUuid mLeScanUuid; /** - * A DOMString array of service UUIDs to discover / scan for. + * A BluetoothUuid array of service UUIDs to discover / scan for. * * This array is only used by LE scan. If BluetoothDiscoveryHandle is built * for classic discovery, the array should be empty. */ - nsTArray mServiceUuids; + nsTArray mServiceUuids; }; END_BLUETOOTH_NAMESPACE From acec6acd17ab0133e9612bb747e5c178e1e66410 Mon Sep 17 00:00:00 2001 From: Mantaroh Yoshinaga Date: Sun, 31 Jan 2016 22:48:00 +0100 Subject: [PATCH 029/252] Bug 1174624 - Add the Transferable parameter into SendAsyncMessage of nsFrameMessageManager. r=baku --- dom/base/StructuredCloneHolder.cpp | 6 +--- dom/base/nsFrameMessageManager.cpp | 44 ++++++++++++++++++++++------ dom/base/nsFrameMessageManager.h | 2 ++ dom/base/nsIMessageManager.idl | 3 +- dom/ipc/DOMTypes.ipdlh | 9 ++++++ dom/ipc/StructuredCloneData.cpp | 11 ++++++- dom/ipc/StructuredCloneData.h | 7 ++++- dom/messagechannel/MessagePort.cpp | 24 ++++++++------- dom/messagechannel/MessagePort.h | 6 ++-- dom/messagechannel/PMessagePort.ipdl | 10 +------ 10 files changed, 82 insertions(+), 40 deletions(-) diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 149419522a3..3540a00adc9 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -1041,16 +1041,12 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx, MOZ_ASSERT(mSupportsTransferring); if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - // This can be null. - nsCOMPtr window = do_QueryInterface(mParent); - MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData]; - // aExtraData is the index of this port identifier. ErrorResult rv; RefPtr port = - MessagePort::Create(window, portIdentifier, rv); + MessagePort::Create(mParent, portIdentifier, rv); if (NS_WARN_IF(rv.Failed())) { return false; } diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index b047df3235d..347c45ed17b 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -33,6 +33,8 @@ #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/nsIContentParent.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessGlobal.h" @@ -274,6 +276,8 @@ BuildClonedMessageData(typename BlobTraits::ConcreteContentManagerType* SerializedStructuredCloneBuffer& buffer = aClonedData.data(); buffer.data = aData.Data(); buffer.dataLength = aData.DataLength(); + aClonedData.identfiers().AppendElements(aData.PortIdentifiers()); + const nsTArray>& blobImpls = aData.BlobImpls(); if (!blobImpls.IsEmpty()) { @@ -317,9 +321,12 @@ UnpackClonedMessageData(const ClonedMessageData& aClonedData, const SerializedStructuredCloneBuffer& buffer = aClonedData.data(); typedef typename BlobTraits::ProtocolType ProtocolType; const InfallibleTArray& blobs = DataBlobs::Blobs(aClonedData); + const InfallibleTArray& identifiers = aClonedData.identfiers(); aData.UseExternalData(buffer.data, buffer.dataLength); + aData.PortIdentifiers().AppendElements(identifiers); + if (!blobs.IsEmpty()) { uint32_t length = blobs.Length(); aData.BlobImpls().SetCapacity(length); @@ -616,12 +623,14 @@ JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData) static bool GetParamsForMessage(JSContext* aCx, const JS::Value& aValue, + const JS::Value& aTransfer, StructuredCloneData& aData) { // First try to use structured clone on the whole thing. JS::RootedValue v(aCx, aValue); + JS::RootedValue t(aCx, aTransfer); ErrorResult rv; - aData.Write(aCx, v, rv); + aData.Write(aCx, v, t, rv); if (!rv.Failed()) { return true; } @@ -716,7 +725,7 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName, } StructuredCloneData data; - if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) { + if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, JS::UndefinedHandleValue, data)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } @@ -791,11 +800,12 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, nsIPrincipal* aPrincipal, + const JS::Value& aTransfers, JSContext* aCx, uint8_t aArgc) { StructuredCloneData data; - if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) { + if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, aTransfers, data)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } @@ -808,7 +818,6 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName, aPrincipal); } - // nsIMessageSender NS_IMETHODIMP @@ -816,11 +825,12 @@ nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName, JS::Handle aJSON, JS::Handle aObjects, nsIPrincipal* aPrincipal, + JS::Handle aTransfers, JSContext* aCx, uint8_t aArgc) { - return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, - aArgc); + return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, + aTransfers, aCx, aArgc); } @@ -833,8 +843,8 @@ nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName, JSContext* aCx, uint8_t aArgc) { - return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, aCx, - aArgc); + return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, + JS::UndefinedHandleValue, aCx, aArgc); } NS_IMETHODIMP @@ -1141,6 +1151,20 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, return NS_OK; } } + + // Get cloned MessagePort from StructuredCloneData. + nsTArray> ports; + if (aCloneData) { + ports = aCloneData->TakeTransferredPorts(); + } + + JS::Rooted transferredList(cx); + RefPtr portList = new MessagePortList(aTargetFrameLoader, ports); + transferredList = portList->WrapObject(cx, nullptr); + if (NS_WARN_IF(!transferredList)) { + return NS_ERROR_UNEXPECTED; + } + JS::Rooted jsMessage(cx, JS_NewUCStringCopyN(cx, static_cast(aMessage.BeginReading()), @@ -1152,7 +1176,9 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, JS_DefineProperty(cx, param, "sync", syncv, JSPROP_ENUMERATE) && JS_DefineProperty(cx, param, "json", json, JSPROP_ENUMERATE) && // deprecated JS_DefineProperty(cx, param, "data", json, JSPROP_ENUMERATE) && - JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE); + JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE) && + JS_DefineProperty(cx, param, "ports", transferredList, JSPROP_ENUMERATE); + NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); if (aTargetFrameLoader) { diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index 5b4e659592b..46afed48771 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -215,8 +215,10 @@ public: const JS::Value& aJSON, const JS::Value& aObjects, nsIPrincipal* aPrincipal, + const JS::Value& aTransfers, JSContext* aCx, uint8_t aArgc); + nsresult DispatchAsyncMessageInternal(JSContext* aCx, const nsAString& aMessage, StructuredCloneData& aData, diff --git a/dom/base/nsIMessageManager.idl b/dom/base/nsIMessageManager.idl index 80ece66e460..c0f8e22e519 100644 --- a/dom/base/nsIMessageManager.idl +++ b/dom/base/nsIMessageManager.idl @@ -282,7 +282,8 @@ interface nsIMessageSender : nsIMessageListenerManager void sendAsyncMessage([optional] in AString messageName, [optional] in jsval obj, [optional] in jsval objects, - [optional] in nsIPrincipal principal); + [optional] in nsIPrincipal principal, + [optional] in jsval transfers); }; /** diff --git a/dom/ipc/DOMTypes.ipdlh b/dom/ipc/DOMTypes.ipdlh index 119fdd57132..49b4f3f2420 100644 --- a/dom/ipc/DOMTypes.ipdlh +++ b/dom/ipc/DOMTypes.ipdlh @@ -24,10 +24,19 @@ union OptionalID void_t; }; +struct MessagePortIdentifier +{ + nsID uuid; + nsID destinationUuid; + uint32_t sequenceId; + bool neutered; +}; + struct ClonedMessageData { SerializedStructuredCloneBuffer data; PBlob[] blobs; + MessagePortIdentifier[] identfiers; }; union BlobData diff --git a/dom/ipc/StructuredCloneData.cpp b/dom/ipc/StructuredCloneData.cpp index 8ae867ca4b2..99238a55663 100644 --- a/dom/ipc/StructuredCloneData.cpp +++ b/dom/ipc/StructuredCloneData.cpp @@ -66,10 +66,19 @@ void StructuredCloneData::Write(JSContext* aCx, JS::Handle aValue, ErrorResult &aRv) +{ + Write(aCx, aValue, JS::UndefinedHandleValue, aRv); +} + +void +StructuredCloneData::Write(JSContext* aCx, + JS::Handle aValue, + JS::Handle aTransfer, + ErrorResult &aRv) { MOZ_ASSERT(!Data()); - StructuredCloneHolder::Write(aCx, aValue, aRv); + StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv); if (NS_WARN_IF(aRv.Failed())) { return; } diff --git a/dom/ipc/StructuredCloneData.h b/dom/ipc/StructuredCloneData.h index 3bcf67b8723..80ff5dcc580 100644 --- a/dom/ipc/StructuredCloneData.h +++ b/dom/ipc/StructuredCloneData.h @@ -70,7 +70,7 @@ class StructuredCloneData : public StructuredCloneHolder public: StructuredCloneData() : StructuredCloneHolder(StructuredCloneHolder::CloningSupported, - StructuredCloneHolder::TransferringNotSupported, + StructuredCloneHolder::TransferringSupported, StructuredCloneHolder::DifferentProcess) , mExternalData(nullptr) , mExternalDataLength(0) @@ -106,6 +106,11 @@ public: JS::Handle aValue, ErrorResult &aRv); + void Write(JSContext* aCx, + JS::Handle aValue, + JS::Handle aTransfers, + ErrorResult &aRv); + void UseExternalData(uint64_t* aData, size_t aDataLength) { MOZ_ASSERT(!Data()); diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp index d6fc3a3a09f..b2a716e6b5f 100644 --- a/dom/messagechannel/MessagePort.cpp +++ b/dom/messagechannel/MessagePort.cpp @@ -104,13 +104,10 @@ private: JSContext* cx = jsapi.cx(); - nsCOMPtr window = - do_QueryInterface(mPort->GetParentObject()); - ErrorResult rv; JS::Rooted value(cx); - mData->Read(window, cx, &value, rv); + mData->Read(mPort->GetParentObject(), cx, &value, rv); if (NS_WARN_IF(rv.Failed())) { return rv.StealNSResult(); } @@ -262,15 +259,20 @@ NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback) } // namespace -MessagePort::MessagePort(nsPIDOMWindowInner* aWindow) - : DOMEventTargetHelper(aWindow) - , mInnerID(0) +MessagePort::MessagePort(nsISupports* aSupports) + : mInnerID(0) , mMessageQueueEnabled(false) , mIsKeptAlive(false) { mIdentifier = new MessagePortIdentifier(); mIdentifier->neutered() = true; mIdentifier->sequenceId() = 0; + + nsCOMPtr globalObject = do_QueryInterface(aSupports); + if (NS_WARN_IF(!globalObject)) { + return; + } + BindToOwner(globalObject); } MessagePort::~MessagePort() @@ -280,21 +282,21 @@ MessagePort::~MessagePort() } /* static */ already_AddRefed -MessagePort::Create(nsPIDOMWindowInner* aWindow, const nsID& aUUID, +MessagePort::Create(nsISupports* aSupport, const nsID& aUUID, const nsID& aDestinationUUID, ErrorResult& aRv) { - RefPtr mp = new MessagePort(aWindow); + RefPtr mp = new MessagePort(aSupport); mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */, false /* Neutered */, eStateUnshippedEntangled, aRv); return mp.forget(); } /* static */ already_AddRefed -MessagePort::Create(nsPIDOMWindowInner* aWindow, +MessagePort::Create(nsISupports* aSupport, const MessagePortIdentifier& aIdentifier, ErrorResult& aRv) { - RefPtr mp = new MessagePort(aWindow); + RefPtr mp = new MessagePort(aSupport); mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(), aIdentifier.sequenceId(), aIdentifier.neutered(), eStateEntangling, aRv); diff --git a/dom/messagechannel/MessagePort.h b/dom/messagechannel/MessagePort.h index 498efeb92d4..81c7e06cf6e 100644 --- a/dom/messagechannel/MessagePort.h +++ b/dom/messagechannel/MessagePort.h @@ -45,11 +45,11 @@ public: DOMEventTargetHelper) static already_AddRefed - Create(nsPIDOMWindowInner* aWindow, const nsID& aUUID, + Create(nsISupports* aSupport, const nsID& aUUID, const nsID& aDestinationUUID, ErrorResult& aRv); static already_AddRefed - Create(nsPIDOMWindowInner* aWindow, const MessagePortIdentifier& aIdentifier, + Create(nsISupports* aSupport, const MessagePortIdentifier& aIdentifier, ErrorResult& aRv); // For IPC. @@ -88,7 +88,7 @@ public: void Closed(); private: - explicit MessagePort(nsPIDOMWindowInner* aWindow); + explicit MessagePort(nsISupports* nsISupports); ~MessagePort(); enum State { diff --git a/dom/messagechannel/PMessagePort.ipdl b/dom/messagechannel/PMessagePort.ipdl index a838c685fe7..8d22fbb449a 100644 --- a/dom/messagechannel/PMessagePort.ipdl +++ b/dom/messagechannel/PMessagePort.ipdl @@ -5,19 +5,11 @@ include protocol PBackground; include protocol PBlob; -using struct nsID from "nsID.h"; +include DOMTypes; namespace mozilla { namespace dom { -struct MessagePortIdentifier -{ - nsID uuid; - nsID destinationUuid; - uint32_t sequenceId; - bool neutered; -}; - struct MessagePortMessage { MessagePortIdentifier[] transferredPorts; From 9e800703863eb29fa4ae28f53c7ec59822c75f66 Mon Sep 17 00:00:00 2001 From: Mantaroh Yoshinaga Date: Tue, 9 Feb 2016 00:13:00 +0100 Subject: [PATCH 030/252] Bug 1174624 - Add mochitest for MessagePort of nsFrameMessagemanager. r=baku --- dom/messagechannel/tests/chrome.ini | 7 + dom/messagechannel/tests/mm_messageChannel.js | 76 ++++++++++ .../tests/mm_messageChannelParent.js | 143 ++++++++++++++++++ .../tests/mm_messageChannelParent.xul | 12 ++ .../mm_messageChannelParentNotRemote.xul | 12 ++ .../test_messageChannelWithMessageManager.xul | 28 ++++ ...sageChannelWithMessageManagerNotRemote.xul | 28 ++++ 7 files changed, 306 insertions(+) create mode 100644 dom/messagechannel/tests/mm_messageChannel.js create mode 100644 dom/messagechannel/tests/mm_messageChannelParent.js create mode 100644 dom/messagechannel/tests/mm_messageChannelParent.xul create mode 100644 dom/messagechannel/tests/mm_messageChannelParentNotRemote.xul create mode 100644 dom/messagechannel/tests/test_messageChannelWithMessageManager.xul create mode 100644 dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul diff --git a/dom/messagechannel/tests/chrome.ini b/dom/messagechannel/tests/chrome.ini index 8d7140d76f2..8613309c5ec 100644 --- a/dom/messagechannel/tests/chrome.ini +++ b/dom/messagechannel/tests/chrome.ini @@ -1,5 +1,12 @@ [DEFAULT] support-files = iframe_messageChannel_chrome.html + mm_messageChannelParent.xul + mm_messageChannelParentNotRemote.xul + mm_messageChannelParent.js + mm_messageChannel.js [test_messageChannel.xul] +[test_messageChannelWithMessageManager.xul] +skip-if = os == 'android' +[test_messageChannelWithMessageManagerNotRemote.xul] diff --git a/dom/messagechannel/tests/mm_messageChannel.js b/dom/messagechannel/tests/mm_messageChannel.js new file mode 100644 index 00000000000..914d800fdf7 --- /dev/null +++ b/dom/messagechannel/tests/mm_messageChannel.js @@ -0,0 +1,76 @@ +function debug(msg) { + dump("[mmMessageChannelChild]" + msg + "\n"); +} + +/** + * Preparation Test + */ +let port; +let toString = Object.prototype.toString; + +(function prepare() { + debug("Script loaded."); + addTestReceiver(); + sendAsyncMessage("mmMessagePort:finishScriptLoad", {}, {}); +})(); + +function ok(condition, message) { + debug('condition: ' + condition + ', ' + message + '\n'); + if (!condition) { + sendAsyncMessage("mmMessagePort:fail", { message: message }); + throw 'failed check: ' + message; + } +} + +function is(a, b, message) { + ok(a===b, message); +} + + +/** + * Testing codes. + */ +function addTestReceiver() { + addMessageListener("BasicTest:PortCreated", basicTest); + addMessageListener("CloseTest:PortCreated", closeTest); + addMessageListener("EmptyTest:PortCreated", emptyTest); + addMessageListener("NotTransferableTest:PortCreated", notTransferableTest); +} + +function basicTest(msg) { + port = msg.ports[0]; + is(toString.call(port), "[object MessagePort]", "created MessagePort."); + + port.onmessage = (msg) => { + is(msg.data, "BasicTest:StartTest", "Replied message is correct."); + port.postMessage("BasicTest:TestOK"); + }; + + sendAsyncMessage("BasicTest:FinishPrepare", { message: "OK" }); +} + +function closeTest(msg) { + port = msg.ports[0]; + is(toString.call(port), "[object MessagePort]", "created MessagePort."); + + port.onmessage = (msg) => { + ok(msg.data,"CloseTest:StartTest", "Replied message is correct."); + port.postMessage("CloseTest:TestOK"); + }; + + port.close(); + + sendAsyncMessage("CloseTest:FinishPrepare", { message: "OK"}); +} + +function emptyTest(msg) { + let portSize = msg.ports.length; + is(portSize, 0, "transfered port size is zero."); + + sendAsyncMessage("EmptyTest:FinishPrepare", { message: "OK"}); +} + +function notTransferableTest(msg) { + sendAsyncMessage("NotTransferableTest:FinishPrepare", {message: "OK"}); +} + diff --git a/dom/messagechannel/tests/mm_messageChannelParent.js b/dom/messagechannel/tests/mm_messageChannelParent.js new file mode 100644 index 00000000000..a5ffa2cafa2 --- /dev/null +++ b/dom/messagechannel/tests/mm_messageChannelParent.js @@ -0,0 +1,143 @@ +Components.utils.import("resource://gre/modules/Services.jsm"); +let port; +let mm; + +function info(message) { + return opener.wrappedJSObject.info(message); +} + +function ok(condition, message) { + return opener.wrappedJSObject.ok(condition, message); +} + +function is(v1, v2, message) { + return opener.wrappedJSObject.is(v1, v2, message); +} + +function todo_is(v1, v2, message) { + return opener.wrappedJSObject.todo_is(v1, v2, message); +} + +function finish() { + opener.setTimeout("done()", 0); + window.close(); +} + +function debug(msg) { + dump("[mmMessageChannelParent]" + msg + "\n"); +} + +let tests = [ basic_test, + close_test, + empty_transferable, + not_transferable]; + +// Test Routine +function run_tests() { + let test = tests.shift(); + if (test === undefined) { + finish(); + return; + } + + test(function() { + setTimeout(run_tests,0); + }); +} + +// Basic communication test. +function basic_test(finish) { + ok(mm, "basic_test"); + + let finishPrepare = (msg) => { + is(msg.data.message, "OK", ""); + ok(port, ""); + port.onmessage = (msg) => { + is(msg.data, "BasicTest:TestOK", ""); + finish(); + } + port.postMessage("BasicTest:StartTest"); + mm.removeMessageListener("BasicTest:FinishPrepare", finishPrepare); + }; + + let channel = new MessageChannel(); + port = channel.port2; + mm.addMessageListener("BasicTest:FinishPrepare", finishPrepare); + mm.sendAsyncMessage("BasicTest:PortCreated", {}, {}, undefined, [channel.port1]); +} + +// Communicate with closed port. +function close_test(finish) { + ok(mm, "close_test"); + + let finishPrepare = (msg) => { + is(msg.data.message, "OK", ""); + ok(port, ""); + + port.onmessage = (msg) => { + ok(false, "Port is alive."); + finish(); + } + + port.postMessage("CloseTest:StartTest"); + mm.removeMessageListener("CloseTest:FinishPrepare", finishPrepare); + finish(); + } + + let channel = new MessageChannel(); + port = channel.port2; + mm.addMessageListener("CloseTest:FinishPrepare", finishPrepare); + mm.sendAsyncMessage("CloseTest:PortCreated", {}, {}, undefined, [channel.port1]); +} + +// Empty transferable object +function empty_transferable(finish) { + ok(mm, "empty_transferable"); + + let finishPrepare = (msg) => { + ok(true, "Same basic test."); + mm.removeMessageListener("EmptyTest:FinishPrepare", finishPrepare); + finish(); + }; + + mm.addMessageListener("EmptyTest:FinishPrepare", finishPrepare); + mm.sendAsyncMessage("EmptyTest:PortCreated", {}, {}, undefined, []); +} + +// Not transferable object. +function not_transferable(finish) { + ok(mm, "not_transferable"); + + let finishPrepare = (msg) => { + ok(true, "Same basic test."); + finish(); + } + + mm.addMessageListener("NotTransferableTest:FinishPrepare", finishPrepare); + mm.sendAsyncMessage("NotTransferableTest:PortCreated", {}, {}, undefined, [""]); +} + +/* + * Test preparation + */ +function finishLoad(msg) { + run_tests(); +} + +function prepare_test() { + debug("start run_tests()"); + var node = document.getElementById('messagechannel_remote'); + mm = node.messageManager; //Services.ppmm.getChildAt(1); + ok(mm, "created MessageManager.") + + mm.addMessageListener("mmMessagePort:finishScriptLoad", finishLoad); + mm.addMessageListener("mmMessagePort:fail", failed_test); + //mm.loadProcessScript("chrome://mochitests/content/chrome/dom/messagechannel/tests/mm_messageChannel.js", true); + mm.loadFrameScript("chrome://mochitests/content/chrome/dom/messagechannel/tests/mm_messageChannel.js", true); + ok(true, "Loaded"); +} + +function failed_test() { + debug("failed test in child process"); + ok(false, ""); +} diff --git a/dom/messagechannel/tests/mm_messageChannelParent.xul b/dom/messagechannel/tests/mm_messageChannelParent.xul new file mode 100644 index 00000000000..5f5c5ae5bee --- /dev/null +++ b/dom/messagechannel/tests/mm_messageChannelParent.xul @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/dom/messagechannel/tests/mm_messageChannelParentNotRemote.xul b/dom/messagechannel/tests/mm_messageChannelParentNotRemote.xul new file mode 100644 index 00000000000..cb3b55dea73 --- /dev/null +++ b/dom/messagechannel/tests/mm_messageChannelParentNotRemote.xul @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/dom/messagechannel/tests/test_messageChannelWithMessageManager.xul b/dom/messagechannel/tests/test_messageChannelWithMessageManager.xul new file mode 100644 index 00000000000..11a1fc585d5 --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannelWithMessageManager.xul @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul b/dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul new file mode 100644 index 00000000000..24ea7ed0d8c --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannelWithMessageManagerNotRemote.xul @@ -0,0 +1,28 @@ + + + + + + + + + + + + + From 9983c3dd5139d439eefcce24b6939b61ea220540 Mon Sep 17 00:00:00 2001 From: Mantaroh Yoshinaga Date: Mon, 15 Feb 2016 19:43:00 +0100 Subject: [PATCH 031/252] Bug 1174624 - Add PortIdentifier copy code in order to communicate with same process. r=baku --- dom/base/StructuredCloneHolder.h | 4 ++-- dom/ipc/StructuredCloneData.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h index 7a620b28507..8e9e36f33ea 100644 --- a/dom/base/StructuredCloneHolder.h +++ b/dom/base/StructuredCloneHolder.h @@ -210,7 +210,7 @@ public: return Move(mTransferredPorts); } - nsTArray& PortIdentifiers() + nsTArray& PortIdentifiers() const { MOZ_ASSERT(mSupportsTransferring); return mPortIdentifiers; @@ -310,7 +310,7 @@ protected: // This array contains the identifiers of the MessagePorts. Based on these we // are able to reconnect the new transferred ports with the other // MessageChannel ports. - nsTArray mPortIdentifiers; + mutable nsTArray mPortIdentifiers; #ifdef DEBUG nsCOMPtr mCreationThread; diff --git a/dom/ipc/StructuredCloneData.cpp b/dom/ipc/StructuredCloneData.cpp index 99238a55663..2c19a23c317 100644 --- a/dom/ipc/StructuredCloneData.cpp +++ b/dom/ipc/StructuredCloneData.cpp @@ -41,6 +41,8 @@ StructuredCloneData::Copy(const StructuredCloneData& aData) NS_ENSURE_TRUE(mSharedData, false); } + PortIdentifiers().AppendElements(aData.PortIdentifiers()); + MOZ_ASSERT(BlobImpls().IsEmpty()); BlobImpls().AppendElements(aData.BlobImpls()); From 4479f918aed5a0f823c0bdb01614b6b4d46f38c7 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Mon, 22 Feb 2016 09:36:22 +0000 Subject: [PATCH 032/252] Bug 1246984 - Fix scrolling on Blackberry capacitive keyboard - r=kats --- .../mozilla/gecko/gfx/NativePanZoomController.java | 14 +++++++++++--- widget/android/nsWindow.cpp | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java b/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java index 7aea6d029f0..e2c79be3737 100644 --- a/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java +++ b/mobile/android/base/java/org/mozilla/gecko/gfx/NativePanZoomController.java @@ -29,6 +29,7 @@ class NativePanZoomController extends JNIObject implements PanZoomController { boolean mNegateWheelScroll; private float mPointerScrollFactor; private final PrefsHelper.PrefHandler mPrefsObserver; + private long mLastDownTime; private static final float MAX_SCROLL = 0.075f * GeckoAppShell.getDpi(); @WrapForJNI @@ -51,6 +52,12 @@ class NativePanZoomController extends JNIObject implements PanZoomController { final int action = event.getActionMasked(); final int count = event.getPointerCount(); + if (action == MotionEvent.ACTION_DOWN) { + mLastDownTime = event.getDownTime(); + } else if (mLastDownTime != event.getDownTime()) { + return false; + } + final int[] pointerId = new int[count]; final float[] x = new float[count]; final float[] y = new float[count]; @@ -145,11 +152,12 @@ class NativePanZoomController extends JNIObject implements PanZoomController { @Override public boolean onMotionEvent(MotionEvent event) { final int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_SCROLL) { + if (action == MotionEvent.ACTION_SCROLL && event.getDownTime() >= mLastDownTime) { + mLastDownTime = event.getDownTime(); return handleScrollEvent(event); - } else { - return false; } + + return false; } @Override diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index b070107ba85..1d47323fad6 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -541,7 +541,7 @@ public: ScreenIntPoint offset = ViewAs(mWindow->WidgetToScreenOffset(), PixelCastJustification::LayoutDeviceIsScreenForBounds); ScreenPoint origin = ScreenPoint(aX, aY) - offset; - ScrollWheelInput input(aTime, TimeStamp(), GetModifiers(aMetaState), + ScrollWheelInput input(aTime, TimeStamp::Now(), GetModifiers(aMetaState), ScrollWheelInput::SCROLLMODE_SMOOTH, ScrollWheelInput::SCROLLDELTA_PIXEL, origin, From 0d41ced207ad3ed56bdd7de5aa7f5f9905de53c0 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 22 Feb 2016 11:21:49 +0100 Subject: [PATCH 033/252] Bug 1247871 - Don't fold JSOP_IN if the rhs might be primitive. r=h4writer --- js/src/jit-test/tests/ion/fold-in.js | 12 ++++++++++++ js/src/jit/IonBuilder.cpp | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/js/src/jit-test/tests/ion/fold-in.js b/js/src/jit-test/tests/ion/fold-in.js index cc48588b94c..4e0c54cd5d7 100644 --- a/js/src/jit-test/tests/ion/fold-in.js +++ b/js/src/jit-test/tests/ion/fold-in.js @@ -30,3 +30,15 @@ function g(arr) { assertEq(g(arr), 250); arr[0].abcd = 3; assertEq(g(arr), 375); + +function testPrimitive() { + var x = 7; + var c = 0; + for (var i=0; i<5; i++) { + try { + "z" in x; + } catch(e) { c++; } + } + assertEq(c, 5); +} +testPrimitive(); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index ff2780f4906..7d2860b8f03 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -13430,7 +13430,7 @@ IonBuilder::inTryFold(bool* emitted, MDefinition* obj, MDefinition* id) return true; TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) + if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType_Object) return true; for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) { From 785eec4fe86ae2a81f173ce91e047d8d3ed755bf Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 22 Feb 2016 11:21:52 +0100 Subject: [PATCH 034/252] Bug 1243787 - Don't replace the CalleeToken on OOM to avoid profiler crashes. r=nbp --- js/src/jit/Bailouts.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index a37e116cfd7..443a0555d79 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -149,16 +149,14 @@ jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut, probes::ExitScript(cx, script, script->functionNonDelazifying(), /* popSPSFrame = */ false); +#ifdef JS_JITSPEW JitFrameLayout* frame = iter.jsFrame(); - JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s): converting to exit frame", + JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s)", (retval == BAILOUT_RETURN_FATAL_ERROR) ? "Fatal Error" : "Over Recursion"); - JitSpew(JitSpew_IonInvalidate, " orig calleeToken %p", (void*) frame->calleeToken()); - JitSpew(JitSpew_IonInvalidate, " orig frameSize %u", unsigned(frame->prevFrameLocalSize())); - JitSpew(JitSpew_IonInvalidate, " orig ra %p", (void*) frame->returnAddress()); - - frame->replaceCalleeToken(nullptr); - - JitSpew(JitSpew_IonInvalidate, " new calleeToken %p", (void*) frame->calleeToken()); + JitSpew(JitSpew_IonInvalidate, " calleeToken %p", (void*) frame->calleeToken()); + JitSpew(JitSpew_IonInvalidate, " frameSize %u", unsigned(frame->prevFrameLocalSize())); + JitSpew(JitSpew_IonInvalidate, " ra %p", (void*) frame->returnAddress()); +#endif } iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp()); From a2c4448e6a97ab62284068aef0df85e3277959d4 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 22 Feb 2016 11:21:54 +0100 Subject: [PATCH 035/252] Bug 1234408 - Fix ARM assembler to bind labels on OOM to silence ~Label assert. r=bbouvier --- js/src/jit/arm/Assembler-arm.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index b2ca0478913..25a7a6efe0b 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -2777,8 +2777,12 @@ Assembler::bind(Label* label, BufferOffset boff) BufferOffset b(label); do { // Even a 0 offset may be invalid if we're out of memory. - if (oom()) + if (oom()) { + // Ensure we always bind the label. This matches what we do on + // x86/x64 and silences the assert in ~Label. + label->bind(0); return; + } BufferOffset next; more = nextLink(b, &next); Instruction branch = *editSrc(b); From 164c010d2ac434b1a3a2334c4b4f0ca249b36ecf Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 22 Feb 2016 11:21:56 +0100 Subject: [PATCH 036/252] Bug 1244502 - Fix minor correctness bug with fun.call bailouts and |arguments|. r=h4writer --- js/src/jit-test/tests/ion/bug1244502.js | 12 +++++++ js/src/jit/BaselineBailouts.cpp | 46 +++++++++++-------------- 2 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1244502.js diff --git a/js/src/jit-test/tests/ion/bug1244502.js b/js/src/jit-test/tests/ion/bug1244502.js new file mode 100644 index 00000000000..b0b3943cd5b --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1244502.js @@ -0,0 +1,12 @@ +function f(arg) { + bailout(); + assertEq(arguments.length, 2); + assertEq(arg, ""); + assertEq(arguments[0], ""); + assertEq(arguments[1], 0); +} +for (var i = 0; i < 100; ++i) { + (function() { + f.call(1, "", 0); + })(); +} diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 132610cce35..b853d5e17b1 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -645,12 +645,6 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, return false; BufferPointer blFrame = builder.pointerAtStackOffset(0); - // Initialize BaselineFrame::frameSize - uint32_t frameSize = BaselineFrame::Size() + BaselineFrame::FramePointerOffset + - (sizeof(Value) * (script->nfixed() + exprStackSlots)); - JitSpew(JitSpew_BaselineBailouts, " FrameSize=%d", (int) frameSize); - blFrame->setFrameSize(frameSize); - uint32_t flags = 0; // If we are bailing to a script whose execution is observed, mark the @@ -930,7 +924,15 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, return false; } - size_t endOfBaselineJSFrameStack = builder.framePushed(); + // BaselineFrame::frameSize is the size of everything pushed since + // the builder.resetFramePushed() call. + uint32_t frameSize = builder.framePushed(); + blFrame->setFrameSize(frameSize); + JitSpew(JitSpew_BaselineBailouts, " FrameSize=%u", frameSize); + + // numValueSlots() is based on the frame size, do some sanity checks. + MOZ_ASSERT(blFrame->numValueSlots() >= script->nfixed()); + MOZ_ASSERT(blFrame->numValueSlots() <= script->nslots()); // If we are resuming at a LOOPENTRY op, resume at the next op to avoid // a bailout -> enter Ion -> bailout loop with --ion-eager. See also @@ -1226,6 +1228,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, // Arguments are reversed on the BaselineJS frame's stack values. MOZ_ASSERT(IsIonInlinablePC(pc)); unsigned actualArgc; + Value callee; if (needToSaveArgs) { // For FUNAPPLY or an accessor, the arguments are not on the stack anymore, // but they are copied in a vector and are written here. @@ -1233,6 +1236,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, actualArgc = blFrame->numActualArgs(); else actualArgc = IsSetPropPC(pc); + callee = savedCallerArgs[0]; // Align the stack based on the number of arguments. size_t afterFrameSize = (actualArgc + 1) * sizeof(Value) + JitFrameLayout::Size(); @@ -1260,12 +1264,16 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding")) return false; - MOZ_ASSERT(actualArgc + 2 + pushedNewTarget <= exprStackSlots); - for (unsigned i = 0; i < actualArgc + 1 + pushedNewTarget; i++) { - size_t argSlot = (script->nfixed() + exprStackSlots) - (i + 1); - if (!builder.writeValue(*blFrame->valueSlot(argSlot), "ArgVal")) + // Copy the arguments and |this| from the BaselineFrame, in reverse order. + size_t valueSlot = blFrame->numValueSlots() - 1; + size_t calleeSlot = valueSlot - actualArgc - 1 - pushedNewTarget; + + for (size_t i = valueSlot; i > calleeSlot; i--) { + if (!builder.writeValue(*blFrame->valueSlot(i), "ArgVal")) return false; } + + callee = *blFrame->valueSlot(calleeSlot); } // In case these arguments need to be copied on the stack again for a rectifier frame, @@ -1283,20 +1291,8 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, return false; // Push callee token (must be a JS Function) - Value callee; - if (needToSaveArgs) { - // The arguments of FUNAPPLY or inlined accessors are not writen to the stack. - // So get the callee from the specially saved vector. - callee = savedCallerArgs[0]; - } else { - uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2 + pushedNewTarget); - size_t calleeOffset = (builder.framePushed() - endOfBaselineJSFrameStack) - + ((exprStackSlots - (calleeStackSlot + 1)) * sizeof(Value)); - callee = *builder.valuePointerAtStackOffset(calleeOffset); - JitSpew(JitSpew_BaselineBailouts, " CalleeStackSlot=%d", (int) calleeStackSlot); - } - JitSpew(JitSpew_BaselineBailouts, " Callee = %016llx", *((uint64_t*) &callee)); - MOZ_ASSERT(callee.isObject() && callee.toObject().is()); + JitSpew(JitSpew_BaselineBailouts, " Callee = %016llx", callee.asRawBits()); + JSFunction* calleeFun = &callee.toObject().as(); if (!builder.writePtr(CalleeToToken(calleeFun, JSOp(*pc) == JSOP_NEW), "CalleeToken")) return false; From 36f6631a00f47ec55602290ea71584d3bbaab9fe Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Mon, 25 Jan 2016 07:49:00 +0100 Subject: [PATCH 037/252] Bug 1242482 - Propagate Service worker unregistration to the parent process. r=bkelly --- dom/workers/ServiceWorkerManagerParent.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dom/workers/ServiceWorkerManagerParent.cpp b/dom/workers/ServiceWorkerManagerParent.cpp index 7bada3f34e0..5b22a999bb8 100644 --- a/dom/workers/ServiceWorkerManagerParent.cpp +++ b/dom/workers/ServiceWorkerManagerParent.cpp @@ -73,9 +73,11 @@ class UnregisterServiceWorkerCallback final : public nsRunnable { public: UnregisterServiceWorkerCallback(const PrincipalInfo& aPrincipalInfo, - const nsString& aScope) + const nsString& aScope, + uint64_t aParentID) : mPrincipalInfo(aPrincipalInfo) , mScope(aScope) + , mParentID(aParentID) { AssertIsInMainProcess(); AssertIsOnBackgroundThread(); @@ -93,12 +95,21 @@ public: service->UnregisterServiceWorker(mPrincipalInfo, NS_ConvertUTF16toUTF8(mScope)); + + RefPtr managerService = + ServiceWorkerManagerService::Get(); + if (managerService) { + managerService->PropagateUnregister(mParentID, mPrincipalInfo, + mScope); + } + return NS_OK; } private: const PrincipalInfo mPrincipalInfo; nsString mScope; + uint64_t mParentID; }; class CheckPrincipalWithCallbackRunnable final : public nsRunnable @@ -222,7 +233,7 @@ ServiceWorkerManagerParent::RecvUnregister(const PrincipalInfo& aPrincipalInfo, } RefPtr callback = - new UnregisterServiceWorkerCallback(aPrincipalInfo, aScope); + new UnregisterServiceWorkerCallback(aPrincipalInfo, aScope, mID); RefPtr parent = BackgroundParent::GetContentParent(Manager()); From 0c99c6d851cce7dc1f6e4dd52b20b8426d22aa79 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 12 Feb 2016 14:21:00 +0100 Subject: [PATCH 038/252] Bug 1242482 P2 Don't SendUnregister() if registration is already removed. r=baku --- dom/workers/ServiceWorkerManager.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index d61c997d517..6a25d21495d 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -2472,16 +2472,6 @@ private: RefPtr swm = ServiceWorkerManager::GetInstance(); - // Note, we send the message to remove the registration from disk now even - // though we may only set the mPendingUninstall flag below. This is - // necessary to ensure the registration is removed if the controlled - // clients are closed by shutting down the browser. If the registration - // is resurrected by clearing mPendingUninstall then it should be saved - // to disk again. - if (swm->mActor) { - swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope)); - } - nsAutoCString scopeKey; nsresult rv = swm->PrincipalToScopeKey(mPrincipal, scopeKey); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -2504,6 +2494,16 @@ private: MOZ_ASSERT(registration); + // Note, we send the message to remove the registration from disk now even + // though we may only set the mPendingUninstall flag below. This is + // necessary to ensure the registration is removed if the controlled + // clients are closed by shutting down the browser. If the registration + // is resurrected by clearing mPendingUninstall then it should be saved + // to disk again. + if (!registration->mPendingUninstall && swm->mActor) { + swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope)); + } + // "Set registration's uninstalling flag." registration->mPendingUninstall = true; // "Resolve promise with true" From 7d5e40d85911f6ff189fe3e1f418b73f686272cc Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Sat, 20 Feb 2016 07:03:00 +0100 Subject: [PATCH 039/252] Bug 1242482 P3 Don't send unregister messages when triggered from a PropagateUnregister(). r=baku --- dom/workers/ServiceWorkerManager.cpp | 48 ++++++++++++++++++++++- dom/workers/ServiceWorkerManager.h | 3 ++ dom/workers/ServiceWorkerManagerChild.cpp | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 6a25d21495d..c5ce671cdeb 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -2427,6 +2427,7 @@ class ServiceWorkerUnregisterJob final : public ServiceWorkerJob const nsCString mScope; nsCOMPtr mCallback; nsCOMPtr mPrincipal; + const bool mSendToParent; ~ServiceWorkerUnregisterJob() {} @@ -2435,11 +2436,13 @@ public: ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue, const nsACString& aScope, nsIServiceWorkerUnregisterCallback* aCallback, - nsIPrincipal* aPrincipal) + nsIPrincipal* aPrincipal, + bool aSendToParent = true) : ServiceWorkerJob(aQueue, Type::UnregisterJob) , mScope(aScope) , mCallback(aCallback) , mPrincipal(aPrincipal) + , mSendToParent(aSendToParent) { AssertIsOnMainThread(); } @@ -2500,7 +2503,7 @@ private: // clients are closed by shutting down the browser. If the registration // is resurrected by clearing mPendingUninstall then it should be saved // to disk again. - if (!registration->mPendingUninstall && swm->mActor) { + if (mSendToParent && !registration->mPendingUninstall && swm->mActor) { swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope)); } @@ -2582,6 +2585,47 @@ ServiceWorkerManager::Unregister(nsIPrincipal* aPrincipal, return NS_OK; } +nsresult +ServiceWorkerManager::NotifyUnregister(nsIPrincipal* aPrincipal, + const nsAString& aScope) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aPrincipal); + + nsresult rv; + +// This is not accessible by content, and callers should always ensure scope is +// a correct URI, so this is wrapped in DEBUG +#ifdef DEBUG + nsCOMPtr scopeURI; + rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } +#endif + + nsAutoCString originSuffix; + rv = PrincipalToScopeKey(aPrincipal, originSuffix); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + NS_ConvertUTF16toUTF8 scope(aScope); + ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(originSuffix, scope); + MOZ_ASSERT(queue); + + RefPtr job = + new ServiceWorkerUnregisterJob(queue, scope, nullptr, aPrincipal, false); + + if (mActor) { + queue->Append(job); + return NS_OK; + } + + AppendPendingOperation(queue, job); + return NS_OK; +} + ServiceWorkerJobQueue* ServiceWorkerManager::GetOrCreateJobQueue(const nsACString& aKey, const nsACString& aScope) diff --git a/dom/workers/ServiceWorkerManager.h b/dom/workers/ServiceWorkerManager.h index 15d02f4f765..8d61a291e65 100644 --- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -499,6 +499,9 @@ public: const nsACString& aScope, Maybe> aData); + nsresult + NotifyUnregister(nsIPrincipal* aPrincipal, const nsAString& aScope); + private: ServiceWorkerManager(); ~ServiceWorkerManager(); diff --git a/dom/workers/ServiceWorkerManagerChild.cpp b/dom/workers/ServiceWorkerManagerChild.cpp index 32ef2f81bd7..9dcee098276 100644 --- a/dom/workers/ServiceWorkerManagerChild.cpp +++ b/dom/workers/ServiceWorkerManagerChild.cpp @@ -62,7 +62,7 @@ ServiceWorkerManagerChild::RecvNotifyUnregister(const PrincipalInfo& aPrincipalI return true; } - nsresult rv = swm->Unregister(principal, nullptr, aScope); + nsresult rv = swm->NotifyUnregister(principal, aScope); Unused << NS_WARN_IF(NS_FAILED(rv)); return true; } From b0ceb434c6281756651884e2452e7af188d16554 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 15 Feb 2016 13:40:00 +0100 Subject: [PATCH 040/252] Bug 1242482 P4 Don't call SendUnregister() a second time when SW registration is finally removed. r=baku --- dom/workers/ServiceWorkerManager.cpp | 55 +++++++++++----------------- dom/workers/ServiceWorkerManager.h | 8 ---- 2 files changed, 21 insertions(+), 42 deletions(-) diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index c5ce671cdeb..046934ac63d 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -2523,7 +2523,6 @@ private: } // "Invoke [[Clear Registration]]..." - registration->Clear(); swm->RemoveRegistration(registration); } @@ -3401,7 +3400,6 @@ ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aR aRegistration->StopControllingADocument(); if (!aRegistration->IsControllingDocuments()) { if (aRegistration->mPendingUninstall) { - aRegistration->Clear(); RemoveRegistration(aRegistration); } else { // If the registration has an active worker that is running @@ -4302,46 +4300,35 @@ ServiceWorkerManager::MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRe MOZ_ASSERT(aRegistration); RefPtr newest = aRegistration->Newest(); if (!newest && HasScope(aRegistration->mPrincipal, aRegistration->mScope)) { - aRegistration->Clear(); RemoveRegistration(aRegistration); } } -void -ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration) -{ - MOZ_ASSERT(aRegistration); - MOZ_ASSERT(!aRegistration->IsControllingDocuments()); - - if (mShuttingDown) { - return; - } - - // All callers should be either from a job in which case the actor is - // available, or from MaybeStopControlling(), in which case, this will only be - // called if a valid registration is found. If a valid registration exists, - // it means the actor is available since the original map of registrations is - // populated by it, and any new registrations wait until the actor is - // available before proceeding (See ServiceWorkerRegisterJob::Start). - MOZ_ASSERT(mActor); - - PrincipalInfo principalInfo; - if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aRegistration->mPrincipal, - &principalInfo)))) { - //XXXnsm I can't think of any other reason a stored principal would fail to - //convert. - NS_WARNING("Unable to unregister serviceworker due to possible OOM"); - return; - } - - mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(aRegistration->mScope)); -} - void ServiceWorkerManager::RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration) { - RemoveRegistrationInternal(aRegistration); + // Note, we do not need to call mActor->SendUnregister() here. There are a few + // ways we can get here: + // 1) Through a normal unregister which calls SendUnregister() in the unregister + // job Start() method. + // 2) Through origin storage being purged. These result in ForceUnregister() + // starting unregister jobs which in turn call SendUnregister(). + // 3) Through the failure to install a new service worker. Since we don't store + // the registration until install succeeds, we do not need to call + // SendUnregister here. + // Assert these conditions by testing for pending uninstall (cases 1 and 2) or + // null workers (case 3). +#ifdef DEBUG + RefPtr newest = aRegistration->Newest(); + MOZ_ASSERT(aRegistration->mPendingUninstall || !newest); +#endif + MOZ_ASSERT(HasScope(aRegistration->mPrincipal, aRegistration->mScope)); + + // When a registration is removed, we must clear its contents since the DOM + // object may be held by content script. + aRegistration->Clear(); + RemoveScopeAndRegistration(aRegistration); } diff --git a/dom/workers/ServiceWorkerManager.h b/dom/workers/ServiceWorkerManager.h index 8d61a291e65..18a9f6776f0 100644 --- a/dom/workers/ServiceWorkerManager.h +++ b/dom/workers/ServiceWorkerManager.h @@ -641,14 +641,6 @@ private: void MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration); - // Does all cleanup except removing the registration from - // mServiceWorkerRegistrationInfos. This is useful when we clear - // registrations via remove()/removeAll() since we are iterating over the - // hashtable and can cleanly remove within the hashtable enumeration - // function. - void - RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration); - // Removes all service worker registrations that matches the given pattern. void RemoveAllRegistrations(OriginAttributesPattern* aPattern); From 435b823b835a3e442a524c35aa5439a455abd6b7 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 22 Feb 2016 12:50:57 +0000 Subject: [PATCH 041/252] Bug 1243808 - Allow modules to be compiled off main thread r=shu --- js/src/builtin/ModuleObject.cpp | 68 ++++- js/src/builtin/ModuleObject.h | 15 +- js/src/frontend/BytecodeCompiler.cpp | 24 +- js/src/frontend/BytecodeCompiler.h | 6 +- js/src/jit-test/tests/modules/global-scope.js | 32 +++ .../tests/modules/off-thread-compile.js | 16 ++ js/src/jsapi.cpp | 4 +- js/src/shell/js.cpp | 116 +++++++- js/src/vm/GlobalObject.cpp | 15 + js/src/vm/GlobalObject.h | 29 +- js/src/vm/HelperThreads.cpp | 257 +++++++++++++----- js/src/vm/HelperThreads.h | 44 ++- js/src/vm/Stack.cpp | 1 + 13 files changed, 526 insertions(+), 101 deletions(-) create mode 100644 js/src/jit-test/tests/modules/global-scope.js create mode 100644 js/src/jit-test/tests/modules/off-thread-compile.js diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index c879fadb86a..eefe54f6e05 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -109,7 +109,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle global) } /* static */ ImportEntryObject* -ImportEntryObject::create(JSContext* cx, +ImportEntryObject::create(ExclusiveContext* cx, HandleAtom moduleRequest, HandleAtom importName, HandleAtom localName) @@ -181,7 +181,7 @@ StringOrNullValue(JSString* maybeString) } /* static */ ExportEntryObject* -ExportEntryObject::create(JSContext* cx, +ExportEntryObject::create(ExclusiveContext* cx, HandleAtom maybeExportName, HandleAtom maybeModuleRequest, HandleAtom maybeImportName, @@ -699,6 +699,62 @@ ModuleObject::initImportExportData(HandleArrayObject requestedModules, initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries)); } +static bool +FreezeObjectProperty(JSContext* cx, HandleNativeObject obj, uint32_t slot) +{ + RootedObject property(cx, &obj->getSlot(slot).toObject()); + return FreezeObject(cx, property); +} + +/* static */ bool +ModuleObject::FreezeArrayProperties(JSContext* cx, HandleModuleObject self) +{ + return FreezeObjectProperty(cx, self, RequestedModulesSlot) && + FreezeObjectProperty(cx, self, ImportEntriesSlot) && + FreezeObjectProperty(cx, self, LocalExportEntriesSlot) && + FreezeObjectProperty(cx, self, IndirectExportEntriesSlot) && + FreezeObjectProperty(cx, self, StarExportEntriesSlot); +} + +static inline void +AssertObjectPropertyFrozen(JSContext* cx, HandleNativeObject obj, uint32_t slot) +{ +#ifdef DEBUG + bool frozen = false; + RootedObject property(cx, &obj->getSlot(slot).toObject()); + MOZ_ALWAYS_TRUE(TestIntegrityLevel(cx, property, IntegrityLevel::Frozen, &frozen)); + MOZ_ASSERT(frozen); +#endif +} + +/* static */ inline void +ModuleObject::AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self) +{ + AssertObjectPropertyFrozen(cx, self, RequestedModulesSlot); + AssertObjectPropertyFrozen(cx, self, ImportEntriesSlot); + AssertObjectPropertyFrozen(cx, self, LocalExportEntriesSlot); + AssertObjectPropertyFrozen(cx, self, IndirectExportEntriesSlot); + AssertObjectPropertyFrozen(cx, self, StarExportEntriesSlot); +} + +inline static void +AssertModuleScopesMatch(ModuleObject* module) +{ + MOZ_ASSERT(IsStaticGlobalLexicalScope(module->enclosingStaticScope())); + MOZ_ASSERT(module->initialEnvironment().enclosingScope().as().staticScope() == + module->enclosingStaticScope()); +} + +void +ModuleObject::fixScopesAfterCompartmentMerge(JSContext* cx) +{ + AssertModuleScopesMatch(this); + Rooted lexicalScope(cx, &script()->global().lexicalScope()); + setReservedSlot(StaticScopeSlot, ObjectValue(lexicalScope->staticBlock())); + initialEnvironment().setEnclosingScope(lexicalScope); + AssertModuleScopesMatch(this); +} + bool ModuleObject::hasScript() const { @@ -775,6 +831,8 @@ ModuleObject::noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, Han /* static */ bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self) { + AssertArrayPropertiesFrozen(cx, self); + FunctionDeclarationVector* funDecls = self->functionDeclarations(); if (!funDecls) { JS_ReportError(cx, "Module function declarations have already been instantiated"); @@ -811,6 +869,8 @@ ModuleObject::setEvaluated() /* static */ bool ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval) { + AssertArrayPropertiesFrozen(cx, self); + RootedScript script(cx, self->script()); RootedModuleEnvironmentObject scope(cx, self->environment()); if (!scope) { @@ -902,7 +962,7 @@ js::InitModuleClasses(JSContext* cx, HandleObject obj) /////////////////////////////////////////////////////////////////////////// // ModuleBuilder -ModuleBuilder::ModuleBuilder(JSContext* cx, HandleModuleObject module) +ModuleBuilder::ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module) : cx_(cx), module_(cx, module), requestedModules_(cx, AtomVector(cx)), @@ -1185,8 +1245,6 @@ ArrayObject* ModuleBuilder::createArray(const GCVector& vector) array->setDenseInitializedLength(length); for (uint32_t i = 0; i < length; i++) array->initDenseElement(i, MakeElementValue(vector[i])); - if (!JS_FreezeObject(cx_, array)) - return nullptr; return array; } diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 640802a2166..5971d486d9a 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -43,9 +43,9 @@ class ImportEntryObject : public NativeObject }; static const Class class_; - static JSObject* initClass(JSContext* cx, HandleObject obj); + static JSObject* initClass(ExclusiveContext* cx, HandleObject obj); static bool isInstance(HandleValue value); - static ImportEntryObject* create(JSContext* cx, + static ImportEntryObject* create(ExclusiveContext* cx, HandleAtom moduleRequest, HandleAtom importName, HandleAtom localName); @@ -70,9 +70,9 @@ class ExportEntryObject : public NativeObject }; static const Class class_; - static JSObject* initClass(JSContext* cx, HandleObject obj); + static JSObject* initClass(ExclusiveContext* cx, HandleObject obj); static bool isInstance(HandleValue value); - static ExportEntryObject* create(JSContext* cx, + static ExportEntryObject* create(ExclusiveContext* cx, HandleAtom maybeExportName, HandleAtom maybeModuleRequest, HandleAtom maybeImportName, @@ -232,6 +232,9 @@ class ModuleObject : public NativeObject HandleArrayObject localExportEntries, HandleArrayObject indiretExportEntries, HandleArrayObject starExportEntries); + static bool FreezeArrayProperties(JSContext* cx, HandleModuleObject self); + static void AssertArrayPropertiesFrozen(JSContext* cx, HandleModuleObject self); + void fixScopesAfterCompartmentMerge(JSContext* cx); JSScript* script() const; JSObject* enclosingStaticScope() const; @@ -273,7 +276,7 @@ class ModuleObject : public NativeObject class MOZ_STACK_CLASS ModuleBuilder { public: - explicit ModuleBuilder(JSContext* cx, HandleModuleObject module); + explicit ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module); bool processImport(frontend::ParseNode* pn); bool processExport(frontend::ParseNode* pn); @@ -296,7 +299,7 @@ class MOZ_STACK_CLASS ModuleBuilder using RootedImportEntryVector = JS::Rooted; using RootedExportEntryVector = JS::Rooted; - JSContext* cx_; + ExclusiveContext* cx_; RootedModuleObject module_; RootedAtomVector requestedModules_; RootedAtomVector importedBoundNames_; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 3ea9abe339f..eade3ffa7c6 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -576,7 +576,7 @@ ModuleObject* BytecodeCompiler::compileModule() module->init(script); - ModuleBuilder builder(cx->asJSContext(), module); + ModuleBuilder builder(cx, module); ParseNode* pn = parser->standaloneModule(module, builder); if (!pn) return nullptr; @@ -759,20 +759,32 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco } ModuleObject* -frontend::CompileModule(JSContext* cx, HandleObject obj, - const ReadOnlyCompileOptions& optionsInput, - SourceBufferHolder& srcBuf) +frontend::CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& optionsInput, + SourceBufferHolder& srcBuf, LifoAlloc* alloc) { MOZ_ASSERT(srcBuf.get()); + MOZ_ASSERT(cx->isJSContext() == (alloc == nullptr)); + + if (!alloc) + alloc = &cx->asJSContext()->tempLifoAlloc(); CompileOptions options(cx, optionsInput); options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code. options.setIsRunOnce(true); Rooted staticScope(cx, &cx->global()->lexicalScope().staticBlock()); - BytecodeCompiler compiler(cx, &cx->tempLifoAlloc(), options, srcBuf, staticScope, + BytecodeCompiler compiler(cx, alloc, options, srcBuf, staticScope, TraceLogger_ParserCompileModule); - return compiler.compileModule(); + RootedModuleObject module(cx, compiler.compileModule()); + if (!module) + return nullptr; + + // This happens in GlobalHelperThreadState::finishModuleParseTask() when a + // module is compiled off main thread. + if (cx->isJSContext() && !ModuleObject::FreezeArrayProperties(cx->asJSContext(), module)) + return nullptr; + + return module; } bool diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 258149477fb..dac0ce0df6c 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -32,9 +32,9 @@ CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, SourceCompressionTask* extraSct = nullptr, ScriptSourceObject** sourceObjectOut = nullptr); -ModuleObject * -CompileModule(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, - SourceBufferHolder &srcBuf); +ModuleObject* +CompileModule(ExclusiveContext *cx, const ReadOnlyCompileOptions &options, + SourceBufferHolder &srcBuf, LifoAlloc* alloc = nullptr); bool CompileLazyFunction(JSContext* cx, Handle lazy, const char16_t* chars, size_t length); diff --git a/js/src/jit-test/tests/modules/global-scope.js b/js/src/jit-test/tests/modules/global-scope.js new file mode 100644 index 00000000000..90a9f7026b1 --- /dev/null +++ b/js/src/jit-test/tests/modules/global-scope.js @@ -0,0 +1,32 @@ +// Test interaction with global object and global lexical scope. + +function parseAndEvaluate(source) { + let m = parseModule(source); + m.declarationInstantiation(); + return m.evaluation(); +} + +var x = 1; +assertEq(parseAndEvaluate("let r = x; x = 2; r"), 1); +assertEq(x, 2); + +let y = 3; +assertEq(parseAndEvaluate("let r = y; y = 4; r"), 3); +assertEq(y, 4); + +if (helperThreadCount() == 0) + quit(); + +function offThreadParseAndEvaluate(source) { + offThreadCompileModule(source); + let m = finishOffThreadModule(); + print("compiled"); + m.declarationInstantiation(); + return m.evaluation(); +} + +assertEq(offThreadParseAndEvaluate("let r = x; x = 5; r"), 2); +assertEq(x, 5); + +assertEq(offThreadParseAndEvaluate("let r = y; y = 6; r"), 4); +assertEq(y, 6); diff --git a/js/src/jit-test/tests/modules/off-thread-compile.js b/js/src/jit-test/tests/modules/off-thread-compile.js new file mode 100644 index 00000000000..8d17d4a749f --- /dev/null +++ b/js/src/jit-test/tests/modules/off-thread-compile.js @@ -0,0 +1,16 @@ +// Test off thread module compilation. + +if (helperThreadCount() == 0) + quit(); + +load(libdir + "asserts.js"); +load(libdir + "dummyModuleResolveHook.js"); + +function offThreadParseAndEvaluate(source) { + offThreadCompileModule(source); + let m = finishOffThreadModule(); + m.declarationInstantiation(); + return m.evaluation(); +} + +offThreadParseAndEvaluate("export let x = 2 * 3;"); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 730ba000921..0848bddb163 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4133,11 +4133,11 @@ JS::FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token) RootedScript script(maybecx); { AutoLastFrameCheck lfc(maybecx); - script = HelperThreadState().finishParseTask(maybecx, rt, token); + script = HelperThreadState().finishScriptParseTask(maybecx, rt, token); } return script; } else { - return HelperThreadState().finishParseTask(maybecx, rt, token); + return HelperThreadState().finishScriptParseTask(maybecx, rt, token); } } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 001f2eaf99e..c8179eae359 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3424,7 +3424,6 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp) return false; } - RootedObject global(cx, JS::CurrentGlobalOrNull(cx)); JSFlatString* scriptContents = args[0].toString()->ensureFlat(cx); if (!scriptContents) return false; @@ -3456,7 +3455,7 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp) SourceBufferHolder srcBuf(chars, scriptContents->length(), SourceBufferHolder::NoOwnership); - RootedObject module(cx, frontend::CompileModule(cx, global, options, srcBuf)); + RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf)); if (!module) return false; @@ -3790,6 +3789,109 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp) return JS_ExecuteScript(cx, script, args.rval()); } +static bool +CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData) +{ + MOZ_ASSERT(JS::CanCompileOffThread(cx, options, length)); + return StartOffThreadParseModule(cx, options, chars, length, callback, callbackData); +} + +static JSObject* +FinishOffThreadModule(JSContext* maybecx, JSRuntime* rt, void* token) +{ + MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt)); + return HelperThreadState().finishModuleParseTask(maybecx, rt, token); +} + +static bool +OffThreadCompileModule(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() != 1 || !args[0].isString()) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, + "offThreadCompileModule"); + return false; + } + + JSAutoByteString fileNameBytes; + CompileOptions options(cx); + options.setIntroductionType("js shell offThreadCompileModule") + .setFileAndLine("", 1); + options.setIsRunOnce(true) + .setSourceIsLazy(false); + options.forceAsync = true; + + JSString* scriptContents = args[0].toString(); + AutoStableStringChars stableChars(cx); + if (!stableChars.initTwoByte(cx, scriptContents)) + return false; + + size_t length = scriptContents->length(); + const char16_t* chars = stableChars.twoByteRange().start().get(); + + // Make sure we own the string's chars, so that they are not freed before + // the compilation is finished. + ScopedJSFreePtr ownedChars; + if (stableChars.maybeGiveOwnershipToCaller()) { + ownedChars = const_cast(chars); + } else { + char16_t* copy = cx->pod_malloc(length); + if (!copy) + return false; + + mozilla::PodCopy(copy, chars, length); + ownedChars = copy; + chars = copy; + } + + if (!JS::CanCompileOffThread(cx, options, length)) { + JS_ReportError(cx, "cannot compile code on worker thread"); + return false; + } + + if (!offThreadState.startIfIdle(cx, ownedChars)) { + JS_ReportError(cx, "called offThreadCompileModule without receiving prior off-thread " + "compilation"); + return false; + } + + if (!CompileOffThreadModule(cx, options, chars, length, + OffThreadCompileScriptCallback, nullptr)) + { + offThreadState.abandon(cx); + return false; + } + + args.rval().setUndefined(); + return true; +} + +static bool +FinishOffThreadModule(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + JSRuntime* rt = cx->runtime(); + if (OffThreadParsingMustWaitForGC(rt)) + gc::AutoFinishGC finishgc(rt); + + void* token = offThreadState.waitUntilDone(cx); + if (!token) { + JS_ReportError(cx, "called finishOffThreadModule when no compilation is pending"); + return false; + } + + RootedObject module(cx, FinishOffThreadModule(cx, rt, token)); + if (!module) + return false; + + args.rval().setObject(*module); + return true; +} + struct MOZ_RAII FreeOnReturn { JSContext* cx; @@ -5205,6 +5307,16 @@ static const JSFunctionSpecWithHelp shell_functions[] = { " throw the appropriate exception; otherwise, run the script and return\n" " its value."), + JS_FN_HELP("offThreadCompileModule", OffThreadCompileModule, 1, 0, +"offThreadCompileModule(code)", +" Compile |code| on a helper thread. To wait for the compilation to finish\n" +" and get the module object, call |finishOffThreadModule|."), + + JS_FN_HELP("finishOffThreadModule", FinishOffThreadModule, 0, 0, +"finishOffThreadModule()", +" Wait for off-thread compilation to complete. If an error occurred,\n" +" throw the appropriate exception; otherwise, return the module object"), + JS_FN_HELP("timeout", Timeout, 1, 0, "timeout([seconds], [func])", " Get/Set the limit in seconds for the execution time for the current context.\n" diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 997c344a0fe..00dd209354f 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -745,3 +745,18 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle global, holder->setSlot(shape->slot(), value); return true; } + +/* static */ bool +GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle global) +{ + if (global->getSlot(MODULE_PROTO).isUndefined()) { + MOZ_ASSERT(global->getSlot(IMPORT_ENTRY_PROTO).isUndefined() && + global->getSlot(EXPORT_ENTRY_PROTO).isUndefined()); + if (!js::InitModuleClasses(cx, global)) + return false; + } + MOZ_ASSERT(global->getSlot(MODULE_PROTO).isObject() && + global->getSlot(IMPORT_ENTRY_PROTO).isObject() && + global->getSlot(EXPORT_ENTRY_PROTO).isObject()); + return true; +} diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 55358898aaf..e0621f031ec 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -469,16 +469,39 @@ class GlobalObject : public NativeObject return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto); } + static bool ensureModulePrototypesCreated(JSContext *cx, Handle global); + + JSObject* maybeGetModulePrototype() { + Value value = getSlot(MODULE_PROTO); + return value.isUndefined() ? nullptr : &value.toObject(); + } + + JSObject* maybeGetImportEntryPrototype() { + Value value = getSlot(IMPORT_ENTRY_PROTO); + return value.isUndefined() ? nullptr : &value.toObject(); + } + + JSObject* maybeGetExportEntryPrototype() { + Value value = getSlot(EXPORT_ENTRY_PROTO); + return value.isUndefined() ? nullptr : &value.toObject(); + } + JSObject* getModulePrototype() { - return &getSlot(MODULE_PROTO).toObject(); + JSObject* proto = maybeGetModulePrototype(); + MOZ_ASSERT(proto); + return proto; } JSObject* getImportEntryPrototype() { - return &getSlot(IMPORT_ENTRY_PROTO).toObject(); + JSObject* proto = maybeGetImportEntryPrototype(); + MOZ_ASSERT(proto); + return proto; } JSObject* getExportEntryPrototype() { - return &getSlot(EXPORT_ENTRY_PROTO).toObject(); + JSObject* proto = maybeGetExportEntryPrototype(); + MOZ_ASSERT(proto); + return proto; } static JSFunction* diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index f9607486b38..86d21a61165 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -195,10 +195,10 @@ static const JSClass parseTaskGlobalClass = { JS_GlobalObjectTraceHook }; -ParseTask::ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSContext* initCx, - const char16_t* chars, size_t length, +ParseTask::ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + JSContext* initCx, const char16_t* chars, size_t length, JS::OffThreadCompileCallback callback, void* callbackData) - : cx(cx), options(initCx), chars(chars), length(length), + : kind(kind), cx(cx), options(initCx), chars(chars), length(length), alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), exclusiveContextGlobal(initCx->runtime(), exclusiveContextGlobal), callback(callback), callbackData(callbackData), @@ -244,6 +244,52 @@ ParseTask::~ParseTask() js_delete(errors[i]); } +ScriptParseTask::ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + JSContext* initCx, const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData) + : ParseTask(ParseTaskKind::Script, cx, exclusiveContextGlobal, initCx, chars, length, callback, + callbackData) +{ +} + +void +ScriptParseTask::parse() +{ + SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); + + // ! WARNING WARNING WARNING ! + // + // See comment in Parser::bindLexical about optimizing global lexical + // bindings. If we start optimizing them, passing in task->cx's + // global lexical scope would be incorrect! + // + // ! WARNING WARNING WARNING ! + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + Rooted staticScope(cx, &globalLexical->staticBlock()); + script = frontend::CompileScript(cx, &alloc, globalLexical, staticScope, nullptr, + options, srcBuf, + /* source_ = */ nullptr, + /* extraSct = */ nullptr, + /* sourceObjectOut = */ sourceObject.address()); +} + +ModuleParseTask::ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + JSContext* initCx, const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData) + : ParseTask(ParseTaskKind::Module, cx, exclusiveContextGlobal, initCx, chars, length, callback, + callbackData) +{ +} + +void +ModuleParseTask::parse() +{ + SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); + ModuleObject* module = frontend::CompileModule(cx, options, srcBuf, &alloc); + if (module) + script = module->script(); +} + void js::CancelOffThreadParses(JSRuntime* rt) { @@ -285,7 +331,8 @@ js::CancelOffThreadParses(JSRuntime* rt) if (task->runtimeMatches(rt)) { found = true; AutoUnlockHelperThreadState unlock; - HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task); + HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task->kind, + task); } } if (!found) @@ -319,7 +366,7 @@ EnsureConstructor(JSContext* cx, Handle global, JSProtoKey key) // Initialize all classes potentially created during parsing for use in parser // data structures, template objects, &c. static bool -EnsureParserCreatedClasses(JSContext* cx) +EnsureParserCreatedClasses(JSContext* cx, ParseTaskKind kind) { Handle global = cx->global(); @@ -338,18 +385,15 @@ EnsureParserCreatedClasses(JSContext* cx) if (!GlobalObject::initStarGenerators(cx, global)) return false; // needed by function*() {} and generator comprehensions + if (kind == ParseTaskKind::Module && !GlobalObject::ensureModulePrototypesCreated(cx, global)) + return false; + return true; } -bool -js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, - JS::OffThreadCompileCallback callback, void* callbackData) +static JSObject* +CreateGlobalForOffThreadParse(JSContext* cx, ParseTaskKind kind, const gc::AutoSuppressGC& nogc) { - // Suppress GC so that calls below do not trigger a new incremental GC - // which could require barriers on the atoms compartment. - gc::AutoSuppressGC suppress(cx); - JSCompartment* currentCompartment = cx->compartment(); JS::CompartmentOptions compartmentOptions(currentCompartment->creationOptions(), @@ -367,21 +411,60 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio JSObject* global = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr, JS::FireOnNewGlobalHook, compartmentOptions); if (!global) - return false; + return nullptr; JS_SetCompartmentPrincipals(global->compartment(), currentCompartment->principals()); // Initialize all classes required for parsing while still on the main // thread, for both the target and the new global so that prototype // pointers can be changed infallibly after parsing finishes. - if (!EnsureParserCreatedClasses(cx)) - return false; + if (!EnsureParserCreatedClasses(cx, kind)) + return nullptr; { AutoCompartment ac(cx, global); - if (!EnsureParserCreatedClasses(cx)) - return false; + if (!EnsureParserCreatedClasses(cx, kind)) + return nullptr; } + return global; +} + +static bool +QueueOffThreadParseTask(JSContext* cx, ParseTask* task) +{ + if (OffThreadParsingMustWaitForGC(cx->runtime())) { + AutoLockHelperThreadState lock; + if (!HelperThreadState().parseWaitingOnGC().append(task)) { + ReportOutOfMemory(cx); + return false; + } + } else { + AutoLockHelperThreadState lock; + if (!HelperThreadState().parseWorklist().append(task)) { + ReportOutOfMemory(cx); + return false; + } + + task->activate(cx->runtime()); + HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER); + } + + return true; +} + +bool +js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData) +{ + // Suppress GC so that calls below do not trigger a new incremental GC + // which could require barriers on the atoms compartment. + gc::AutoSuppressGC nogc(cx); + + JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Script, nogc); + if (!global) + return false; + ScopedJSDeletePtr helpercx( cx->new_(cx->runtime(), (PerThreadData*) nullptr, ExclusiveContext::Context_Exclusive)); @@ -389,32 +472,50 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio return false; ScopedJSDeletePtr task( - cx->new_(helpercx.get(), global, cx, chars, length, - callback, callbackData)); + cx->new_(helpercx.get(), global, cx, chars, length, + callback, callbackData)); if (!task) return false; helpercx.forget(); - if (!task->init(cx, options)) + if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task)) return false; - if (OffThreadParsingMustWaitForGC(cx->runtime())) { - AutoLockHelperThreadState lock; - if (!HelperThreadState().parseWaitingOnGC().append(task.get())) { - ReportOutOfMemory(cx); - return false; - } - } else { - AutoLockHelperThreadState lock; - if (!HelperThreadState().parseWorklist().append(task.get())) { - ReportOutOfMemory(cx); - return false; - } + task.forget(); - task->activate(cx->runtime()); - HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER); - } + return true; +} + +bool +js::StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData) +{ + // Suppress GC so that calls below do not trigger a new incremental GC + // which could require barriers on the atoms compartment. + gc::AutoSuppressGC nogc(cx); + + JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Module, nogc); + if (!global) + return false; + + ScopedJSDeletePtr helpercx( + cx->new_(cx->runtime(), (PerThreadData*) nullptr, + ExclusiveContext::Context_Exclusive)); + if (!helpercx) + return false; + + ScopedJSDeletePtr task( + cx->new_(helpercx.get(), global, cx, chars, length, + callback, callbackData)); + if (!task) + return false; + + helpercx.forget(); + + if (!task->init(cx, options) || !QueueOffThreadParseTask(cx, task)) + return false; task.forget(); @@ -1015,7 +1116,8 @@ LeaveParseTaskZone(JSRuntime* rt, ParseTask* task) } JSScript* -GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token) +GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind, + void* token) { ScopedJSDeletePtr parseTask; @@ -1033,6 +1135,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void } } MOZ_ASSERT(parseTask); + MOZ_ASSERT(parseTask->kind == kind); if (!maybecx) { LeaveParseTaskZone(rt, parseTask); @@ -1045,7 +1148,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void // Make sure we have all the constructors we need for the prototype // remapping below, since we can't GC while that's happening. Rooted global(cx, &cx->global()->as()); - if (!EnsureParserCreatedClasses(cx)) { + if (!EnsureParserCreatedClasses(cx, kind)) { LeaveParseTaskZone(rt, parseTask); return nullptr; } @@ -1091,6 +1194,34 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void return script; } +JSScript* +GlobalHelperThreadState::finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token) +{ + JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Script, token); + MOZ_ASSERT_IF(script, script->isGlobalCode()); + return script; +} + +JSObject* +GlobalHelperThreadState::finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token) +{ + JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Module, token); + if (!script) + return nullptr; + + MOZ_ASSERT(script->module()); + if (!maybecx) + return nullptr; + + JSContext* cx = maybecx; + RootedModuleObject module(cx, script->module()); + module->fixScopesAfterCompartmentMerge(cx); + if (!ModuleObject::FreezeArrayProperties(cx, module)) + return nullptr; + + return module; +} + JSObject* GlobalObject::getStarGeneratorFunctionPrototype() { @@ -1118,8 +1249,13 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* par // Generator functions don't have Function.prototype as prototype but a // different function object, so the IdentifyStandardPrototype trick // below won't work. Just special-case it. - JSObject* parseTaskStarGenFunctionProto = - parseTask->exclusiveContextGlobal->as().getStarGeneratorFunctionPrototype(); + GlobalObject* parseGlobal = &parseTask->exclusiveContextGlobal->as(); + JSObject* parseTaskStarGenFunctionProto = parseGlobal->getStarGeneratorFunctionPrototype(); + + // Module objects don't have standard prototypes either. + JSObject* moduleProto = parseGlobal->maybeGetModulePrototype(); + JSObject* importEntryProto = parseGlobal->maybeGetImportEntryPrototype(); + JSObject* exportEntryProto = parseGlobal->maybeGetExportEntryPrototype(); // Point the prototypes of any objects in the script's compartment to refer // to the corresponding prototype in the new compartment. This will briefly @@ -1134,21 +1270,24 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* par JSObject* protoObj = proto.toObject(); JSObject* newProto; - if (protoObj == parseTaskStarGenFunctionProto) { - newProto = global->getStarGeneratorFunctionPrototype(); - } else { - JSProtoKey key = JS::IdentifyStandardPrototype(protoObj); - if (key == JSProto_Null) - continue; - + JSProtoKey key = JS::IdentifyStandardPrototype(protoObj); + if (key != JSProto_Null) { MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array || key == JSProto_Function || key == JSProto_RegExp || key == JSProto_Iterator); - newProto = GetBuiltinPrototypePure(global, key); + } else if (protoObj == parseTaskStarGenFunctionProto) { + newProto = global->getStarGeneratorFunctionPrototype(); + } else if (protoObj == moduleProto) { + newProto = global->getModulePrototype(); + } else if (protoObj == importEntryProto) { + newProto = global->getImportEntryPrototype(); + } else if (protoObj == exportEntryProto) { + newProto = global->getExportEntryPrototype(); + } else { + continue; } - MOZ_ASSERT(newProto); group->setProtoUnchecked(TaggedProto(newProto)); } } @@ -1389,25 +1528,7 @@ HelperThread::handleParseWorkload() AutoUnlockHelperThreadState unlock; PerThreadData::AutoEnterRuntime enter(threadData.ptr(), task->exclusiveContextGlobal->runtimeFromAnyThread()); - SourceBufferHolder srcBuf(task->chars, task->length, - SourceBufferHolder::NoOwnership); - - // ! WARNING WARNING WARNING ! - // - // See comment in Parser::bindLexical about optimizing global lexical - // bindings. If we start optimizing them, passing in task->cx's - // global lexical scope would be incorrect! - // - // ! WARNING WARNING WARNING ! - ExclusiveContext* parseCx = task->cx; - Rooted globalLexical(parseCx, &parseCx->global()->lexicalScope()); - Rooted staticScope(parseCx, &globalLexical->staticBlock()); - task->script = frontend::CompileScript(parseCx, &task->alloc, - globalLexical, staticScope, nullptr, - task->options, srcBuf, - /* source_ = */ nullptr, - /* extraSct = */ nullptr, - /* sourceObjectOut = */ task->sourceObject.address()); + task->parse(); } // The callback is invoked while we are still off the main thread. diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index 5eae2d21eb5..76fccf8f560 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -37,6 +37,12 @@ namespace wasm { typedef Vector IonCompileTaskVector; } // namespace wasm +enum class ParseTaskKind +{ + Script, + Module +}; + // Per-process state for off thread work items. class GlobalHelperThreadState { @@ -219,6 +225,11 @@ class GlobalHelperThreadState return bool(numWasmFailedJobs); } + JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind, void* token); + void mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask, + Handle global, + JSCompartment* dest); + private: /* * Number of wasm jobs that encountered failure for the active module. @@ -227,10 +238,8 @@ class GlobalHelperThreadState uint32_t numWasmFailedJobs; public: - JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token); - void mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask, - Handle global, - JSCompartment* dest); + JSScript* finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token); + JSObject* finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token); bool compressionInProgress(SourceCompressionTask* task); SourceCompressionTask* compressionTaskForSource(ScriptSource* ss); @@ -410,6 +419,11 @@ StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::OffThreadCompileCallback callback, void* callbackData); +bool +StartOffThreadParseModule(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData); + /* * Called at the end of GC to enqueue any Parse tasks that were waiting on an * atoms-zone GC to finish. @@ -463,6 +477,7 @@ class MOZ_RAII AutoUnlockHelperThreadState struct ParseTask { + ParseTaskKind kind; ExclusiveContext* cx; OwningCompileOptions options; const char16_t* chars; @@ -490,19 +505,36 @@ struct ParseTask bool overRecursed; bool outOfMemory; - ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSContext* initCx, const char16_t* chars, size_t length, JS::OffThreadCompileCallback callback, void* callbackData); bool init(JSContext* cx, const ReadOnlyCompileOptions& options); void activate(JSRuntime* rt); + virtual void parse() = 0; bool finish(JSContext* cx); bool runtimeMatches(JSRuntime* rt) { return exclusiveContextGlobal->runtimeFromAnyThread() == rt; } - ~ParseTask(); + virtual ~ParseTask(); +}; + +struct ScriptParseTask : public ParseTask +{ + ScriptParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + JSContext* initCx, const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData); + void parse() override; +}; + +struct ModuleParseTask : public ParseTask +{ + ModuleParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, + JSContext* initCx, const char16_t* chars, size_t length, + JS::OffThreadCompileCallback callback, void* callbackData); + void parse() override; }; // Return whether, if a new parse task was started, it would need to wait for diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 7559acc9ad2..f61d5ab330b 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -18,6 +18,7 @@ #include "js/GCAPI.h" #include "vm/Debugger.h" #include "vm/Opcodes.h" +#include "vm/ScopeObject.h" #include "jit/JitFrameIterator-inl.h" #include "vm/Interpreter-inl.h" From d178960151b8657ad17e9531713ae746f7459b47 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 22 Feb 2016 15:43:54 +0100 Subject: [PATCH 042/252] Bug 1248251 - We should not send the referrer when a link is open in a different container., r=ttaubert --- browser/base/content/nsContextMenu.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index c452f8a47de..af498a92005 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -981,11 +981,16 @@ nsContextMenu.prototype = { catch (e) { } } - let params = this._openLinkInParameters({ + let params = { allowMixedContent: persistAllowMixedContentInChildTab, - userContextId: parseInt(event.target.getAttribute('usercontextid')), - }); - openLinkIn(this.linkURL, "tab", params); + userContextId: parseInt(event.target.getAttribute('usercontextid')) + }; + + if (params.userContextId != this.principal.originAttributes.userContextId) { + params.noReferrer = true; + } + + openLinkIn(this.linkURL, "tab", this._openLinkInParameters(params)); }, // open URL in current tab From aaa1202c74492a165ab9828adf978c942725bbf5 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 22 Feb 2016 15:44:20 +0100 Subject: [PATCH 043/252] Bug 1248251 - We should not send the referrer when a link is open in a different container - part 2 - r=ttaubert --- .../base/content/test/referrer/browser.ini | 2 + ...ser_referrer_open_link_in_container_tab.js | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js diff --git a/browser/base/content/test/referrer/browser.ini b/browser/base/content/test/referrer/browser.ini index 05eb30c1440..0cf041f76bd 100644 --- a/browser/base/content/test/referrer/browser.ini +++ b/browser/base/content/test/referrer/browser.ini @@ -13,3 +13,5 @@ skip-if = os == 'linux' # Bug 1144816 [browser_referrer_open_link_in_window.js] skip-if = os == 'linux' # Bug 1145199 [browser_referrer_simple_click.js] +[browser_referrer_open_link_in_container_tab.js] +skip-if = os == 'linux' # Bug 1144816 diff --git a/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js b/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js new file mode 100644 index 00000000000..54b1c4cc9ab --- /dev/null +++ b/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js @@ -0,0 +1,50 @@ +// Tests referrer on context menu navigation - open link in new container tab. +// Selects "open link in new container tab" from the context menu. + +function getReferrerTest(aTestNumber) { + let test = _referrerTests[aTestNumber]; + if (test) { + // We want all the referrer tests to fail! + test.result = ""; + } + + return test; +} + +function startNewTabTestCase(aTestNumber) { + info("browser_referrer_open_link_in_container_tab: " + + getReferrerTestDescription(aTestNumber)); + contextMenuOpened(gTestWindow, "testlink").then(function(aContextMenu) { + someTabLoaded(gTestWindow).then(function(aNewTab) { + gTestWindow.gBrowser.selectedTab = aNewTab; + + checkReferrerAndStartNextTest(aTestNumber, null, aNewTab, + startNewTabTestCase); + }); + + let menu = gTestWindow.document.getElementById("context-openlinkinusercontext-menu"); + ok(menu && menu.firstChild, "The menu exists and it has a first child node."); + + let menupopup = menu.firstChild; + is(menupopup.nodeType, Node.ELEMENT_NODE, "We have a menupopup."); + ok(menupopup.firstChild, "We have a first container entry."); + + let firstContext = menupopup.firstChild; + is(firstContext.nodeType, Node.ELEMENT_NODE, "We have a first container entry."); + ok(firstContext.hasAttribute('usercontextid'), "We have a usercontextid value."); + + firstContext.doCommand(); + aContextMenu.hidePopup(); + }); +} + +function test() { + waitForExplicitFinish(); + + SpecialPowers.pushPrefEnv( + {set: [["privacy.userContext.enabled", true]]}, + function() { + requestLongerTimeout(10); // slowwww shutdown on e10s + startReferrerTest(startNewTabTestCase); + }); +} From 17e1daf377f88b02ad21e9632540ceabd1108cbd Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 8 Feb 2016 16:30:54 -0500 Subject: [PATCH 044/252] Bug 1188045 - Part 1: Move the definition of sandboxTarget::Instance() out-of-line; r=bobowen,glandium This is required so that delay-loading xul.dll works with clang-cl. --- .../sandbox/win/src/sandboxtarget/moz.build | 11 ++++++++++ .../win/src/sandboxtarget/sandboxTarget.cpp | 21 +++++++++++++++++++ .../win/src/sandboxtarget/sandboxTarget.h | 9 +++----- 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp diff --git a/security/sandbox/win/src/sandboxtarget/moz.build b/security/sandbox/win/src/sandboxtarget/moz.build index 4272ff7ae9a..27cc1d3c185 100644 --- a/security/sandbox/win/src/sandboxtarget/moz.build +++ b/security/sandbox/win/src/sandboxtarget/moz.build @@ -7,3 +7,14 @@ EXPORTS.mozilla += [ 'sandboxTarget.h', ] + +SOURCES += [ + 'sandboxTarget.cpp', +] + +LOCAL_INCLUDES += [ + '/security/sandbox/chromium', + '/security/sandbox/chromium-shim', +] + +FINAL_LIBRARY = 'xul' diff --git a/security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp b/security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp new file mode 100644 index 00000000000..a989b362556 --- /dev/null +++ b/security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#define TARGET_SANDBOX_EXPORTS +#include "sandboxTarget.h" + +namespace mozilla { + +// We need to define this function out of line so that clang-cl doesn't inline +// it. +/* static */ SandboxTarget* +SandboxTarget::Instance() +{ + static SandboxTarget sb; + return &sb; +} + +} diff --git a/security/sandbox/win/src/sandboxtarget/sandboxTarget.h b/security/sandbox/win/src/sandboxtarget/sandboxTarget.h index eee3f67169e..50ac15283e2 100644 --- a/security/sandbox/win/src/sandboxtarget/sandboxTarget.h +++ b/security/sandbox/win/src/sandboxtarget/sandboxTarget.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ @@ -9,6 +9,7 @@ #include +#include "mozilla/Assertions.h" #include "base/MissingBasicTypes.h" #include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/target_services.h" @@ -27,11 +28,7 @@ public: /** * Obtains a pointer to the singleton instance */ - static SandboxTarget* Instance() - { - static SandboxTarget sb; - return &sb; - } + static SandboxTarget* Instance(); /** * Used by the application to pass in the target services that provide certain From 41c6279a69c47abf755d5f9c0dd133566ebecfbe Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 22 Feb 2016 09:55:58 -0500 Subject: [PATCH 045/252] Bug 1188045 - Part 2: Delay-load xul.dll when built with clang-cl This reverts an earlier work-around for this issue. --- ipc/app/moz.build | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ipc/app/moz.build b/ipc/app/moz.build index 4598b1e4c9a..e6c443713e4 100644 --- a/ipc/app/moz.build +++ b/ipc/app/moz.build @@ -66,13 +66,10 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': 'sandbox_staticruntime_s', ] - # clang-cl can't deal with this delay-load due to bug 1188045 - # (also filed as https://llvm.org/bugs/show_bug.cgi?id=24291) - if not CONFIG['CLANG_CL']: - DELAYLOAD_DLLS += [ - 'nss3.dll', - 'xul.dll' - ] + DELAYLOAD_DLLS += [ + 'nss3.dll', + 'xul.dll' + ] DEFINES['HASH_NODE_ID_WITH_DEVICE_ID'] = 1; SOURCES += [ From 495269b3e86eadd995a7b7f37edda0b23c95b5ea Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Mon, 22 Feb 2016 16:48:20 +0100 Subject: [PATCH 046/252] Bug 1244062, Upgrade Firefox 47 to NSPR 4.12, final version numbers, no code changes, r=me --- configure.in | 2 +- nsprpub/TAG-INFO | 2 +- nsprpub/config/prdepend.h | 1 + nsprpub/pr/include/prinit.h | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.in b/configure.in index d4b8b9836e7..35e0865ed7d 100644 --- a/configure.in +++ b/configure.in @@ -53,7 +53,7 @@ dnl ======================================================== MOZJPEG=62 MOZPNG=10619 NSPR_VERSION=4 -NSPR_MINVER=4.11 +NSPR_MINVER=4.12 NSS_VERSION=3 dnl Set the minimum version of toolkit libs used by mozilla diff --git a/nsprpub/TAG-INFO b/nsprpub/TAG-INFO index bba2b1c70a9..af20a19405b 100644 --- a/nsprpub/TAG-INFO +++ b/nsprpub/TAG-INFO @@ -1 +1 @@ -NSPR_4_12_BETA2 +NSPR_4_12_RTM diff --git a/nsprpub/config/prdepend.h b/nsprpub/config/prdepend.h index e49e92677e3..6c66b37ca0f 100644 --- a/nsprpub/config/prdepend.h +++ b/nsprpub/config/prdepend.h @@ -10,3 +10,4 @@ */ #error "Do not include this header file." + diff --git a/nsprpub/pr/include/prinit.h b/nsprpub/pr/include/prinit.h index fa9a43e16e4..523c2b97fa4 100644 --- a/nsprpub/pr/include/prinit.h +++ b/nsprpub/pr/include/prinit.h @@ -31,11 +31,11 @@ PR_BEGIN_EXTERN_C ** The format of the version string is ** ".[.] []" */ -#define PR_VERSION "4.12 Beta" +#define PR_VERSION "4.12" #define PR_VMAJOR 4 #define PR_VMINOR 12 #define PR_VPATCH 0 -#define PR_BETA PR_TRUE +#define PR_BETA PR_FALSE /* ** PRVersionCheck From 4d78ccc2861ca9eefeb42ccc1ad9b08837ba3804 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Mon, 22 Feb 2016 15:56:54 +0000 Subject: [PATCH 047/252] Bug 1245176 - Ensure enough ballast space in BacktrackingAllocator::reifyAllocations. r=h4writer --- js/src/jit/BacktrackingAllocator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 7c10127f551..f608d044021 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -1938,6 +1938,8 @@ BacktrackingAllocator::reifyAllocations() LAllocation sourceAlloc = range->bundle()->allocation(); if (res != *alloc) { + if (!this->alloc().ensureBallast()) + return false; LMoveGroup* group = getInputMoveGroup(ins->toInstruction()); if (!group->addAfter(sourceAlloc, res, reg.type())) return false; From f733cd7dd17e791211a451fb280c4ac8a64f5a44 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Mon, 22 Feb 2016 15:56:54 +0000 Subject: [PATCH 048/252] Bug 1245416 - Ensure enough ballast space in jit::EliminateDeadResumePointOperands. r=h4writer --- js/src/jit/IonAnalysis.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 885767b9e98..8604fee3116 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -925,6 +925,9 @@ jit::EliminateDeadResumePointOperands(MIRGenerator* mir, MIRGraph& graph) continue; } + if (!graph.alloc().ensureBallast()) + return false; + // Store an optimized out magic value in place of all dead // resume point operands. Making any such substitution can in // general alter the interpreter's behavior, even though the From 50433e0e74efb7cc7e9c5233b045d04466d13291 Mon Sep 17 00:00:00 2001 From: Jeff Lu Date: Mon, 22 Feb 2016 17:00:10 +0100 Subject: [PATCH 049/252] Bug 864842 - Show error for browsing Windows drive without media, r=michal --- xpcom/io/nsLocalFileWin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 7a8a8ad6deb..e8b5c5be1d6 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -481,6 +481,7 @@ ConvertWinError(DWORD aWinErr) case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_DRIVE: + case ERROR_NOT_READY: rv = NS_ERROR_FILE_NOT_FOUND; break; case ERROR_ACCESS_DENIED: From ae0c88f5d0b73f67d43062909b4f8f800f6fb3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20N=C3=A4slund?= Date: Mon, 22 Feb 2016 07:50:16 -0600 Subject: [PATCH 050/252] Bug 1242196 - Use RadixSort for typed arrays. r=mrrrgn --- js/src/builtin/Sorting.js | 109 +++++++++++++++++++++++++++++++++++ js/src/builtin/TypedArray.js | 14 ++++- js/src/vm/GlobalObject.cpp | 1 + js/src/vm/SelfHosting.cpp | 35 +++++++++++ 4 files changed, 156 insertions(+), 3 deletions(-) diff --git a/js/src/builtin/Sorting.js b/js/src/builtin/Sorting.js index 1761f02099f..c35a399f0ac 100644 --- a/js/src/builtin/Sorting.js +++ b/js/src/builtin/Sorting.js @@ -43,6 +43,115 @@ function CountingSort(array, len, signed) { return array; } +// Helper for RadixSort +function ByteAtCol(x, pos) { + return (x >> (pos * 8)) & 0xFF; +} + +function SortByColumn(array, len, aux, col) { + const R = 256; + let counts = new List(); + + // |counts| is used to compute the starting index position for each key. + // Letting counts[0] always be 0, simplifies the transform step below. + // Example: + // + // Computing frequency counts for the input [1 2 1] gives: + // 0 1 2 3 ... (keys) + // 0 0 2 1 (frequencies) + // + // Transforming frequencies to indexes gives: + // 0 1 2 3 ... (keys) + // 0 0 2 3 (indexes) + for (let r = 0; r < R + 1; r++) { + counts[r] = 0; + } + // Compute frequency counts + for (let i = 0; i < len; i++) { + let val = array[i]; + let b = ByteAtCol(val, col); + counts[b + 1]++; + } + + // Transform counts to indices. + for (let r = 0; r < R; r++) { + counts[r+1] += counts[r]; + } + + // Distribute + for (let i = 0; i < len; i++) { + let val = array[i]; + let b = ByteAtCol(val, col); + aux[counts[b]++] = val; + } + + // Copy back + for (let i = 0; i < len; i++) { + array[i] = aux[i]; + } +} + +// Sorts integers and float32. |signed| is true for int16 and int32, |floating| +// is true for float32. +function RadixSort(array, len, nbytes, signed, floating, comparefn) { + + // Determined by performance testing. + if (len < 128) { + QuickSort(array, len, comparefn); + return array; + } + + let aux = new List(); + for (let i = 0; i < len; i++) { + aux[i] = 0; + } + + let view = array; + let signMask = 1 << nbytes * 8 - 1; + + // Preprocess + if (floating) { + view = new Int32Array(array.buffer); + + // Flip sign bit for positive numbers; flip all bits for negative + // numbers + for (let i = 0; i < len; i++) { + if (view[i] & signMask) { + view[i] ^= 0xFFFFFFFF; + } else { + view[i] ^= signMask + } + } + } else if (signed) { + // Flip sign bit + for (let i = 0; i < len; i++) { + view[i] ^= signMask + } + } + + // Sort + for (let col = 0; col < nbytes; col++) { + SortByColumn(view, len, aux, col); + } + + // Restore original bit representation + if (floating) { + for (let i = 0; i < len; i++) { + if (view[i] & signMask) { + view[i] ^= signMask; + } else { + view[i] ^= 0xFFFFFFFF; + } + } + } else if (signed) { + for (let i = 0; i < len; i++) { + view[i] ^= signMask + } + } + return array; +} + + // For sorting small arrays. function InsertionSort(array, from, to, comparefn) { let item, swap, i, j; diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index cb5280077d9..143aeb5b21f 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -987,15 +987,23 @@ function TypedArraySort(comparefn) { var len = TypedArrayLength(obj); if (comparefn === undefined) { + comparefn = TypedArrayCompare; // CountingSort doesn't invoke the comparefn if (IsUint8TypedArray(obj)) { return CountingSort(obj, len, false /* signed */); } else if (IsInt8TypedArray(obj)) { return CountingSort(obj, len, true /* signed */); + } else if (IsUint16TypedArray(obj)) { + return RadixSort(obj, len, 2 /* nbytes */, false /* signed */, false /* floating */, comparefn); + } else if (IsInt16TypedArray(obj)) { + return RadixSort(obj, len, 2 /* nbytes */, true /* signed */, false /* floating */, comparefn); + } else if (IsUint32TypedArray(obj)) { + return RadixSort(obj, len, 4 /* nbytes */, false /* signed */, false /* floating */, comparefn); + } else if (IsInt32TypedArray(obj)) { + return RadixSort(obj, len, 4 /* nbytes */, true /* signed */, false /* floating */, comparefn); + } else if (IsFloat32TypedArray(obj)) { + return RadixSort(obj, len, 4 /* nbytes */, true /* signed */, true /* floating */, comparefn); } - - comparefn = TypedArrayCompare; - } else { // To satisfy step 2 from TypedArray SortCompare described in 22.2.3.26 // the user supplied comparefn is wrapped. var wrappedCompareFn = comparefn; diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 00dd209354f..554f15fe98e 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -434,6 +434,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle globa return InitBareBuiltinCtor(cx, global, JSProto_Array) && InitBareBuiltinCtor(cx, global, JSProto_TypedArray) && InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) && + InitBareBuiltinCtor(cx, global, JSProto_Int32Array) && InitBareWeakMapCtor(cx, global) && InitStopIterationClass(cx, global) && InitSelfHostingCollectionIteratorFunctions(cx, global) && diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index e1c66f93dc9..045e5bfefc0 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -835,6 +835,36 @@ intrinsic_IsInt8TypedArray(JSContext* cx, unsigned argc, Value* vp) return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int8); } +static bool +intrinsic_IsUint16TypedArray(JSContext* cx, unsigned argc, Value* vp) +{ + return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint16); +} + +static bool +intrinsic_IsInt16TypedArray(JSContext* cx, unsigned argc, Value* vp) +{ + return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int16); +} + +static bool +intrinsic_IsUint32TypedArray(JSContext* cx, unsigned argc, Value* vp) +{ + return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Uint32); +} + +static bool +intrinsic_IsInt32TypedArray(JSContext* cx, unsigned argc, Value* vp) +{ + return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Int32); +} + +static bool +intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp) +{ + return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Float32); +} + static bool intrinsic_IsPossiblyWrappedTypedArray(JSContext* cx, unsigned argc, Value* vp) { @@ -1855,6 +1885,11 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("IsUint8TypedArray", intrinsic_IsUint8TypedArray, 1,0), JS_FN("IsInt8TypedArray", intrinsic_IsInt8TypedArray, 1,0), + JS_FN("IsUint16TypedArray", intrinsic_IsUint16TypedArray, 1,0), + JS_FN("IsInt16TypedArray", intrinsic_IsInt16TypedArray, 1,0), + JS_FN("IsUint32TypedArray", intrinsic_IsUint32TypedArray, 1,0), + JS_FN("IsInt32TypedArray", intrinsic_IsInt32TypedArray, 1,0), + JS_FN("IsFloat32TypedArray", intrinsic_IsFloat32TypedArray, 1,0), JS_INLINABLE_FN("IsTypedArray", intrinsic_IsInstanceOfBuiltin, 1,0, IntrinsicIsTypedArray), From cb57b5bc6a63b64057b0cef98f40ec0ea95e2df4 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 19 Feb 2016 16:09:16 -0500 Subject: [PATCH 051/252] Bug 831450 - No Range Requests against weak Etag r=mayhemer --- netwerk/protocol/http/nsHttpChannel.cpp | 7 ++-- netwerk/test/unit/test_range_requests.js | 41 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index c572a1d9168..dd487b8e397 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -2419,12 +2419,13 @@ nsHttpChannel::IsResumable(int64_t partialLen, int64_t contentLength, bool ignoreMissingPartialLen) const { bool hasContentEncoding = - mCachedResponseHead->PeekHeader(nsHttp::Content_Encoding) - != nullptr; + (mCachedResponseHead->PeekHeader(nsHttp::Content_Encoding) != nullptr); + const char *etag = mCachedResponseHead->PeekHeader(nsHttp::ETag); + bool hasWeakEtag = etag && !strncmp(etag, "W/", 2); return (partialLen < contentLength) && (partialLen > 0 || ignoreMissingPartialLen) && - !hasContentEncoding && + !hasContentEncoding && !hasWeakEtag && mCachedResponseHead->IsResumable() && !mCustomConditionalRequest && !mCachedResponseHead->NoStore(); diff --git a/netwerk/test/unit/test_range_requests.js b/netwerk/test/unit/test_range_requests.js index bb3bedeb29c..1850ade4389 100644 --- a/netwerk/test/unit/test_range_requests.js +++ b/netwerk/test/unit/test_range_requests.js @@ -338,6 +338,42 @@ function received_partial_8(request, data) { chan.asyncOpen2(new FailedChannelListener(testFinished, null, CL_EXPECT_LATE_FAILURE)); } +var case_9_request_no = 0; +function handler_9(metadata, response) { + switch (case_9_request_no) { + case 0: + do_check_false(metadata.hasHeader("Range")); + response.setHeader("Content-Type", "text/plain", false); + response.setHeader("ETag", "W/test9WeakEtag"); + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("Cache-Control", "max-age=360000"); + response.setHeader("Content-Length", "10"); + response.processAsync(); + response.bodyOutputStream.write(simpleBody.slice(0, 4), 4); + response.finish(); // truncated response + break; + case 1: + do_check_false(metadata.hasHeader("Range")); + response.setHeader("Content-Type", "text/plain", false); + response.setHeader("ETag", "W/test9WeakEtag"); + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("Cache-Control", "max-age=360000"); + response.setHeader("Content-Length", "10"); + response.processAsync(); + response.bodyOutputStream.write(simpleBody, 10); + response.finish(); // full response + break; + default: + response.setStatusLine(metadata.httpVersion, 404, "Not Found"); + } + case_9_request_no++; +} +function received_partial_9(request, data) { + do_check_eq(partial_data_length, data.length); + var chan = make_channel("http://localhost:" + port + "/test_9"); + chan.asyncOpen2(new ChannelListener(received_simple, null)); +} + // Simple mechanism to keep track of tests and stop the server var numTestsFinished = 0; function testFinished() { @@ -354,6 +390,7 @@ function run_test() { httpserver.registerPathHandler("/test_6", handler_6); httpserver.registerPathHandler("/test_7", handler_7); httpserver.registerPathHandler("/test_8", handler_8); + httpserver.registerPathHandler("/test_9", handler_9); httpserver.start(-1); port = httpserver.identity.primaryPort; @@ -389,5 +426,9 @@ function run_test() { var chan = make_channel("http://localhost:" + port + "/test_8"); chan.asyncOpen2(new MyListener(received_partial_8)); + // Case 9: check that weak etag is not used for a range request + var chan = make_channel("http://localhost:" + port + "/test_9"); + chan.asyncOpen2(new MyListener(received_partial_9)); + do_test_pending(); } From 052f1a0a29365803adeb9d9ab7f77f662b37da73 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 19 Feb 2016 15:21:28 -0500 Subject: [PATCH 052/252] Bug 739029 - null check a thread allocation in notifyaddrlistener r=bagder --- netwerk/system/win32/nsNotifyAddrListener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/system/win32/nsNotifyAddrListener.cpp b/netwerk/system/win32/nsNotifyAddrListener.cpp index 68d830ea88b..3fbb1270924 100644 --- a/netwerk/system/win32/nsNotifyAddrListener.cpp +++ b/netwerk/system/win32/nsNotifyAddrListener.cpp @@ -289,7 +289,7 @@ nsNotifyAddrListener::Shutdown(void) mShutdown = true; SetEvent(mCheckEvent); - nsresult rv = mThread->Shutdown(); + nsresult rv = mThread ? mThread->Shutdown() : NS_OK; // Have to break the cycle here, otherwise nsNotifyAddrListener holds // onto the thread and the thread holds onto the nsNotifyAddrListener From be115fc3c0a659259fdbeaa3d645c2cb207f84c6 Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Tue, 16 Feb 2016 14:34:25 -0500 Subject: [PATCH 053/252] Bug 1248027 - '#define FOO' should use an empty value, not '1'; r=glandium --- python/mozbuild/mozbuild/preprocessor.py | 2 +- python/mozbuild/mozbuild/test/test_preprocessor.py | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/python/mozbuild/mozbuild/preprocessor.py b/python/mozbuild/mozbuild/preprocessor.py index 8cc35cda711..e8aac7057cd 100644 --- a/python/mozbuild/mozbuild/preprocessor.py +++ b/python/mozbuild/mozbuild/preprocessor.py @@ -561,7 +561,7 @@ class Preprocessor: m = re.match('(?P\w+)(?:\s(?P.*))?', args, re.U) if not m: raise Preprocessor.Error(self, 'SYNTAX_DEF', args) - val = 1 + val = '' if m.group('value'): val = self.applyFilters(m.group('value')) try: diff --git a/python/mozbuild/mozbuild/test/test_preprocessor.py b/python/mozbuild/mozbuild/test/test_preprocessor.py index 44b5ddcb1fe..b0d0748afed 100644 --- a/python/mozbuild/mozbuild/test/test_preprocessor.py +++ b/python/mozbuild/mozbuild/test/test_preprocessor.py @@ -155,12 +155,12 @@ class TestPreprocessor(unittest.TestCase): def test_conditional_not_emptyval(self): self.do_include_compare([ '#define EMPTYVAL', - '#if !EMPTYVAL', + '#ifndef EMPTYVAL', 'FAIL', '#else', 'PASS', '#endif', - '#if EMPTYVAL', + '#ifdef EMPTYVAL', 'PASS', '#else', 'FAIL', @@ -458,6 +458,15 @@ class TestPreprocessor(unittest.TestCase): '#endif', ]) + def test_default_defines(self): + self.pp.handleCommandLine(["-DFOO"]) + self.do_include_pass([ + '#if FOO == 1', + 'PASS', + '#else', + 'FAIL', + ]) + def test_number_value_equals_defines(self): self.pp.handleCommandLine(["-DFOO=1000"]) self.do_include_pass([ From 0e50435796b232fdb1550ce979af836256a894b1 Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Thu, 18 Feb 2016 13:27:06 -0500 Subject: [PATCH 054/252] Bug 1249157: prefapi enums into class enums, explicit conversion, cleanup. r=bsmedberg MozReview-Commit-ID: nvvOD8ajV4 --- modules/libpref/Preferences.cpp | 2 +- modules/libpref/nsPrefBranch.cpp | 16 ++- modules/libpref/prefapi.cpp | 221 ++++++++++++++----------------- modules/libpref/prefapi.h | 107 +++++++++++---- modules/libpref/prefread.cpp | 36 ++--- modules/libpref/prefread.h | 2 +- 6 files changed, 221 insertions(+), 163 deletions(-) diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 5e613f9b43f..017f68ebadc 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -1315,7 +1315,7 @@ static nsresult pref_InitInitialObjects() // channel, telemetry is on by default, otherwise not. This is necessary // so that beta users who are testing final release builds don't flipflop // defaults. - if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) { + if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) { bool prerelease = false; #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT prerelease = true; diff --git a/modules/libpref/nsPrefBranch.cpp b/modules/libpref/nsPrefBranch.cpp index 6c341722e09..fe57c241dfa 100644 --- a/modules/libpref/nsPrefBranch.cpp +++ b/modules/libpref/nsPrefBranch.cpp @@ -127,7 +127,21 @@ NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval) { NS_ENSURE_ARG(aPrefName); const char *pref = getPrefName(aPrefName); - *_retval = PREF_GetPrefType(pref); + switch (PREF_GetPrefType(pref)) { + case PrefType::String: + *_retval = PREF_STRING; + break; + case PrefType::Int: + *_retval = PREF_INT; + break; + case PrefType::Bool: + *_retval = PREF_BOOL; + break; + case PrefType::Invalid: + default: + *_retval = PREF_INVALID; + break; + } return NS_OK; } diff --git a/modules/libpref/prefapi.cpp b/modules/libpref/prefapi.cpp index 1caa0538614..9d0c92f1e28 100644 --- a/modules/libpref/prefapi.cpp +++ b/modules/libpref/prefapi.cpp @@ -40,7 +40,7 @@ static void clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { PrefHashEntry *pref = static_cast(entry); - if (pref->flags & PREF_STRING) + if (pref->prefFlags.IsTypeString()) { if (pref->defaultPref.stringVal) PL_strfree(pref->defaultPref.stringVal); @@ -117,13 +117,7 @@ static char *ArenaStrDup(const char* str, PLArenaPool* aArena) /*---------------------------------------------------------------------------*/ -#define PREF_IS_LOCKED(pref) ((pref)->flags & PREF_LOCKED) -#define PREF_HAS_DEFAULT_VALUE(pref) ((pref)->flags & PREF_HAS_DEFAULT) -#define PREF_HAS_USER_VALUE(pref) ((pref)->flags & PREF_USERSET) -#define PREF_TYPE(pref) (PrefType)((pref)->flags & PREF_VALUETYPE_MASK) - static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type); - /* -- Privates */ struct CallbackNode { char* domain; @@ -249,7 +243,7 @@ PREF_SetCharPref(const char *pref_name, const char *value, bool set_default) PrefValue pref; pref.stringVal = (char*)value; - return pref_HashPref(pref_name, pref, PREF_STRING, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PrefType::String, set_default ? kPrefSetDefault : 0); } nsresult @@ -258,7 +252,7 @@ PREF_SetIntPref(const char *pref_name, int32_t value, bool set_default) PrefValue pref; pref.intVal = value; - return pref_HashPref(pref_name, pref, PREF_INT, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PrefType::Int, set_default ? kPrefSetDefault : 0); } nsresult @@ -267,7 +261,7 @@ PREF_SetBoolPref(const char *pref_name, bool value, bool set_default) PrefValue pref; pref.boolVal = value; - return pref_HashPref(pref_name, pref, PREF_BOOL, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PrefType::Bool, set_default ? kPrefSetDefault : 0); } enum WhichValue { DEFAULT_VALUE, USER_VALUE }; @@ -335,12 +329,12 @@ pref_savePrefs(PLDHashTable* aTable) // where we're getting our pref from PrefValue* sourcePref; - if (PREF_HAS_USER_VALUE(pref) && + if (pref->prefFlags.HasUserValue() && (pref_ValueChanged(pref->defaultPref, pref->userPref, - (PrefType) PREF_TYPE(pref)) || - !(pref->flags & PREF_HAS_DEFAULT) || - pref->flags & PREF_STICKY_DEFAULT)) { + pref->prefFlags.GetPrefType()) || + !(pref->prefFlags.HasDefault()) || + pref->prefFlags.HasStickyDefault())) { sourcePref = &pref->userPref; } else { // do not save default prefs that haven't changed @@ -348,15 +342,15 @@ pref_savePrefs(PLDHashTable* aTable) } // strings are in quotes! - if (pref->flags & PREF_STRING) { + if (pref->prefFlags.IsTypeString()) { prefValue = '\"'; str_escape(sourcePref->stringVal, prefValue); prefValue += '\"'; - } else if (pref->flags & PREF_INT) { + } else if (pref->prefFlags.IsTypeInt()) { prefValue.AppendInt(sourcePref->intVal); - } else if (pref->flags & PREF_BOOL) { + } else if (pref->prefFlags.IsTypeBool()) { prefValue = (sourcePref->boolVal) ? "true" : "false"; } @@ -389,14 +383,14 @@ GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref, settingValue = &aPref->defaultValue().get_PrefValue(); } - switch (aHashEntry->flags & PREF_VALUETYPE_MASK) { - case PREF_STRING: + switch (aHashEntry->prefFlags.GetPrefType()) { + case PrefType::String: *settingValue = nsDependentCString(value->stringVal); return; - case PREF_INT: + case PrefType::Int: *settingValue = value->intVal; return; - case PREF_BOOL: + case PrefType::Bool: *settingValue = !!value->boolVal; return; default: @@ -408,12 +402,12 @@ void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref) { aPref->name() = aHashEntry->key; - if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) { + if (aHashEntry->prefFlags.HasDefault()) { GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE); } else { aPref->defaultValue() = null_t(); } - if (PREF_HAS_USER_VALUE(aHashEntry)) { + if (aHashEntry->prefFlags.HasUserValue()) { GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE); } else { aPref->userValue() = null_t(); @@ -451,11 +445,7 @@ bool PREF_HasUserPref(const char *pref_name) return false; PrefHashEntry *pref = pref_HashTableLookup(pref_name); - if (!pref) return false; - - /* convert PREF_HAS_USER_VALUE to bool */ - return (PREF_HAS_USER_VALUE(pref) != 0); - + return pref && pref->prefFlags.HasUserValue(); } nsresult @@ -468,12 +458,12 @@ PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default char* stringVal; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && (pref->flags & PREF_STRING)) - { - if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) + if (pref && (pref->prefFlags.IsTypeString())) { + if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { stringVal = pref->defaultPref.stringVal; - else + } else { stringVal = pref->userPref.stringVal; + } if (stringVal) { *return_buffer = NS_strdup(stringVal); @@ -490,18 +480,17 @@ nsresult PREF_GetIntPref(const char *pref_name,int32_t * return_int, bool get_de nsresult rv = NS_ERROR_UNEXPECTED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && (pref->flags & PREF_INT)) - { - if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) - { + if (pref && (pref->prefFlags.IsTypeInt())) { + if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { int32_t tempInt = pref->defaultPref.intVal; /* check to see if we even had a default */ - if (!(pref->flags & PREF_HAS_DEFAULT)) + if (!pref->prefFlags.HasDefault()) { return NS_ERROR_UNEXPECTED; + } *return_int = tempInt; - } - else + } else { *return_int = pref->userPref.intVal; + } rv = NS_OK; } return rv; @@ -515,18 +504,15 @@ nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_d nsresult rv = NS_ERROR_UNEXPECTED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); //NS_ASSERTION(pref, pref_name); - if (pref && (pref->flags & PREF_BOOL)) - { - if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) - { + if (pref && (pref->prefFlags.IsTypeBool())) { + if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { bool tempBool = pref->defaultPref.boolVal; /* check to see if we even had a default */ - if (pref->flags & PREF_HAS_DEFAULT) { + if (pref->prefFlags.HasDefault()) { *return_value = tempBool; rv = NS_OK; } - } - else { + } else { *return_value = pref->userPref.boolVal; rv = NS_OK; } @@ -584,11 +570,10 @@ PREF_ClearUserPref(const char *pref_name) return NS_ERROR_NOT_INITIALIZED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && PREF_HAS_USER_VALUE(pref)) - { - pref->flags &= ~PREF_USERSET; + if (pref && pref->prefFlags.HasUserValue()) { + pref->prefFlags.SetHasUserValue(false); - if (!(pref->flags & PREF_HAS_DEFAULT)) { + if (!pref->prefFlags.HasDefault()) { gHashTable->RemoveEntry(pref); } @@ -612,11 +597,11 @@ PREF_ClearAllUserPrefs() for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { auto pref = static_cast(iter.Get()); - if (PREF_HAS_USER_VALUE(pref)) { + if (pref->prefFlags.HasUserValue()) { prefStrings.push_back(std::string(pref->key)); - pref->flags &= ~PREF_USERSET; - if (!(pref->flags & PREF_HAS_DEFAULT)) { + pref->prefFlags.SetHasUserValue(false); + if (!pref->prefFlags.HasDefault()) { iter.Remove(); } } @@ -640,18 +625,14 @@ nsresult PREF_LockPref(const char *key, bool lockit) return NS_ERROR_UNEXPECTED; if (lockit) { - if (!PREF_IS_LOCKED(pref)) - { - pref->flags |= PREF_LOCKED; + if (!pref->prefFlags.IsLocked()) { + pref->prefFlags.SetLocked(true); gIsAnyPrefLocked = true; pref_DoCallback(key); } - } - else - { - if (PREF_IS_LOCKED(pref)) - { - pref->flags &= ~PREF_LOCKED; + } else { + if (pref->prefFlags.IsLocked()) { + pref->prefFlags.SetLocked(false); pref_DoCallback(key); } } @@ -664,15 +645,23 @@ nsresult PREF_LockPref(const char *key, bool lockit) static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type) { bool changed = true; - if (type & PREF_STRING) - { - if (oldValue.stringVal && newValue.stringVal) + switch(type) { + case PrefType::String: + if (oldValue.stringVal && newValue.stringVal) { changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0); - } - else if (type & PREF_INT) + } + break; + case PrefType::Int: changed = oldValue.intVal != newValue.intVal; - else if (type & PREF_BOOL) + break; + case PrefType::Bool: changed = oldValue.boolVal != newValue.boolVal; + break; + case PrefType::Invalid: + default: + changed = false; + break; + } return changed; } @@ -681,20 +670,21 @@ static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType t * ensure that they are not changing the type of a preference that has * a default value. */ -static void pref_SetValue(PrefValue* existingValue, uint16_t *existingFlags, - PrefValue newValue, PrefType newType) +static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags, + PrefValue newValue, PrefType newType) { - if ((*existingFlags & PREF_STRING) && existingValue->stringVal) { + if (flags.IsTypeString() && existingValue->stringVal) { PL_strfree(existingValue->stringVal); } - *existingFlags = (*existingFlags & ~PREF_VALUETYPE_MASK) | newType; - if (newType & PREF_STRING) { + flags.SetPrefType(newType); + if (flags.IsTypeString()) { PR_ASSERT(newValue.stringVal); existingValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr; } else { *existingValue = newValue; } + return flags; } PrefHashEntry* pref_HashTableLookup(const char *key) @@ -723,63 +713,53 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t if (!pref->key) { // initialize the pref entry - pref->flags = type; + pref->prefFlags.Reset().SetPrefType(type); pref->key = ArenaStrDup(key, &gPrefNameArena); memset(&pref->defaultPref, 0, sizeof(pref->defaultPref)); memset(&pref->userPref, 0, sizeof(pref->userPref)); - } - else if ((pref->flags & PREF_HAS_DEFAULT) && PREF_TYPE(pref) != type) - { + } else if (pref->prefFlags.HasDefault() && !pref->prefFlags.IsPrefType(type)) { NS_WARNING(nsPrintfCString("Trying to overwrite value of default pref %s with the wrong type!", key).get()); return NS_ERROR_UNEXPECTED; } bool valueChanged = false; - if (flags & kPrefSetDefault) - { - if (!PREF_IS_LOCKED(pref)) - { /* ?? change of semantics? */ + if (flags & kPrefSetDefault) { + if (!pref->prefFlags.IsLocked()) { + /* ?? change of semantics? */ if (pref_ValueChanged(pref->defaultPref, value, type) || - !(pref->flags & PREF_HAS_DEFAULT)) - { - pref_SetValue(&pref->defaultPref, &pref->flags, value, type); - pref->flags |= PREF_HAS_DEFAULT; - if (flags & kPrefStickyDefault) - pref->flags |= PREF_STICKY_DEFAULT; - if (!PREF_HAS_USER_VALUE(pref)) + !pref->prefFlags.HasDefault()) { + pref->prefFlags = pref_SetValue(&pref->defaultPref, pref->prefFlags, value, type).SetHasDefault(true); + if (flags & kPrefStickyDefault) { + pref->prefFlags.SetHasStickyDefault(true); + } + if (!pref->prefFlags.HasUserValue()) { valueChanged = true; + } } // What if we change the default to be the same as the user value? // Should we clear the user value? } - } - else - { + } else { /* If new value is same as the default value and it's not a "sticky" pref, then un-set the user value. Otherwise, set the user value only if it has changed */ - if ((pref->flags & PREF_HAS_DEFAULT) && - !(pref->flags & PREF_STICKY_DEFAULT) && + if ((pref->prefFlags.HasDefault()) && + !(pref->prefFlags.HasStickyDefault()) && !pref_ValueChanged(pref->defaultPref, value, type) && - !(flags & kPrefForceSet)) - { - if (PREF_HAS_USER_VALUE(pref)) - { + !(flags & kPrefForceSet)) { + if (pref->prefFlags.HasUserValue()) { /* XXX should we free a user-set string value if there is one? */ - pref->flags &= ~PREF_USERSET; - if (!PREF_IS_LOCKED(pref)) { + pref->prefFlags.SetHasUserValue(false); + if (!pref->prefFlags.IsLocked()) { gDirty = true; valueChanged = true; } } - } - else if (!PREF_HAS_USER_VALUE(pref) || - PREF_TYPE(pref) != type || - pref_ValueChanged(pref->userPref, value, type) ) - { - pref_SetValue(&pref->userPref, &pref->flags, value, type); - pref->flags |= PREF_USERSET; - if (!PREF_IS_LOCKED(pref)) { + } else if (!pref->prefFlags.HasUserValue() || + !pref->prefFlags.IsPrefType(type) || + pref_ValueChanged(pref->userPref, value, type) ) { + pref->prefFlags = pref_SetValue(&pref->userPref, pref->prefFlags, value, type).SetHasUserValue(true); + if (!pref->prefFlags.IsLocked()) { gDirty = true; valueChanged = true; } @@ -808,17 +788,11 @@ PREF_GetPrefType(const char *pref_name) { if (gHashTable) { PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref) - { - if (pref->flags & PREF_STRING) - return PREF_STRING; - else if (pref->flags & PREF_INT) - return PREF_INT; - else if (pref->flags & PREF_BOOL) - return PREF_BOOL; + if (pref) { + return pref->prefFlags.GetPrefType(); } } - return PREF_INVALID; + return PrefType::Invalid; } /* -- */ @@ -829,8 +803,9 @@ PREF_PrefIsLocked(const char *pref_name) bool result = false; if (gIsAnyPrefLocked && gHashTable) { PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && PREF_IS_LOCKED(pref)) + if (pref && pref->prefFlags.IsLocked()) { result = true; + } } return result; @@ -973,10 +948,16 @@ void PREF_ReaderCallback(void *closure, PrefType type, bool isDefault, bool isStickyDefault) + { - uint32_t flags = isDefault ? kPrefSetDefault : kPrefForceSet; - if (isDefault && isStickyDefault) { - flags |= kPrefStickyDefault; + uint32_t flags = 0; + if (isDefault) { + flags |= kPrefSetDefault; + if (isStickyDefault) { + flags |= kPrefStickyDefault; + } + } else { + flags |= kPrefForceSet; } pref_HashPref(pref, value, type, flags); } diff --git a/modules/libpref/prefapi.h b/modules/libpref/prefapi.h index a168dbf469d..7dc70ca2366 100644 --- a/modules/libpref/prefapi.h +++ b/modules/libpref/prefapi.h @@ -28,14 +28,6 @@ typedef union bool boolVal; } PrefValue; -struct PrefHashEntry : PLDHashEntryHdr -{ - uint16_t flags; // This field goes first to minimize struct size on 64-bit. - const char *key; - PrefValue defaultPref; - PrefValue userPref; -}; - /* // // The Init function initializes the preference context and creates @@ -45,7 +37,7 @@ struct PrefHashEntry : PLDHashEntryHdr void PREF_Init(); /* -// Cleanup should be called at program exit to free the +// Cleanup should be called at program exit to free the // list of registered callbacks. */ void PREF_Cleanup(); @@ -53,23 +45,88 @@ void PREF_CleanupPrefs(); /* // -// Preference flags, including the native type of the preference +// Preference flags, including the native type of the preference. Changing any of these +// values will require modifying the code inside of PrefTypeFlags class. // */ -typedef enum { PREF_INVALID = 0, - PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4, PREF_REMOTE = 8, - PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128, - PREF_HAS_DEFAULT = 256, - // pref is default pref with "sticky" semantics - PREF_STICKY_DEFAULT = 512, - PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL) - } PrefType; +enum class PrefType { + Invalid = 0, + String = 1, + Int = 2, + Bool = 3, +}; + +// Keep the type of the preference, as well as the flags guiding its behaviour. +class PrefTypeFlags +{ +public: + PrefTypeFlags() : mValue(AsInt(PrefType::Invalid)) {} + PrefTypeFlags(PrefType aType) : mValue(AsInt(aType)) {} + PrefTypeFlags& Reset() { mValue = AsInt(PrefType::Invalid); return *this; } + + bool IsTypeValid() const { return !IsPrefType(PrefType::Invalid); } + bool IsTypeString() const { return IsPrefType(PrefType::String); } + bool IsTypeInt() const { return IsPrefType(PrefType::Int); } + bool IsTypeBool() const { return IsPrefType(PrefType::Bool); } + bool IsPrefType(PrefType type) const { return GetPrefType() == type; } + + PrefTypeFlags& SetPrefType(PrefType aType) { + mValue = mValue - AsInt(GetPrefType()) + AsInt(aType); + return *this; + } + PrefType GetPrefType() const { + return (PrefType)(mValue & (AsInt(PrefType::String) | + AsInt(PrefType::Int) | + AsInt(PrefType::Bool))); + } + + bool HasDefault() const { return mValue & PREF_FLAG_HAS_DEFAULT; } + PrefTypeFlags& SetHasDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_HAS_DEFAULT, aSetOrUnset); } + + bool HasStickyDefault() const { return mValue & PREF_FLAG_STICKY_DEFAULT; } + PrefTypeFlags& SetHasStickyDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_STICKY_DEFAULT, aSetOrUnset); } + + bool IsLocked() const { return mValue & PREF_FLAG_LOCKED; } + PrefTypeFlags& SetLocked(bool aSetOrUnset) { return SetFlag(PREF_FLAG_LOCKED, aSetOrUnset); } + + bool HasUserValue() const { return mValue & PREF_FLAG_USERSET; } + PrefTypeFlags& SetHasUserValue(bool aSetOrUnset) { return SetFlag(PREF_FLAG_USERSET, aSetOrUnset); } + +private: + static uint16_t AsInt(PrefType aType) { return (uint16_t)aType; } + + PrefTypeFlags& SetFlag(uint16_t aFlag, bool aSetOrUnset) { + mValue = aSetOrUnset ? mValue | aFlag : mValue & ~aFlag; + return *this; + } + + // Pack both the value of type (PrefType) and flags into the same int. This is why + // the flag enum starts at 4, as PrefType occupies the bottom two bits. + enum { + PREF_FLAG_LOCKED = 4, + PREF_FLAG_USERSET = 8, + PREF_FLAG_CONFIG = 16, + PREF_FLAG_REMOTE = 32, + PREF_FLAG_LILOCAL = 64, + PREF_FLAG_HAS_DEFAULT = 128, + PREF_FLAG_STICKY_DEFAULT = 256, + }; + uint16_t mValue; +}; + +struct PrefHashEntry : PLDHashEntryHdr +{ + PrefTypeFlags prefFlags; // This field goes first to minimize struct size on 64-bit. + const char *key; + PrefValue defaultPref; + PrefValue userPref; +}; /* // // Set the various types of preferences. These functions take a dotted -// notation of the preference name (e.g. "browser.startup.homepage"). +// notation of the preference name (e.g. "browser.startup.homepage"). // Note that this will cause the preference to be saved to the file if // it is different from the default. In other words, these are used // to set the _user_ preferences. @@ -103,8 +160,8 @@ bool PREF_HasUserPref(const char* pref_name); // */ nsresult PREF_GetIntPref(const char *pref, - int32_t * return_int, bool get_default); -nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default); + int32_t * return_int, bool get_default); +nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default); /* // // These functions are similar to the above "Get" version with the significant @@ -173,10 +230,10 @@ typedef void (*PrefChangedFunc) (const char *, void *); // matched all the parameters; otherwise it returns PREF_ERROR. // */ -void PREF_RegisterCallback( const char* domain, - PrefChangedFunc callback, void* instance_data ); -nsresult PREF_UnregisterCallback( const char* domain, - PrefChangedFunc callback, void* instance_data ); +void PREF_RegisterCallback(const char* domain, + PrefChangedFunc callback, void* instance_data ); +nsresult PREF_UnregisterCallback(const char* domain, + PrefChangedFunc callback, void* instance_data ); /* * Used by nsPrefService as the callback function of the 'pref' parser diff --git a/modules/libpref/prefread.cpp b/modules/libpref/prefread.cpp index 6c4d339894f..0a723cf3e54 100644 --- a/modules/libpref/prefread.cpp +++ b/modules/libpref/prefread.cpp @@ -114,17 +114,17 @@ pref_DoCallback(PrefParseState *ps) PrefValue value; switch (ps->vtype) { - case PREF_STRING: + case PrefType::String: value.stringVal = ps->vb; break; - case PREF_INT: + case PrefType::Int: if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') { NS_WARNING("malformed integer value"); return false; } value.intVal = atoi(ps->vb); break; - case PREF_BOOL: + case PrefType::Bool: value.boolVal = (ps->vb == kTrue); break; default: @@ -154,7 +154,7 @@ PREF_FinalizeParseState(PrefParseState *ps) * Pseudo-BNF * ---------- * function = LJUNK function-name JUNK function-args - * function-name = "user_pref" | "pref" + * function-name = "user_pref" | "pref" | "sticky_pref" * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";" * pref-name = quoted-string * pref-value = quoted-string | "true" | "false" | integer-value @@ -188,7 +188,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) if (ps->lbcur != ps->lb) { /* reset state */ ps->lbcur = ps->lb; ps->vb = nullptr; - ps->vtype = PREF_INVALID; + ps->vtype = PrefType::Invalid; ps->fdefault = false; ps->fstickydefault = false; } @@ -200,10 +200,15 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) state = PREF_PARSE_UNTIL_EOL; break; case 'u': /* indicating user_pref */ - case 'p': /* indicating pref */ case 's': /* indicating sticky_pref */ - ps->smatch = (c == 'u' ? kUserPref : - (c == 's' ? kPrefSticky : kPref)); + case 'p': /* indicating pref */ + if (c == 'u') { + ps->smatch = kUserPref; + } else if (c == 's') { + ps->smatch = kPrefSticky; + } else { + ps->smatch = kPref; + } ps->sindex = 1; ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN; state = PREF_PARSE_MATCH_STRING; @@ -248,6 +253,8 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) case PREF_PARSE_UNTIL_NAME: if (c == '\"' || c == '\'') { ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky); + ps->fdefault = (ps->smatch == kPref || + ps->smatch == kPrefSticky); ps->fstickydefault = (ps->smatch == kPrefSticky); ps->quotechar = c; ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */ @@ -284,21 +291,21 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) /* the pref value type is unknown. so, we scan for the first * character of the value, and determine the type from that. */ if (c == '\"' || c == '\'') { - ps->vtype = PREF_STRING; + ps->vtype = PrefType::String; ps->quotechar = c; ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; state = PREF_PARSE_QUOTED_STRING; } else if (c == 't' || c == 'f') { ps->vb = (char *) (c == 't' ? kTrue : kFalse); - ps->vtype = PREF_BOOL; + ps->vtype = PrefType::Bool; ps->smatch = ps->vb; ps->sindex = 1; ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; state = PREF_PARSE_MATCH_STRING; } else if (isdigit(c) || (c == '-') || (c == '+')) { - ps->vtype = PREF_INT; + ps->vtype = PrefType::Int; /* write c to line buffer... */ if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) return false; /* out of memory */ @@ -511,13 +518,12 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) break; case PREF_PARSE_UNTIL_CLOSE_PAREN: /* tolerate only whitespace and embedded comments */ - if (c == ')') + if (c == ')') { state = PREF_PARSE_UNTIL_SEMICOLON; - else if (c == '/') { + } else if (c == '/') { ps->nextstate = state; /* return here when done with comment */ state = PREF_PARSE_COMMENT_MAYBE_START; - } - else if (!isspace(c)) { + } else if (!isspace(c)) { NS_WARNING("malformed pref file"); return false; } diff --git a/modules/libpref/prefread.h b/modules/libpref/prefread.h index 3c317ff044d..5e5cd0989cd 100644 --- a/modules/libpref/prefread.h +++ b/modules/libpref/prefread.h @@ -54,7 +54,7 @@ typedef struct PrefParseState { char *lbend; /* line buffer end */ char *vb; /* value buffer (ptr into lb) */ PrefType vtype; /* PREF_STRING,INT,BOOL */ - bool fdefault; /* true if (default) pref */ + bool fdefault; /* true if (default) pref */ bool fstickydefault; /* true if (sticky) pref */ } PrefParseState; From 5c476def4419b36cdc5e89b6030bd83dc77dae9e Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 22 Feb 2016 09:05:21 -0800 Subject: [PATCH 055/252] Backed out changeset dd911452e3f7 (bug 1249157) for build bustage CLOSED TREE --- modules/libpref/Preferences.cpp | 2 +- modules/libpref/nsPrefBranch.cpp | 16 +-- modules/libpref/prefapi.cpp | 223 +++++++++++++++++-------------- modules/libpref/prefapi.h | 107 ++++----------- modules/libpref/prefread.cpp | 36 +++-- modules/libpref/prefread.h | 2 +- 6 files changed, 164 insertions(+), 222 deletions(-) diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 017f68ebadc..5e613f9b43f 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -1315,7 +1315,7 @@ static nsresult pref_InitInitialObjects() // channel, telemetry is on by default, otherwise not. This is necessary // so that beta users who are testing final release builds don't flipflop // defaults. - if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) { + if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) { bool prerelease = false; #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT prerelease = true; diff --git a/modules/libpref/nsPrefBranch.cpp b/modules/libpref/nsPrefBranch.cpp index fe57c241dfa..6c341722e09 100644 --- a/modules/libpref/nsPrefBranch.cpp +++ b/modules/libpref/nsPrefBranch.cpp @@ -127,21 +127,7 @@ NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval) { NS_ENSURE_ARG(aPrefName); const char *pref = getPrefName(aPrefName); - switch (PREF_GetPrefType(pref)) { - case PrefType::String: - *_retval = PREF_STRING; - break; - case PrefType::Int: - *_retval = PREF_INT; - break; - case PrefType::Bool: - *_retval = PREF_BOOL; - break; - case PrefType::Invalid: - default: - *_retval = PREF_INVALID; - break; - } + *_retval = PREF_GetPrefType(pref); return NS_OK; } diff --git a/modules/libpref/prefapi.cpp b/modules/libpref/prefapi.cpp index 9d0c92f1e28..1caa0538614 100644 --- a/modules/libpref/prefapi.cpp +++ b/modules/libpref/prefapi.cpp @@ -40,7 +40,7 @@ static void clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { PrefHashEntry *pref = static_cast(entry); - if (pref->prefFlags.IsTypeString()) + if (pref->flags & PREF_STRING) { if (pref->defaultPref.stringVal) PL_strfree(pref->defaultPref.stringVal); @@ -117,7 +117,13 @@ static char *ArenaStrDup(const char* str, PLArenaPool* aArena) /*---------------------------------------------------------------------------*/ +#define PREF_IS_LOCKED(pref) ((pref)->flags & PREF_LOCKED) +#define PREF_HAS_DEFAULT_VALUE(pref) ((pref)->flags & PREF_HAS_DEFAULT) +#define PREF_HAS_USER_VALUE(pref) ((pref)->flags & PREF_USERSET) +#define PREF_TYPE(pref) (PrefType)((pref)->flags & PREF_VALUETYPE_MASK) + static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type); + /* -- Privates */ struct CallbackNode { char* domain; @@ -243,7 +249,7 @@ PREF_SetCharPref(const char *pref_name, const char *value, bool set_default) PrefValue pref; pref.stringVal = (char*)value; - return pref_HashPref(pref_name, pref, PrefType::String, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PREF_STRING, set_default ? kPrefSetDefault : 0); } nsresult @@ -252,7 +258,7 @@ PREF_SetIntPref(const char *pref_name, int32_t value, bool set_default) PrefValue pref; pref.intVal = value; - return pref_HashPref(pref_name, pref, PrefType::Int, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PREF_INT, set_default ? kPrefSetDefault : 0); } nsresult @@ -261,7 +267,7 @@ PREF_SetBoolPref(const char *pref_name, bool value, bool set_default) PrefValue pref; pref.boolVal = value; - return pref_HashPref(pref_name, pref, PrefType::Bool, set_default ? kPrefSetDefault : 0); + return pref_HashPref(pref_name, pref, PREF_BOOL, set_default ? kPrefSetDefault : 0); } enum WhichValue { DEFAULT_VALUE, USER_VALUE }; @@ -329,12 +335,12 @@ pref_savePrefs(PLDHashTable* aTable) // where we're getting our pref from PrefValue* sourcePref; - if (pref->prefFlags.HasUserValue() && + if (PREF_HAS_USER_VALUE(pref) && (pref_ValueChanged(pref->defaultPref, pref->userPref, - pref->prefFlags.GetPrefType()) || - !(pref->prefFlags.HasDefault()) || - pref->prefFlags.HasStickyDefault())) { + (PrefType) PREF_TYPE(pref)) || + !(pref->flags & PREF_HAS_DEFAULT) || + pref->flags & PREF_STICKY_DEFAULT)) { sourcePref = &pref->userPref; } else { // do not save default prefs that haven't changed @@ -342,15 +348,15 @@ pref_savePrefs(PLDHashTable* aTable) } // strings are in quotes! - if (pref->prefFlags.IsTypeString()) { + if (pref->flags & PREF_STRING) { prefValue = '\"'; str_escape(sourcePref->stringVal, prefValue); prefValue += '\"'; - } else if (pref->prefFlags.IsTypeInt()) { + } else if (pref->flags & PREF_INT) { prefValue.AppendInt(sourcePref->intVal); - } else if (pref->prefFlags.IsTypeBool()) { + } else if (pref->flags & PREF_BOOL) { prefValue = (sourcePref->boolVal) ? "true" : "false"; } @@ -383,14 +389,14 @@ GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref, settingValue = &aPref->defaultValue().get_PrefValue(); } - switch (aHashEntry->prefFlags.GetPrefType()) { - case PrefType::String: + switch (aHashEntry->flags & PREF_VALUETYPE_MASK) { + case PREF_STRING: *settingValue = nsDependentCString(value->stringVal); return; - case PrefType::Int: + case PREF_INT: *settingValue = value->intVal; return; - case PrefType::Bool: + case PREF_BOOL: *settingValue = !!value->boolVal; return; default: @@ -402,12 +408,12 @@ void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref) { aPref->name() = aHashEntry->key; - if (aHashEntry->prefFlags.HasDefault()) { + if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) { GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE); } else { aPref->defaultValue() = null_t(); } - if (aHashEntry->prefFlags.HasUserValue()) { + if (PREF_HAS_USER_VALUE(aHashEntry)) { GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE); } else { aPref->userValue() = null_t(); @@ -445,7 +451,11 @@ bool PREF_HasUserPref(const char *pref_name) return false; PrefHashEntry *pref = pref_HashTableLookup(pref_name); - return pref && pref->prefFlags.HasUserValue(); + if (!pref) return false; + + /* convert PREF_HAS_USER_VALUE to bool */ + return (PREF_HAS_USER_VALUE(pref) != 0); + } nsresult @@ -458,12 +468,12 @@ PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default char* stringVal; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && (pref->prefFlags.IsTypeString())) { - if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { + if (pref && (pref->flags & PREF_STRING)) + { + if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) stringVal = pref->defaultPref.stringVal; - } else { + else stringVal = pref->userPref.stringVal; - } if (stringVal) { *return_buffer = NS_strdup(stringVal); @@ -480,17 +490,18 @@ nsresult PREF_GetIntPref(const char *pref_name,int32_t * return_int, bool get_de nsresult rv = NS_ERROR_UNEXPECTED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && (pref->prefFlags.IsTypeInt())) { - if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { + if (pref && (pref->flags & PREF_INT)) + { + if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) + { int32_t tempInt = pref->defaultPref.intVal; /* check to see if we even had a default */ - if (!pref->prefFlags.HasDefault()) { + if (!(pref->flags & PREF_HAS_DEFAULT)) return NS_ERROR_UNEXPECTED; - } *return_int = tempInt; - } else { - *return_int = pref->userPref.intVal; } + else + *return_int = pref->userPref.intVal; rv = NS_OK; } return rv; @@ -504,15 +515,18 @@ nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_d nsresult rv = NS_ERROR_UNEXPECTED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); //NS_ASSERTION(pref, pref_name); - if (pref && (pref->prefFlags.IsTypeBool())) { - if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) { + if (pref && (pref->flags & PREF_BOOL)) + { + if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref)) + { bool tempBool = pref->defaultPref.boolVal; /* check to see if we even had a default */ - if (pref->prefFlags.HasDefault()) { + if (pref->flags & PREF_HAS_DEFAULT) { *return_value = tempBool; rv = NS_OK; } - } else { + } + else { *return_value = pref->userPref.boolVal; rv = NS_OK; } @@ -570,10 +584,11 @@ PREF_ClearUserPref(const char *pref_name) return NS_ERROR_NOT_INITIALIZED; PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && pref->prefFlags.HasUserValue()) { - pref->prefFlags.SetHasUserValue(false); + if (pref && PREF_HAS_USER_VALUE(pref)) + { + pref->flags &= ~PREF_USERSET; - if (!pref->prefFlags.HasDefault()) { + if (!(pref->flags & PREF_HAS_DEFAULT)) { gHashTable->RemoveEntry(pref); } @@ -597,11 +612,11 @@ PREF_ClearAllUserPrefs() for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) { auto pref = static_cast(iter.Get()); - if (pref->prefFlags.HasUserValue()) { + if (PREF_HAS_USER_VALUE(pref)) { prefStrings.push_back(std::string(pref->key)); - pref->prefFlags.SetHasUserValue(false); - if (!pref->prefFlags.HasDefault()) { + pref->flags &= ~PREF_USERSET; + if (!(pref->flags & PREF_HAS_DEFAULT)) { iter.Remove(); } } @@ -625,14 +640,18 @@ nsresult PREF_LockPref(const char *key, bool lockit) return NS_ERROR_UNEXPECTED; if (lockit) { - if (!pref->prefFlags.IsLocked()) { - pref->prefFlags.SetLocked(true); + if (!PREF_IS_LOCKED(pref)) + { + pref->flags |= PREF_LOCKED; gIsAnyPrefLocked = true; pref_DoCallback(key); } - } else { - if (pref->prefFlags.IsLocked()) { - pref->prefFlags.SetLocked(false); + } + else + { + if (PREF_IS_LOCKED(pref)) + { + pref->flags &= ~PREF_LOCKED; pref_DoCallback(key); } } @@ -645,23 +664,15 @@ nsresult PREF_LockPref(const char *key, bool lockit) static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type) { bool changed = true; - switch(type) { - case PrefType::String: - if (oldValue.stringVal && newValue.stringVal) { + if (type & PREF_STRING) + { + if (oldValue.stringVal && newValue.stringVal) changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0); - } - break; - case PrefType::Int: - changed = oldValue.intVal != newValue.intVal; - break; - case PrefType::Bool: - changed = oldValue.boolVal != newValue.boolVal; - break; - case PrefType::Invalid: - default: - changed = false; - break; } + else if (type & PREF_INT) + changed = oldValue.intVal != newValue.intVal; + else if (type & PREF_BOOL) + changed = oldValue.boolVal != newValue.boolVal; return changed; } @@ -670,21 +681,20 @@ static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType t * ensure that they are not changing the type of a preference that has * a default value. */ -static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags, - PrefValue newValue, PrefType newType) +static void pref_SetValue(PrefValue* existingValue, uint16_t *existingFlags, + PrefValue newValue, PrefType newType) { - if (flags.IsTypeString() && existingValue->stringVal) { + if ((*existingFlags & PREF_STRING) && existingValue->stringVal) { PL_strfree(existingValue->stringVal); } - flags.SetPrefType(newType); - if (flags.IsTypeString()) { + *existingFlags = (*existingFlags & ~PREF_VALUETYPE_MASK) | newType; + if (newType & PREF_STRING) { PR_ASSERT(newValue.stringVal); existingValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr; } else { *existingValue = newValue; } - return flags; } PrefHashEntry* pref_HashTableLookup(const char *key) @@ -713,53 +723,63 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t if (!pref->key) { // initialize the pref entry - pref->prefFlags.Reset().SetPrefType(type); + pref->flags = type; pref->key = ArenaStrDup(key, &gPrefNameArena); memset(&pref->defaultPref, 0, sizeof(pref->defaultPref)); memset(&pref->userPref, 0, sizeof(pref->userPref)); - } else if (pref->prefFlags.HasDefault() && !pref->prefFlags.IsPrefType(type)) { + } + else if ((pref->flags & PREF_HAS_DEFAULT) && PREF_TYPE(pref) != type) + { NS_WARNING(nsPrintfCString("Trying to overwrite value of default pref %s with the wrong type!", key).get()); return NS_ERROR_UNEXPECTED; } bool valueChanged = false; - if (flags & kPrefSetDefault) { - if (!pref->prefFlags.IsLocked()) { - /* ?? change of semantics? */ + if (flags & kPrefSetDefault) + { + if (!PREF_IS_LOCKED(pref)) + { /* ?? change of semantics? */ if (pref_ValueChanged(pref->defaultPref, value, type) || - !pref->prefFlags.HasDefault()) { - pref->prefFlags = pref_SetValue(&pref->defaultPref, pref->prefFlags, value, type).SetHasDefault(true); - if (flags & kPrefStickyDefault) { - pref->prefFlags.SetHasStickyDefault(true); - } - if (!pref->prefFlags.HasUserValue()) { + !(pref->flags & PREF_HAS_DEFAULT)) + { + pref_SetValue(&pref->defaultPref, &pref->flags, value, type); + pref->flags |= PREF_HAS_DEFAULT; + if (flags & kPrefStickyDefault) + pref->flags |= PREF_STICKY_DEFAULT; + if (!PREF_HAS_USER_VALUE(pref)) valueChanged = true; - } } // What if we change the default to be the same as the user value? // Should we clear the user value? } - } else { + } + else + { /* If new value is same as the default value and it's not a "sticky" pref, then un-set the user value. Otherwise, set the user value only if it has changed */ - if ((pref->prefFlags.HasDefault()) && - !(pref->prefFlags.HasStickyDefault()) && + if ((pref->flags & PREF_HAS_DEFAULT) && + !(pref->flags & PREF_STICKY_DEFAULT) && !pref_ValueChanged(pref->defaultPref, value, type) && - !(flags & kPrefForceSet)) { - if (pref->prefFlags.HasUserValue()) { + !(flags & kPrefForceSet)) + { + if (PREF_HAS_USER_VALUE(pref)) + { /* XXX should we free a user-set string value if there is one? */ - pref->prefFlags.SetHasUserValue(false); - if (!pref->prefFlags.IsLocked()) { + pref->flags &= ~PREF_USERSET; + if (!PREF_IS_LOCKED(pref)) { gDirty = true; valueChanged = true; } } - } else if (!pref->prefFlags.HasUserValue() || - !pref->prefFlags.IsPrefType(type) || - pref_ValueChanged(pref->userPref, value, type) ) { - pref->prefFlags = pref_SetValue(&pref->userPref, pref->prefFlags, value, type).SetHasUserValue(true); - if (!pref->prefFlags.IsLocked()) { + } + else if (!PREF_HAS_USER_VALUE(pref) || + PREF_TYPE(pref) != type || + pref_ValueChanged(pref->userPref, value, type) ) + { + pref_SetValue(&pref->userPref, &pref->flags, value, type); + pref->flags |= PREF_USERSET; + if (!PREF_IS_LOCKED(pref)) { gDirty = true; valueChanged = true; } @@ -788,11 +808,17 @@ PREF_GetPrefType(const char *pref_name) { if (gHashTable) { PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref) { - return pref->prefFlags.GetPrefType(); + if (pref) + { + if (pref->flags & PREF_STRING) + return PREF_STRING; + else if (pref->flags & PREF_INT) + return PREF_INT; + else if (pref->flags & PREF_BOOL) + return PREF_BOOL; } } - return PrefType::Invalid; + return PREF_INVALID; } /* -- */ @@ -803,9 +829,8 @@ PREF_PrefIsLocked(const char *pref_name) bool result = false; if (gIsAnyPrefLocked && gHashTable) { PrefHashEntry* pref = pref_HashTableLookup(pref_name); - if (pref && pref->prefFlags.IsLocked()) { + if (pref && PREF_IS_LOCKED(pref)) result = true; - } } return result; @@ -948,16 +973,10 @@ void PREF_ReaderCallback(void *closure, PrefType type, bool isDefault, bool isStickyDefault) - { - uint32_t flags = 0; - if (isDefault) { - flags |= kPrefSetDefault; - if (isStickyDefault) { - flags |= kPrefStickyDefault; - } - } else { - flags |= kPrefForceSet; + uint32_t flags = isDefault ? kPrefSetDefault : kPrefForceSet; + if (isDefault && isStickyDefault) { + flags |= kPrefStickyDefault; } pref_HashPref(pref, value, type, flags); } diff --git a/modules/libpref/prefapi.h b/modules/libpref/prefapi.h index 7dc70ca2366..a168dbf469d 100644 --- a/modules/libpref/prefapi.h +++ b/modules/libpref/prefapi.h @@ -28,6 +28,14 @@ typedef union bool boolVal; } PrefValue; +struct PrefHashEntry : PLDHashEntryHdr +{ + uint16_t flags; // This field goes first to minimize struct size on 64-bit. + const char *key; + PrefValue defaultPref; + PrefValue userPref; +}; + /* // // The Init function initializes the preference context and creates @@ -37,7 +45,7 @@ typedef union void PREF_Init(); /* -// Cleanup should be called at program exit to free the +// Cleanup should be called at program exit to free the // list of registered callbacks. */ void PREF_Cleanup(); @@ -45,88 +53,23 @@ void PREF_CleanupPrefs(); /* // -// Preference flags, including the native type of the preference. Changing any of these -// values will require modifying the code inside of PrefTypeFlags class. +// Preference flags, including the native type of the preference // */ -enum class PrefType { - Invalid = 0, - String = 1, - Int = 2, - Bool = 3, -}; - -// Keep the type of the preference, as well as the flags guiding its behaviour. -class PrefTypeFlags -{ -public: - PrefTypeFlags() : mValue(AsInt(PrefType::Invalid)) {} - PrefTypeFlags(PrefType aType) : mValue(AsInt(aType)) {} - PrefTypeFlags& Reset() { mValue = AsInt(PrefType::Invalid); return *this; } - - bool IsTypeValid() const { return !IsPrefType(PrefType::Invalid); } - bool IsTypeString() const { return IsPrefType(PrefType::String); } - bool IsTypeInt() const { return IsPrefType(PrefType::Int); } - bool IsTypeBool() const { return IsPrefType(PrefType::Bool); } - bool IsPrefType(PrefType type) const { return GetPrefType() == type; } - - PrefTypeFlags& SetPrefType(PrefType aType) { - mValue = mValue - AsInt(GetPrefType()) + AsInt(aType); - return *this; - } - PrefType GetPrefType() const { - return (PrefType)(mValue & (AsInt(PrefType::String) | - AsInt(PrefType::Int) | - AsInt(PrefType::Bool))); - } - - bool HasDefault() const { return mValue & PREF_FLAG_HAS_DEFAULT; } - PrefTypeFlags& SetHasDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_HAS_DEFAULT, aSetOrUnset); } - - bool HasStickyDefault() const { return mValue & PREF_FLAG_STICKY_DEFAULT; } - PrefTypeFlags& SetHasStickyDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_STICKY_DEFAULT, aSetOrUnset); } - - bool IsLocked() const { return mValue & PREF_FLAG_LOCKED; } - PrefTypeFlags& SetLocked(bool aSetOrUnset) { return SetFlag(PREF_FLAG_LOCKED, aSetOrUnset); } - - bool HasUserValue() const { return mValue & PREF_FLAG_USERSET; } - PrefTypeFlags& SetHasUserValue(bool aSetOrUnset) { return SetFlag(PREF_FLAG_USERSET, aSetOrUnset); } - -private: - static uint16_t AsInt(PrefType aType) { return (uint16_t)aType; } - - PrefTypeFlags& SetFlag(uint16_t aFlag, bool aSetOrUnset) { - mValue = aSetOrUnset ? mValue | aFlag : mValue & ~aFlag; - return *this; - } - - // Pack both the value of type (PrefType) and flags into the same int. This is why - // the flag enum starts at 4, as PrefType occupies the bottom two bits. - enum { - PREF_FLAG_LOCKED = 4, - PREF_FLAG_USERSET = 8, - PREF_FLAG_CONFIG = 16, - PREF_FLAG_REMOTE = 32, - PREF_FLAG_LILOCAL = 64, - PREF_FLAG_HAS_DEFAULT = 128, - PREF_FLAG_STICKY_DEFAULT = 256, - }; - uint16_t mValue; -}; - -struct PrefHashEntry : PLDHashEntryHdr -{ - PrefTypeFlags prefFlags; // This field goes first to minimize struct size on 64-bit. - const char *key; - PrefValue defaultPref; - PrefValue userPref; -}; +typedef enum { PREF_INVALID = 0, + PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4, PREF_REMOTE = 8, + PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128, + PREF_HAS_DEFAULT = 256, + // pref is default pref with "sticky" semantics + PREF_STICKY_DEFAULT = 512, + PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL) + } PrefType; /* // // Set the various types of preferences. These functions take a dotted -// notation of the preference name (e.g. "browser.startup.homepage"). +// notation of the preference name (e.g. "browser.startup.homepage"). // Note that this will cause the preference to be saved to the file if // it is different from the default. In other words, these are used // to set the _user_ preferences. @@ -160,8 +103,8 @@ bool PREF_HasUserPref(const char* pref_name); // */ nsresult PREF_GetIntPref(const char *pref, - int32_t * return_int, bool get_default); -nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default); + int32_t * return_int, bool get_default); +nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default); /* // // These functions are similar to the above "Get" version with the significant @@ -230,10 +173,10 @@ typedef void (*PrefChangedFunc) (const char *, void *); // matched all the parameters; otherwise it returns PREF_ERROR. // */ -void PREF_RegisterCallback(const char* domain, - PrefChangedFunc callback, void* instance_data ); -nsresult PREF_UnregisterCallback(const char* domain, - PrefChangedFunc callback, void* instance_data ); +void PREF_RegisterCallback( const char* domain, + PrefChangedFunc callback, void* instance_data ); +nsresult PREF_UnregisterCallback( const char* domain, + PrefChangedFunc callback, void* instance_data ); /* * Used by nsPrefService as the callback function of the 'pref' parser diff --git a/modules/libpref/prefread.cpp b/modules/libpref/prefread.cpp index 0a723cf3e54..6c4d339894f 100644 --- a/modules/libpref/prefread.cpp +++ b/modules/libpref/prefread.cpp @@ -114,17 +114,17 @@ pref_DoCallback(PrefParseState *ps) PrefValue value; switch (ps->vtype) { - case PrefType::String: + case PREF_STRING: value.stringVal = ps->vb; break; - case PrefType::Int: + case PREF_INT: if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') { NS_WARNING("malformed integer value"); return false; } value.intVal = atoi(ps->vb); break; - case PrefType::Bool: + case PREF_BOOL: value.boolVal = (ps->vb == kTrue); break; default: @@ -154,7 +154,7 @@ PREF_FinalizeParseState(PrefParseState *ps) * Pseudo-BNF * ---------- * function = LJUNK function-name JUNK function-args - * function-name = "user_pref" | "pref" | "sticky_pref" + * function-name = "user_pref" | "pref" * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";" * pref-name = quoted-string * pref-value = quoted-string | "true" | "false" | integer-value @@ -188,7 +188,7 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) if (ps->lbcur != ps->lb) { /* reset state */ ps->lbcur = ps->lb; ps->vb = nullptr; - ps->vtype = PrefType::Invalid; + ps->vtype = PREF_INVALID; ps->fdefault = false; ps->fstickydefault = false; } @@ -200,15 +200,10 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) state = PREF_PARSE_UNTIL_EOL; break; case 'u': /* indicating user_pref */ - case 's': /* indicating sticky_pref */ case 'p': /* indicating pref */ - if (c == 'u') { - ps->smatch = kUserPref; - } else if (c == 's') { - ps->smatch = kPrefSticky; - } else { - ps->smatch = kPref; - } + case 's': /* indicating sticky_pref */ + ps->smatch = (c == 'u' ? kUserPref : + (c == 's' ? kPrefSticky : kPref)); ps->sindex = 1; ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN; state = PREF_PARSE_MATCH_STRING; @@ -253,8 +248,6 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) case PREF_PARSE_UNTIL_NAME: if (c == '\"' || c == '\'') { ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky); - ps->fdefault = (ps->smatch == kPref || - ps->smatch == kPrefSticky); ps->fstickydefault = (ps->smatch == kPrefSticky); ps->quotechar = c; ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */ @@ -291,21 +284,21 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) /* the pref value type is unknown. so, we scan for the first * character of the value, and determine the type from that. */ if (c == '\"' || c == '\'') { - ps->vtype = PrefType::String; + ps->vtype = PREF_STRING; ps->quotechar = c; ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; state = PREF_PARSE_QUOTED_STRING; } else if (c == 't' || c == 'f') { ps->vb = (char *) (c == 't' ? kTrue : kFalse); - ps->vtype = PrefType::Bool; + ps->vtype = PREF_BOOL; ps->smatch = ps->vb; ps->sindex = 1; ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN; state = PREF_PARSE_MATCH_STRING; } else if (isdigit(c) || (c == '-') || (c == '+')) { - ps->vtype = PrefType::Int; + ps->vtype = PREF_INT; /* write c to line buffer... */ if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps)) return false; /* out of memory */ @@ -518,12 +511,13 @@ PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen) break; case PREF_PARSE_UNTIL_CLOSE_PAREN: /* tolerate only whitespace and embedded comments */ - if (c == ')') { + if (c == ')') state = PREF_PARSE_UNTIL_SEMICOLON; - } else if (c == '/') { + else if (c == '/') { ps->nextstate = state; /* return here when done with comment */ state = PREF_PARSE_COMMENT_MAYBE_START; - } else if (!isspace(c)) { + } + else if (!isspace(c)) { NS_WARNING("malformed pref file"); return false; } diff --git a/modules/libpref/prefread.h b/modules/libpref/prefread.h index 5e5cd0989cd..3c317ff044d 100644 --- a/modules/libpref/prefread.h +++ b/modules/libpref/prefread.h @@ -54,7 +54,7 @@ typedef struct PrefParseState { char *lbend; /* line buffer end */ char *vb; /* value buffer (ptr into lb) */ PrefType vtype; /* PREF_STRING,INT,BOOL */ - bool fdefault; /* true if (default) pref */ + bool fdefault; /* true if (default) pref */ bool fstickydefault; /* true if (sticky) pref */ } PrefParseState; From 593f07996ba3e9b9f85f9d329e7df2e21feb2ab2 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Mon, 22 Feb 2016 17:16:01 +0000 Subject: [PATCH 056/252] Bug 1221872 - ValueNumbering: Set the dominator index of fixup blocks when they are created. r=sunfish --- js/src/jit/ValueNumbering.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/jit/ValueNumbering.cpp b/js/src/jit/ValueNumbering.cpp index 6dd9cad9ba4..a8d4a7a3077 100644 --- a/js/src/jit/ValueNumbering.cpp +++ b/js/src/jit/ValueNumbering.cpp @@ -439,6 +439,7 @@ ValueNumberer::fixupOSROnlyLoop(MBasicBlock* block, MBasicBlock* backedge) graph_.insertBlockBefore(block, fake); fake->setImmediateDominator(fake); fake->addNumDominated(1); + fake->setDomIndex(fake->id()); // Create zero-input phis to use as inputs for any phis in |block|. // Again, this is a little odd, but it's the least-odd thing we can do From 677a302dd02d9fcf9eb53632d6886ec9aaac63a5 Mon Sep 17 00:00:00 2001 From: Jeffrey Tran Date: Mon, 22 Feb 2016 09:21:15 -0800 Subject: [PATCH 057/252] Bug 637238 - Uncheck rich text option in MainMenu.nib. r=ted --- .../MainMenu.nib/keyedobjects.nib | Bin 27027 -> 25518 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib index d390a16cd8afc6c7054d4dc7dbad131c8cf1424b..bfdcccb74c66424472a22a064c429f5c67171ef3 100644 GIT binary patch literal 25518 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%0A7L((mvRutW$sJWZ?mcpAY_AwG`830X)yzMRP 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 From 8c1463f0b56cd830b151fd1227d659e5f53f4bf2 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Mon, 22 Feb 2016 12:32:03 -0500 Subject: [PATCH 058/252] Bug 1249927 - devirtualize CanHavaAnonymousChildren, r=davdib --- accessible/base/TreeWalker.cpp | 4 ++-- accessible/generic/Accessible.cpp | 6 ------ accessible/generic/Accessible.h | 16 ++++++++------- accessible/xul/XULComboboxAccessible.cpp | 26 ++++++++---------------- accessible/xul/XULComboboxAccessible.h | 1 - accessible/xul/XULListboxAccessible.cpp | 11 ++++------ accessible/xul/XULListboxAccessible.h | 1 - accessible/xul/XULMenuAccessible.cpp | 8 +------- accessible/xul/XULMenuAccessible.h | 2 -- accessible/xul/XULSliderAccessible.cpp | 9 +------- accessible/xul/XULSliderAccessible.h | 1 - 11 files changed, 26 insertions(+), 59 deletions(-) diff --git a/accessible/base/TreeWalker.cpp b/accessible/base/TreeWalker.cpp index cabcf24c1f3..a06bd2e3514 100644 --- a/accessible/base/TreeWalker.cpp +++ b/accessible/base/TreeWalker.cpp @@ -27,8 +27,8 @@ TreeWalker:: { NS_ASSERTION(aContent, "No node for the accessible tree walker!"); - mChildFilter = mContext->CanHaveAnonChildren() ? - nsIContent::eAllChildren : nsIContent::eAllButXBL; + mChildFilter = mContext->NoXBLKids() ? + nsIContent::eAllButXBL : nsIContent::eAllChildren; mChildFilter |= nsIContent::eSkipPlaceholderContent; if (aContent) diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index 34c119e8521..960823ae511 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -302,12 +302,6 @@ Accessible::KeyboardShortcut() const return KeyBinding(); } -bool -Accessible::CanHaveAnonChildren() -{ - return true; -} - void Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut) { diff --git a/accessible/generic/Accessible.h b/accessible/generic/Accessible.h index 2317aee5d00..baf03119092 100644 --- a/accessible/generic/Accessible.h +++ b/accessible/generic/Accessible.h @@ -494,11 +494,6 @@ public: */ virtual nsresult HandleAccEvent(AccEvent* aAccEvent); - /** - * Return true if this accessible allows accessible children from anonymous subtree. - */ - virtual bool CanHaveAnonChildren(); - /** * Return true if the accessible is an acceptable child. */ @@ -930,6 +925,12 @@ public: mStateFlags &= ~eRelocated; } + /** + * Return true if the accessible doesn't allow accessible children from XBL + * anonymous subtree. + */ + bool NoXBLKids() { return mStateFlags & eNoXBLKids; } + /** * Return true if this accessible has a parent whose name depends on this * accessible. @@ -1021,8 +1022,9 @@ protected: eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them eRelocated = 1 << 9, // accessible was moved in tree + eNoXBLKids = 1 << 10, // accessible don't allows XBL children - eLastStateFlag = eRelocated + eLastStateFlag = eNoXBLKids }; /** @@ -1137,7 +1139,7 @@ protected: int32_t mIndexInParent; static const uint8_t kChildrenFlagsBits = 2; - static const uint8_t kStateFlagsBits = 10; + static const uint8_t kStateFlagsBits = 11; static const uint8_t kContextFlagsBits = 2; static const uint8_t kTypeBits = 6; static const uint8_t kGenericTypesBits = 14; diff --git a/accessible/xul/XULComboboxAccessible.cpp b/accessible/xul/XULComboboxAccessible.cpp index ec818dffc15..1bca6d58e1a 100644 --- a/accessible/xul/XULComboboxAccessible.cpp +++ b/accessible/xul/XULComboboxAccessible.cpp @@ -31,6 +31,15 @@ XULComboboxAccessible:: mGenericTypes |= eAutoComplete; else mGenericTypes |= eCombobox; + + // Both the XUL and + // widgets use XULComboboxAccessible. We need to walk the anonymous children + // for these so that the entry field is a child. Otherwise no XBL children. + if (!mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) && + !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable, + nsGkAtoms::_true, eIgnoreCase)) { + mStateFlags |= eNoXBLKids; + } } role @@ -96,23 +105,6 @@ XULComboboxAccessible::Value(nsString& aValue) menuList->GetLabel(aValue); } -bool -XULComboboxAccessible::CanHaveAnonChildren() -{ - if (mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) || - mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable, - nsGkAtoms::_true, eIgnoreCase)) { - // Both the XUL and widgets - // use XULComboboxAccessible. We need to walk the anonymous children for these - // so that the entry field is a child - return true; - } - - // Argument of false indicates we don't walk anonymous children for - // menuitems - return false; -} - uint8_t XULComboboxAccessible::ActionCount() { diff --git a/accessible/xul/XULComboboxAccessible.h b/accessible/xul/XULComboboxAccessible.h index ae8398a521a..679f479b5f3 100644 --- a/accessible/xul/XULComboboxAccessible.h +++ b/accessible/xul/XULComboboxAccessible.h @@ -26,7 +26,6 @@ public: virtual void Value(nsString& aValue) override; virtual a11y::role NativeRole() override; virtual uint64_t NativeState() override; - virtual bool CanHaveAnonChildren() override; // ActionAccessible virtual uint8_t ActionCount() override; diff --git a/accessible/xul/XULListboxAccessible.cpp b/accessible/xul/XULListboxAccessible.cpp index 3f37e9e929e..52c3ddf0f42 100644 --- a/accessible/xul/XULListboxAccessible.cpp +++ b/accessible/xul/XULListboxAccessible.cpp @@ -544,6 +544,10 @@ XULListitemAccessible:: nsGkAtoms::checkbox, eCaseMatters); mType = eXULListItemType; + + // Walk XBL anonymous children for list items. Overrides the flag value from + // base XULMenuitemAccessible class. + mStateFlags &= ~eNoXBLKids; } XULListitemAccessible::~XULListitemAccessible() @@ -668,13 +672,6 @@ XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) } } -bool -XULListitemAccessible::CanHaveAnonChildren() -{ - // That indicates we should walk anonymous children for listitems - return true; -} - //////////////////////////////////////////////////////////////////////////////// // XULListitemAccessible: Widgets diff --git a/accessible/xul/XULListboxAccessible.h b/accessible/xul/XULListboxAccessible.h index e90f88acecf..05783803507 100644 --- a/accessible/xul/XULListboxAccessible.h +++ b/accessible/xul/XULListboxAccessible.h @@ -115,7 +115,6 @@ public: virtual a11y::role NativeRole() override; virtual uint64_t NativeState() override; virtual uint64_t NativeInteractiveState() const override; - virtual bool CanHaveAnonChildren() override; // Actions virtual void ActionNameAt(uint8_t index, nsAString& aName) override; diff --git a/accessible/xul/XULMenuAccessible.cpp b/accessible/xul/XULMenuAccessible.cpp index 6c5e4287b7c..fde8c970b33 100644 --- a/accessible/xul/XULMenuAccessible.cpp +++ b/accessible/xul/XULMenuAccessible.cpp @@ -41,6 +41,7 @@ XULMenuitemAccessible:: XULMenuitemAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc) { + mStateFlags |= eNoXBLKids; } uint64_t @@ -267,13 +268,6 @@ XULMenuitemAccessible::GetLevelInternal() return nsAccUtils::GetLevelForXULContainerItem(mContent); } -bool -XULMenuitemAccessible::CanHaveAnonChildren() -{ - // That indicates we don't walk anonymous children for menuitems - return false; -} - bool XULMenuitemAccessible::DoAction(uint8_t index) { diff --git a/accessible/xul/XULMenuAccessible.h b/accessible/xul/XULMenuAccessible.h index 3fa66620e78..6280db17dd4 100644 --- a/accessible/xul/XULMenuAccessible.h +++ b/accessible/xul/XULMenuAccessible.h @@ -30,8 +30,6 @@ public: virtual uint64_t NativeInteractiveState() const override; virtual int32_t GetLevelInternal() override; - virtual bool CanHaveAnonChildren() override; - // ActionAccessible virtual uint8_t ActionCount() override; virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override; diff --git a/accessible/xul/XULSliderAccessible.cpp b/accessible/xul/XULSliderAccessible.cpp index a2cbfa0d27e..476cb17ebf5 100644 --- a/accessible/xul/XULSliderAccessible.cpp +++ b/accessible/xul/XULSliderAccessible.cpp @@ -23,7 +23,7 @@ XULSliderAccessible:: XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc) { - mStateFlags |= eHasNumericValue; + mStateFlags |= eHasNumericValue | eNoXBLKids; } // Accessible @@ -127,13 +127,6 @@ XULSliderAccessible::SetCurValue(double aValue) return SetSliderAttr(nsGkAtoms::curpos, aValue); } -bool -XULSliderAccessible::CanHaveAnonChildren() -{ - // Do not allow anonymous xul:slider be accessible. - return false; -} - // Utils nsIContent* diff --git a/accessible/xul/XULSliderAccessible.h b/accessible/xul/XULSliderAccessible.h index 264f78c8c91..72c914c2670 100644 --- a/accessible/xul/XULSliderAccessible.h +++ b/accessible/xul/XULSliderAccessible.h @@ -26,7 +26,6 @@ public: virtual a11y::role NativeRole() override; virtual uint64_t NativeInteractiveState() const override; virtual bool NativelyUnavailable() const override; - virtual bool CanHaveAnonChildren() override; // Value virtual double MaxValue() const override; From cf9c34166289a4454263b6b35f8cab47aea608f8 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 22 Feb 2016 09:43:09 -0800 Subject: [PATCH 059/252] Bug 1246800 - Masked shift-by-scalar amounts. r=sunfish Modulo-reduce SIMD shift amounts by the size of the lane instead of saturating shift amounts larger than the number of bits in a lane. MozReview-Commit-ID: KdfpIvpucPt --- js/src/builtin/SIMD.cpp | 20 ++++++++--- js/src/jit-test/tests/SIMD/shift.js | 17 +++++---- js/src/jit-test/tests/asm.js/testSIMD.js | 11 +++--- js/src/jit/Lowering.cpp | 5 ++- js/src/jit/shared/LIR-shared.h | 11 ++++-- .../x86-shared/CodeGenerator-x86-shared.cpp | 25 +++++-------- js/src/tests/ecma_7/SIMD/shifts.js | 36 +++++++++---------- 7 files changed, 68 insertions(+), 57 deletions(-) diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 8e3ff21d3f2..e033d3b2f33 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -712,27 +712,37 @@ template struct Or { static T apply(T l, T r) { return l | r; } }; + // For the following three operators, if the value v we're trying to shift is // such that v << bits can't fit in the int32 range, then we have undefined -// behavior, according to C++11 [expr.shift]p2. +// behavior, according to C++11 [expr.shift]p2. However, left-shifting an +// unsigned type is well-defined. +// +// In C++, shifting by an amount outside the range [0;N-1] is undefined +// behavior. SIMD.js reduces the shift amount modulo the number of bits in a +// lane and has defined behavior for all shift amounts. template struct ShiftLeft { static T apply(T v, int32_t bits) { - return uint32_t(bits) >= sizeof(T) * 8 ? 0 : v << bits; + typedef typename mozilla::MakeUnsigned::Type UnsignedT; + uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); + return UnsignedT(v) << maskedBits; } }; template struct ShiftRightArithmetic { static T apply(T v, int32_t bits) { typedef typename mozilla::MakeSigned::Type SignedT; - uint32_t maxBits = sizeof(T) * 8; - return SignedT(v) >> (uint32_t(bits) >= maxBits ? maxBits - 1 : bits); + uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); + return SignedT(v) >> maskedBits; } }; template struct ShiftRightLogical { static T apply(T v, int32_t bits) { - return uint32_t(bits) >= sizeof(T) * 8 ? 0 : uint32_t(v) >> bits; + typedef typename mozilla::MakeUnsigned::Type UnsignedT; + uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8); + return UnsignedT(v) >> maskedBits; } }; diff --git a/js/src/jit-test/tests/SIMD/shift.js b/js/src/jit-test/tests/SIMD/shift.js index 9975d0f871b..8448e52ecbb 100644 --- a/js/src/jit-test/tests/SIMD/shift.js +++ b/js/src/jit-test/tests/SIMD/shift.js @@ -4,16 +4,16 @@ setJitCompilerOption("ion.warmup.trigger", 50); function curry(f, arg) { return f.bind(null, arg); } -function binaryLsh(count, v) { if (count>>>0 >= 32) return 0; return (v << count) | 0; } +function binaryLsh(count, v) { count &= 31; return (v << count) | 0; } function lsh(count) { return curry(binaryLsh, count); } -function binaryRsh(count, v) { if (count>>>0 >= 32) count = 31; return (v >> count) | 0; } +function binaryRsh(count, v) { count &= 31; return (v >> count) | 0; } function rsh(count) { return curry(binaryRsh, count); } -function binaryUlsh(count, v) { if (count>>>0 >= 32) return 0; return (v << count) >>> 0; } +function binaryUlsh(count, v) { count &= 31; return (v << count) >>> 0; } function ulsh(count) { return curry(binaryUlsh, count); } -function binaryUrsh(count, v) { if (count>>>0 >= 32) return 0; return v >>> count; } +function binaryUrsh(count, v) { count &= 31; return v >>> count; } function ursh(count) { return curry(binaryUrsh, count); } function f() { @@ -21,9 +21,8 @@ function f() { var u = SIMD.Uint32x4(1, 0x55005500, -3, 0xaa00aa00); var a = [1, 2, -3, 4]; var b = [1, 0x55005500, -3, 0xaa00aa00]; - var zeros = [0,0,0,0]; - var shifts = [-1, 0, 1, 31, 32]; + var shifts = [-2, -1, 0, 1, 31, 32, 33]; var r; for (var i = 0; i < 150; i++) { @@ -34,13 +33,15 @@ function f() { assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 2), a.map(lsh(2))); assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 31), a.map(lsh(31))); assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 32), a.map(lsh(32))); + assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 33), a.map(lsh(33))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, -1), a.map(rsh(31))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 0), a.map(rsh(0))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 1), a.map(rsh(1))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 2), a.map(rsh(2))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 31), a.map(rsh(31))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 32), a.map(rsh(31))); + assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 32), a.map(rsh(32))); + assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 33), a.map(rsh(33))); assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, -1), b.map(ulsh(-1))); assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 0), b.map(ulsh(0))); @@ -48,6 +49,7 @@ function f() { assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 2), b.map(ulsh(2))); assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 31), b.map(ulsh(31))); assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 32), b.map(ulsh(32))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 33), b.map(ulsh(33))); assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, -1), b.map(ursh(-1))); assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 0), b.map(ursh(0))); @@ -55,6 +57,7 @@ function f() { assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 2), b.map(ursh(2))); assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 31), b.map(ursh(31))); assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 32), b.map(ursh(32))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 33), b.map(ursh(33))); // Non constant shift counts var c = shifts[i % shifts.length]; diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js index 6eefcacc99e..a44dde1ec53 100644 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ b/js/src/jit-test/tests/asm.js/testSIMD.js @@ -1082,11 +1082,8 @@ assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + LSHI + "function f() { var input = 'i4(0, 1, ' + INT32_MIN + ', ' + INT32_MAX + ')'; var vinput = [0, 1, INT32_MIN, INT32_MAX]; -// TODO: What to do for masks > 31? Should we keep only the five low bits of -// the mask (JS) or not (x86)? -// See bug 1246800. -function Lsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) | 0 } } -function Rsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } } +function Lsh(i) { return function(x) { return (x << (i & 31)) | 0 } } +function Rsh(i) { return function(x) { return (x >> (i & 31)) | 0 } } var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(lsh(v, x+y))} return f;'), this) var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(rsh(v, x+y))} return f;'), this) @@ -1106,8 +1103,8 @@ const RSHU = 'var rsh=u4.shiftRightByScalar;' input = 'u4(0, 1, 0x80008000, ' + INT32_MAX + ')'; vinput = [0, 1, 0x80008000, INT32_MAX]; -function uLsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) >>> 0 } } -function uRsh(i) { if (i > 31) return () => 0; return function(x) { return (x >>> i) } } +function uLsh(i) { return function(x) { return (x << (i & 31)) >>> 0 } } +function uRsh(i) { return function(x) { return (x >>> (i & 31)) } } // Need to bitcast to Int32x4 before returning result. asmLsh = asmLink(asmCompile('glob', USE_ASM + U32 + CU32 + LSHU + I32 + CI32 + I32U32 + diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 8a6dc50d38b..cbd91e26c68 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4375,7 +4375,10 @@ LIRGenerator::visitSimdShift(MSimdShift* ins) LUse vector = useRegisterAtStart(ins->lhs()); LAllocation value = useRegisterOrConstant(ins->rhs()); - LSimdShift* lir = new(alloc()) LSimdShift(vector, value); + // We need a temp register to mask the shift amount, but not if the shift + // amount is a constant. + LDefinition tempReg = value.isConstant() ? LDefinition::BogusTemp() : temp(); + LSimdShift* lir = new(alloc()) LSimdShift(vector, value, tempReg); defineReuseInput(lir, ins, 0); } diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index d495cadbc53..c29ab2ee0ca 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -578,13 +578,17 @@ class LSimdBinaryBitwiseX4 : public LInstructionHelper<1, 2, 0> } }; -class LSimdShift : public LInstructionHelper<1, 2, 0> +// Shift a SIMD vector by a scalar amount. +// The temp register is only required if the shift amount is a dynamical +// value. If it is a constant, use a BogusTemp instead. +class LSimdShift : public LInstructionHelper<1, 2, 1> { public: LIR_HEADER(SimdShift) - LSimdShift(const LAllocation& vec, const LAllocation& val) { + LSimdShift(const LAllocation& vec, const LAllocation& val, const LDefinition& temp) { setOperand(0, vec); setOperand(1, val); + setTemp(0, temp); } const LAllocation* vector() { return getOperand(0); @@ -592,6 +596,9 @@ class LSimdShift : public LInstructionHelper<1, 2, 0> const LAllocation* value() { return getOperand(1); } + const LDefinition* temp() { + return getTemp(0); + } MSimdShift::Operation operation() const { return mir_->toSimdShift()->operation(); } diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 851608e4cd0..ba6e25dcb76 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -3433,24 +3433,11 @@ CodeGeneratorX86Shared::visitSimdShift(LSimdShift* ins) FloatRegister out = ToFloatRegister(ins->output()); MOZ_ASSERT(ToFloatRegister(ins->vector()) == out); // defineReuseInput(0); - // If the shift count is greater than 31, this will just zero all lanes by - // default for lsh and ursh, and for rsh extend the sign bit to all bits, - // per the SIMD.js spec (as of March 19th 2015). + // If the shift count is out of range, only use the low 5 bits. const LAllocation* val = ins->value(); if (val->isConstant()) { - uint32_t c = uint32_t(ToInt32(val)); - if (c > 31) { - switch (ins->operation()) { - case MSimdShift::lsh: - case MSimdShift::ursh: - masm.zeroInt32x4(out); - return; - default: - c = 31; - break; - } - } - Imm32 count(c); + MOZ_ASSERT(ins->temp()->isBogusTemp()); + Imm32 count(uint32_t(ToInt32(val)) % 32); switch (ins->operation()) { case MSimdShift::lsh: masm.packedLeftShiftByScalar(count, out); @@ -3465,9 +3452,13 @@ CodeGeneratorX86Shared::visitSimdShift(LSimdShift* ins) MOZ_CRASH("unexpected SIMD bitwise op"); } + // Truncate val to 5 bits. We should have a temp register for that. MOZ_ASSERT(val->isRegister()); + Register count = ToRegister(ins->temp()); + masm.mov(ToRegister(val), count); + masm.andl(Imm32(31), count); ScratchFloat32Scope scratch(masm); - masm.vmovd(ToRegister(val), scratch); + masm.vmovd(count, scratch); switch (ins->operation()) { case MSimdShift::lsh: diff --git a/js/src/tests/ecma_7/SIMD/shifts.js b/js/src/tests/ecma_7/SIMD/shifts.js index 7f5e5db9964..1d81f7483a9 100644 --- a/js/src/tests/ecma_7/SIMD/shifts.js +++ b/js/src/tests/ecma_7/SIMD/shifts.js @@ -14,68 +14,68 @@ var Uint32x4 = SIMD.Uint32x4; // Int8 shifts. function lsh8(a, b) { - return (b >>> 0) >= 8 ? 0 : (a << b) << 24 >> 24; + return (a << (b & 7)) << 24 >> 24; } function rsha8(a, b) { - return (a >> Math.min(b >>> 0, 7)) << 24 >> 24; + return (a >> (b & 7)) << 24 >> 24; } function rshl8(a, b) { - return (b >>> 0) >= 8 ? 0 : (a >>> b) << 24 >> 24; + return (a >>> (b & 7)) << 24 >> 24; } // Int16 shifts. function lsh16(a, b) { - return (b >>> 0) >= 16 ? 0 : (a << b) << 16 >> 16; + return (a << (b & 15)) << 16 >> 16; } function rsha16(a, b) { - return (a >> Math.min(b >>> 0, 15)) << 16 >> 16; + return (a >> (b & 15)) << 16 >> 16; } function rshl16(a, b) { - return (b >>> 0) >= 16 ? 0 : (a >>> b) << 16 >> 16; + return (a >>> (b & 15)) << 16 >> 16; } // Int32 shifts. function lsh32(a, b) { - return (b >>> 0) >= 32 ? 0 : (a << b) | 0; + return (a << (b & 31)) | 0; } function rsha32(a, b) { - return (a >> Math.min(b >>> 0, 31)) | 0; + return (a >> (b & 31)) | 0; } function rshl32(a, b) { - return (b >>> 0) >= 32 ? 0 : (a >>> b) | 0; + return (a >>> (b & 31)) | 0; } // Uint8 shifts. function ulsh8(a, b) { - return (b >>> 0) >= 8 ? 0 : (a << b) << 24 >>> 24; + return (a << (b & 7)) << 24 >>> 24; } function ursha8(a, b) { - return ((a << 24 >> 24) >> Math.min(b >>> 0, 7)) << 24 >>> 24; + return ((a << 24 >> 24) >> (b & 7)) << 24 >>> 24; } function urshl8(a, b) { - return (b >>> 0) >= 8 ? 0 : (a >>> b) << 24 >>> 24; + return (a >>> (b & 7)) << 24 >>> 24; } // Uint16 shifts. function ulsh16(a, b) { - return (b >>> 0) >= 16 ? 0 : (a << b) << 16 >>> 16; + return (a << (b & 15)) << 16 >>> 16; } function ursha16(a, b) { - return ((a << 16 >> 16) >> Math.min(b >>> 0, 15)) << 16 >>> 16; + return ((a << 16 >> 16) >> (b & 15)) << 16 >>> 16; } function urshl16(a, b) { - return (b >>> 0) >= 16 ? 0 : (a >>> b) << 16 >>> 16; + return (a >>> (b & 15)) << 16 >>> 16; } // Uint32 shifts. function ulsh32(a, b) { - return (b >>> 0) >= 32 ? 0 : (a << b) >>> 0; + return (a << (b & 31)) >>> 0; } function ursha32(a, b) { - return ((a | 0) >> Math.min(b >>> 0, 31)) >>> 0; + return ((a | 0) >> (b & 31)) >>> 0; } function urshl32(a, b) { - return (b >>> 0) >= 32 ? 0 : (a >>> b) >>> 0; + return (a >>> (b & 31)) >>> 0; } function test() { From cffce7401fc9ba77b2fb2d20f5b6f5e10854fffe Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Mon, 22 Feb 2016 19:37:50 +0200 Subject: [PATCH 060/252] Bug 1249932 - indicate in the GC and CC log (browser console) whether it is about default or content process, r=mccr8 --- dom/base/nsJSEnvironment.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 9788c6db524..2807624c75d 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -216,6 +216,13 @@ static bool sIsCompactingOnUserInactive = false; static int32_t sExpensiveCollectorPokes = 0; static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5; +static const char* +ProcessNameForCollectorLog() +{ + return XRE_GetProcessType() == GeckoProcessType_Default ? + "default" : "content"; +} + static PRTime GetCollectionTimeDelta() { @@ -1718,10 +1725,11 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults) } NS_NAMED_MULTILINE_LITERAL_STRING(kFmt, - MOZ_UTF16("CC(T+%.1f) max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n") + MOZ_UTF16("CC(T+%.1f)[%s] max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n") MOZ_UTF16("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu")); nsString msg; msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC, + ProcessNameForCollectorLog(), gCCStats.mMaxSliceTime, gCCStats.mTotalSliceTime, aResults.mNumSlices, gCCStats.mSuspected, aResults.mVisitedRefCounted, aResults.mVisitedGCed, mergeMsg.get(), @@ -2244,11 +2252,12 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip PRTime delta = GetCollectionTimeDelta(); if (sPostGCEventsToConsole) { - NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) "); + NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f)[%s] "); nsString prefix, gcstats; gcstats.Adopt(aDesc.formatSummaryMessage(aRt)); prefix.Adopt(nsTextFormatter::smprintf(kFmt.get(), - double(delta) / PR_USEC_PER_SEC)); + double(delta) / PR_USEC_PER_SEC, + ProcessNameForCollectorLog())); nsString msg = prefix + gcstats; nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); if (cs) { From de104048f4d1b6bc633398af9bb65a7aca42514d Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 22 Feb 2016 10:11:02 -0800 Subject: [PATCH 061/252] Bug 1247679, part 1 - Make ClearJSHolder publicly inherit from TraceCallbacks. r=smaug --- xpcom/base/CycleCollectedJSRuntime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index d370d532210..6d230a3b9a8 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -996,7 +996,7 @@ CycleCollectedJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTrace mJSHolders.Put(aHolder, aTracer); } -struct ClearJSHolder : TraceCallbacks +struct ClearJSHolder : public TraceCallbacks { virtual void Trace(JS::Heap* aPtr, const char*, void*) const override { From e38c20468313c6786d37fa4b624446c9886cfc71 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 22 Feb 2016 10:11:02 -0800 Subject: [PATCH 062/252] Bug 1247679, part 2 - Null check inside TraceCallbackFunc::Trace. r=smaug --- xpcom/base/nsCycleCollectorTraceJSHelpers.cpp | 24 ++++++++++++++----- xpcom/glue/nsCycleCollectionParticipant.h | 5 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp index 0e4e5d876a4..09c193f47e8 100644 --- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp +++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp @@ -58,40 +58,52 @@ void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JSObject** aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + if (*aPtr) { + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure); + if (aPtr->getPtr()) { + mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + if (aPtr->get()) { + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); + } } diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index fd114b76f01..5b65770e5e7 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -468,11 +468,10 @@ DowncastCCParticipant(void* aPtr) NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, aCallbacks, aClosure); #define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \ - if (tmp->_field) \ - aCallbacks.Trace(&tmp->_field, #_field, aClosure); + aCallbacks.Trace(&tmp->_field, #_field, aClosure); #define NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(_field) \ - aCallbacks.Trace(&tmp->_field, #_field, aClosure); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) // NB: The (void)tmp; hack in the TRACE_END macro exists to support // implementations that don't need to do anything in their Trace method. From 94ba83d71e29091280940e548fd09785e6d057c0 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 22 Feb 2016 10:11:02 -0800 Subject: [PATCH 063/252] Bug 1247679, part 3 - Replace NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK with JS_MEMBER. r=smaug --- devtools/server/nsJSInspector.cpp | 4 ++-- dom/base/Console.cpp | 2 +- dom/base/DOMException.cpp | 2 +- dom/base/DOMRequest.cpp | 2 +- dom/base/nsDocument.cpp | 2 +- dom/base/nsFrameMessageManager.cpp | 2 +- dom/base/nsJSEnvironment.cpp | 4 ++-- dom/base/nsJSTimeoutHandler.cpp | 2 +- dom/base/nsXMLHttpRequest.cpp | 2 +- dom/bindings/Codegen.py | 4 +--- dom/events/MessageEvent.cpp | 2 +- dom/html/HTMLFormElement.cpp | 2 +- dom/html/nsDOMStringMap.cpp | 2 +- dom/indexedDB/IDBCursor.cpp | 6 +++--- dom/indexedDB/IDBIndex.cpp | 2 +- dom/indexedDB/IDBKeyRange.cpp | 4 ++-- dom/indexedDB/IDBObjectStore.cpp | 2 +- dom/indexedDB/IDBRequest.cpp | 2 +- dom/notification/Notification.cpp | 2 +- dom/promise/Promise.cpp | 2 +- dom/workers/ServiceWorkerEvents.cpp | 2 +- dom/workers/ServiceWorkerMessageEvent.cpp | 2 +- dom/workers/XMLHttpRequest.cpp | 2 +- toolkit/components/osfile/NativeOSFileInternals.cpp | 2 +- xpcom/glue/nsCycleCollectionParticipant.h | 3 --- 25 files changed, 29 insertions(+), 34 deletions(-) diff --git a/devtools/server/nsJSInspector.cpp b/devtools/server/nsJSInspector.cpp index fa1fead2b90..6d717af5bc7 100644 --- a/devtools/server/nsJSInspector.cpp +++ b/devtools/server/nsJSInspector.cpp @@ -47,9 +47,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSInspector) for (uint32_t i = 0; i < tmp->mRequestors.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mRequestors[i]) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRequestors[i]) } - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mLastRequestor) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLastRequestor) NS_IMPL_CYCLE_COLLECTION_TRACE_END nsJSInspector::nsJSInspector() : mNestedLoopLevel(0), mRequestors(1), mLastRequestor(JS::NullValue()) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 719bd47e089..b09396a34d4 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -158,7 +158,7 @@ public: ConsoleCallData* tmp = this; for (uint32_t i = 0; i < mCopiedArguments.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCopiedArguments[i]); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCopiedArguments[i]) } } diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp index c5ea640b093..a035a4f98f2 100644 --- a/dom/base/DOMException.cpp +++ b/dom/base/DOMException.cpp @@ -182,7 +182,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mThrownJSVal) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception) diff --git a/dom/base/DOMRequest.cpp b/dom/base/DOMRequest.cpp index b1abca3c2f7..2897dd30dc7 100644 --- a/dom/base/DOMRequest.cpp +++ b/dom/base/DOMRequest.cpp @@ -62,7 +62,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest, DOMEventTargetHelper) // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because // DOMEventTargetHelper does it for us. - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResult) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResult) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMRequest) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index f290e2f9197..b111beb1353 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1893,7 +1893,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument) if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) } NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 347c45ed17b..839c0205d07 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -140,7 +140,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFrameMessageManager) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mInitialProcessData) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mInitialProcessData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameMessageManager) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 2807624c75d..1d491e4342d 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2807,8 +2807,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray) if (tmp->mArgv) { for (uint32_t i = 0; i < tmp->mArgc; ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mArgv[i]) - } + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgv[i]) + } } NS_IMPL_CYCLE_COLLECTION_TRACE_END diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index bc4b36c5e1b..7c4d18b76ac 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -129,7 +129,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler) for (uint32_t i = 0; i < tmp->mArgs.Length(); ++i) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mArgs[i]) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArgs[i]) } NS_IMPL_CYCLE_COLLECTION_TRACE_END diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index 628820d9183..eee1dd569ee 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -442,7 +442,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest, nsXHREventTarget) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultJSON) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultJSON) NS_IMPL_CYCLE_COLLECTION_TRACE_END // QueryInterface implementation for nsXMLHttpRequest diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index feb1ae1e285..1720ce228ea 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -16543,9 +16543,7 @@ class CGEventClass(CGBindingImplClass): for m in self.descriptor.interface.members: if m.isAttr(): name = CGDictionary.makeMemberName(m.identifier.name) - if m.type.isAny(): - retVal += " NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(" + name + ")\n" - elif m.type.isObject() or m.type.isSpiderMonkeyInterface(): + if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface(): retVal += " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(" + name + ")\n" elif typeNeedsRooting(m.type): raise TypeError("Need to implement tracing for event " diff --git a/dom/events/MessageEvent.cpp b/dom/events/MessageEvent.cpp index 36b60f8cccc..c41fe72cf06 100644 --- a/dom/events/MessageEvent.cpp +++ b/dom/events/MessageEvent.cpp @@ -33,7 +33,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessageEvent, Event) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MessageEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessageEvent) diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index a9410f5d8cf..076753454e4 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -151,7 +151,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(HTMLFormElement, nsGenericHTMLElement) if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) } NS_IMPL_CYCLE_COLLECTION_TRACE_END diff --git a/dom/html/nsDOMStringMap.cpp b/dom/html/nsDOMStringMap.cpp index fe2b8638865..831fb83ef0e 100644 --- a/dom/html/nsDOMStringMap.cpp +++ b/dom/html/nsDOMStringMap.cpp @@ -38,7 +38,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMStringMap) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) } NS_IMPL_CYCLE_COLLECTION_TRACE_END diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index 9615b2b4962..193499057f7 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -867,9 +867,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor) diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index dc4ec5d208c..8387aef69ed 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -593,7 +593,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp index 46a04d3b9df..5aa2c2bc35f 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -242,8 +242,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedLowerVal) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedUpperVal) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange) diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index bd9e0c74ab8..8ae74ce77a7 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1611,7 +1611,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp index 024e9b84474..9c0cec53d3c 100644 --- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -436,7 +436,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because // DOMEventTargetHelper does it for us. - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultVal) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest) diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index b81b387aa0f..fa31ee163ff 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -1228,7 +1228,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHe NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Notification, DOMEventTargetHelper) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData); + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 6dcf7491e18..aee724c61aa 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -416,7 +416,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Promise) #ifndef SPIDERMONKEY_PROMISE - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResult) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResult) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAllocationStack) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRejectionStack) NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mFullfillmentStack) diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index e7f4bb6bbbf..a2065280d6d 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -1247,7 +1247,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent, Event) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableMessageEvent) diff --git a/dom/workers/ServiceWorkerMessageEvent.cpp b/dom/workers/ServiceWorkerMessageEvent.cpp index fab9e1d2ea7..43fde834977 100644 --- a/dom/workers/ServiceWorkerMessageEvent.cpp +++ b/dom/workers/ServiceWorkerMessageEvent.cpp @@ -33,7 +33,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServiceWorkerMessageEvent, Eve NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ServiceWorkerMessageEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerMessageEvent) diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 6f116e2b202..23303fd684f 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1608,7 +1608,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequest, nsXHREventTarget) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mStateData.mResponse) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStateData.mResponse) NS_IMPL_CYCLE_COLLECTION_TRACE_END JSObject* diff --git a/toolkit/components/osfile/NativeOSFileInternals.cpp b/toolkit/components/osfile/NativeOSFileInternals.cpp index 4738f68fe83..d2452619b30 100644 --- a/toolkit/components/osfile/NativeOSFileInternals.cpp +++ b/toolkit/components/osfile/NativeOSFileInternals.cpp @@ -228,7 +228,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbstractResult) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AbstractResult) - NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedResult) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedResult) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbstractResult) diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 5b65770e5e7..effafd575b1 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -470,9 +470,6 @@ DowncastCCParticipant(void* aPtr) #define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \ aCallbacks.Trace(&tmp->_field, #_field, aClosure); -#define NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(_field) \ - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) - // NB: The (void)tmp; hack in the TRACE_END macro exists to support // implementations that don't need to do anything in their Trace method. // Without this hack, some compilers warn about the unused tmp local. From 4e1b7aa6e59b917bc51bc41eaf6d092bd668d020 Mon Sep 17 00:00:00 2001 From: Andi-Bogdan Postelnicu Date: Mon, 22 Feb 2016 17:04:52 +0200 Subject: [PATCH 064/252] Bug 1250144 - call super.onAttachedToWindow in ToolbarEditLayout::onAttachedToWindow. r=sebastian MozReview-Commit-ID: 5ld41tfhVGv --- .../base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java index fe856eaa176..113dbb24f54 100644 --- a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java +++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditLayout.java @@ -79,6 +79,8 @@ public class ToolbarEditLayout extends ThemedLinearLayout { @Override public void onAttachedToWindow() { + super.onAttachedToWindow(); + if (HardwareUtils.isTablet()) { mSearchIcon.setVisibility(View.VISIBLE); } From e42d3cb6675faa079a69c30e488efabbfeb34358 Mon Sep 17 00:00:00 2001 From: "Kearwood (Kip) Gilbert" Date: Tue, 16 Feb 2016 12:53:33 -0800 Subject: [PATCH 065/252] Bug 1237691 - Implement Oculus Head Pose Prediction MozReview-Commit-ID: 4hbKmZycEcn --- dom/vr/VRDevice.cpp | 2 +- gfx/thebes/gfxPrefs.h | 1 + gfx/vr/VRDeviceProxy.cpp | 10 ++- gfx/vr/VRDeviceProxy.h | 3 +- gfx/vr/VRDeviceProxyOrientationFallBack.cpp | 9 ++- gfx/vr/VRDeviceProxyOrientationFallBack.h | 3 +- gfx/vr/gfxVR.h | 3 +- gfx/vr/gfxVRCardboard.cpp | 9 ++- gfx/vr/gfxVRCardboard.h | 3 +- gfx/vr/gfxVROculus.cpp | 77 ++++++++++++++------- gfx/vr/gfxVROculus.h | 18 ++++- gfx/vr/gfxVROculus050.cpp | 10 ++- gfx/vr/gfxVROculus050.h | 3 +- modules/libpref/init/all.js | 5 ++ 14 files changed, 116 insertions(+), 40 deletions(-) diff --git a/dom/vr/VRDevice.cpp b/dom/vr/VRDevice.cpp index 2cee57c0b44..a59ca777a80 100644 --- a/dom/vr/VRDevice.cpp +++ b/dom/vr/VRDevice.cpp @@ -351,7 +351,7 @@ HMDPositionVRDevice::GetState() already_AddRefed HMDPositionVRDevice::GetImmediateState() { - gfx::VRHMDSensorState state = mHMD->GetSensorState(); + gfx::VRHMDSensorState state = mHMD->GetImmediateSensorState(); RefPtr obj = new VRPositionState(mParent, state); return obj.forget(); diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 1d46eeb0840..7b084e83af2 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -199,6 +199,7 @@ private: DECL_GFX_PREF(Once, "dom.vr.oculus050.enabled", VROculus050Enabled, bool, true); DECL_GFX_PREF(Once, "dom.vr.cardboard.enabled", VRCardboardEnabled, bool, false); DECL_GFX_PREF(Once, "dom.vr.add-test-devices", VRAddTestDevices, int32_t, 1); + DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled", VRPosePredictionEnabled, bool, false); DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false); DECL_GFX_PREF(Live, "dom.w3c_touch_events.enabled", TouchEventsEnabled, int32_t, 0); diff --git a/gfx/vr/VRDeviceProxy.cpp b/gfx/vr/VRDeviceProxy.cpp index a4d88b5b264..5ec7596edcc 100644 --- a/gfx/vr/VRDeviceProxy.cpp +++ b/gfx/vr/VRDeviceProxy.cpp @@ -79,13 +79,21 @@ VRDeviceProxy::ZeroSensor() } VRHMDSensorState -VRDeviceProxy::GetSensorState(double timeOffset) +VRDeviceProxy::GetSensorState() { VRManagerChild *vm = VRManagerChild::Get(); Unused << vm->SendKeepSensorTracking(mDeviceInfo.mDeviceID); return mSensorState; } +VRHMDSensorState +VRDeviceProxy::GetImmediateSensorState() +{ + // XXX TODO - Need to perform IPC call to get the current sensor + // state rather than the predictive state used for the frame rendering. + return GetSensorState(); +} + void VRDeviceProxy::UpdateSensorState(const VRHMDSensorState& aSensorState) { diff --git a/gfx/vr/VRDeviceProxy.h b/gfx/vr/VRDeviceProxy.h index 440a706c870..6476b0028f0 100644 --- a/gfx/vr/VRDeviceProxy.h +++ b/gfx/vr/VRDeviceProxy.h @@ -28,7 +28,8 @@ public: void UpdateSensorState(const VRHMDSensorState& aSensorState); const VRDeviceInfo& GetDeviceInfo() const { return mDeviceInfo; } - virtual VRHMDSensorState GetSensorState(double timeOffset = 0.0); + virtual VRHMDSensorState GetSensorState(); + virtual VRHMDSensorState GetImmediateSensorState(); bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight, double zNear, double zFar); diff --git a/gfx/vr/VRDeviceProxyOrientationFallBack.cpp b/gfx/vr/VRDeviceProxyOrientationFallBack.cpp index 89a1962fcad..c09d449afc6 100644 --- a/gfx/vr/VRDeviceProxyOrientationFallBack.cpp +++ b/gfx/vr/VRDeviceProxyOrientationFallBack.cpp @@ -187,13 +187,20 @@ VRDeviceProxyOrientationFallBack::ComputeStateFromLastSensor() } VRHMDSensorState -VRDeviceProxyOrientationFallBack::GetSensorState(double timeOffset) +VRDeviceProxyOrientationFallBack::GetSensorState() { StartSensorTracking(); ComputeStateFromLastSensor(); return mSensorState; } +VRHMDSensorState +VRDeviceProxyOrientationFallBack::GetImmediateSensorState() +{ + // XXX TODO - Should return actual immediate sensor state + return GetSensorState(); +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/vr/VRDeviceProxyOrientationFallBack.h b/gfx/vr/VRDeviceProxyOrientationFallBack.h index e1fb0d8df93..0a89a24be36 100644 --- a/gfx/vr/VRDeviceProxyOrientationFallBack.h +++ b/gfx/vr/VRDeviceProxyOrientationFallBack.h @@ -23,7 +23,8 @@ public: explicit VRDeviceProxyOrientationFallBack(const VRDeviceUpdate& aDeviceUpdate); virtual void ZeroSensor() override; - virtual VRHMDSensorState GetSensorState(double timeOffset = 0.0) override; + virtual VRHMDSensorState GetSensorState() override; + virtual VRHMDSensorState GetImmediateSensorState() override; // ISensorObserver interface void Notify(const hal::SensorData& SensorData) override; diff --git a/gfx/vr/gfxVR.h b/gfx/vr/gfxVR.h index 55c1890c85d..db5e2e4a5ad 100644 --- a/gfx/vr/gfxVR.h +++ b/gfx/vr/gfxVR.h @@ -264,7 +264,8 @@ public: virtual bool KeepSensorTracking() = 0; virtual void NotifyVsync(const TimeStamp& aVsyncTimestamp) = 0; - virtual VRHMDSensorState GetSensorState(double timeOffset = 0.0) = 0; + virtual VRHMDSensorState GetSensorState() = 0; + virtual VRHMDSensorState GetImmediateSensorState() = 0; virtual void ZeroSensor() = 0; diff --git a/gfx/vr/gfxVRCardboard.cpp b/gfx/vr/gfxVRCardboard.cpp index 3e4d4379329..04ee49b645e 100644 --- a/gfx/vr/gfxVRCardboard.cpp +++ b/gfx/vr/gfxVRCardboard.cpp @@ -51,7 +51,7 @@ HMDInfoCardboard::HMDInfoCardboard() VRHMDSensorState -HMDInfoCardboard::GetSensorState(double timeOffset) +HMDInfoCardboard::GetSensorState() { // Actual sensor state is calculated on the main thread, // within VRDeviceProxyOrientationFallBack @@ -60,6 +60,13 @@ HMDInfoCardboard::GetSensorState(double timeOffset) return result; } +VRHMDSensorState +HMDInfoCardboard::GetImmediateSensorState() +{ + return GetSensorState(); +} + + void HMDInfoCardboard::ZeroSensor() { diff --git a/gfx/vr/gfxVRCardboard.h b/gfx/vr/gfxVRCardboard.h index 822a5b209a8..0925bfd588d 100644 --- a/gfx/vr/gfxVRCardboard.h +++ b/gfx/vr/gfxVRCardboard.h @@ -25,7 +25,8 @@ public: bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight, double zNear, double zFar) override; - VRHMDSensorState GetSensorState(double timeOffset) override; + virtual VRHMDSensorState GetSensorState() override; + virtual VRHMDSensorState GetImmediateSensorState() override; void ZeroSensor() override; bool KeepSensorTracking() override; void NotifyVsync(const TimeStamp& aVsyncTimestamp) override; diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index 87cbfd512c4..ef76f70c7a4 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -41,6 +41,7 @@ static pfn_ovr_Destroy ovr_Destroy = nullptr; static pfn_ovr_RecenterPose ovr_RecenterPose = nullptr; static pfn_ovr_GetTrackingState ovr_GetTrackingState = nullptr; +static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr; static pfn_ovr_GetFovTextureSize ovr_GetFovTextureSize = nullptr; static pfn_ovr_GetRenderDesc ovr_GetRenderDesc = nullptr; @@ -170,6 +171,7 @@ InitializeOculusCAPI() REQUIRE_FUNCTION(ovr_RecenterPose); REQUIRE_FUNCTION(ovr_GetTrackingState); + REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime); REQUIRE_FUNCTION(ovr_GetFovTextureSize); REQUIRE_FUNCTION(ovr_GetRenderDesc); @@ -199,26 +201,6 @@ static bool InitializeOculusCAPI() #endif -static void -do_CalcEyePoses(ovrPosef headPose, - const ovrVector3f hmdToEyeViewOffset[2], - ovrPosef outEyePoses[2]) -{ - if (!hmdToEyeViewOffset || !outEyePoses) - return; - - for (uint32_t i = 0; i < 2; ++i) { - gfx::Quaternion o(headPose.Orientation.x, headPose.Orientation.y, headPose.Orientation.z, headPose.Orientation.w); - Point3D vo(hmdToEyeViewOffset[i].x, hmdToEyeViewOffset[i].y, hmdToEyeViewOffset[i].z); - Point3D p = o.RotatePoint(vo); - - outEyePoses[i].Orientation = headPose.Orientation; - outEyePoses[i].Position.x = p.x + headPose.Position.x; - outEyePoses[i].Position.y = p.y + headPose.Position.y; - outEyePoses[i].Position.z = p.z + headPose.Position.z; - } -} - ovrFovPort ToFovPort(const gfx::VRFieldOfView& aFOV) { @@ -280,6 +262,10 @@ HMDInfoOculus::HMDInfoOculus(ovrSession aSession) mDeviceInfo.mIsFakeScreen = true; SetFOV(mDeviceInfo.mRecommendedEyeFOV[VRDeviceInfo::Eye_Left], mDeviceInfo.mRecommendedEyeFOV[VRDeviceInfo::Eye_Right], 0.01, 10000.0); + + for (int i = 0; i < kMaxLatencyFrames; i++) { + mLastSensorState[i].Clear(); + } } void @@ -355,15 +341,33 @@ HMDInfoOculus::ZeroSensor() ovr_RecenterPose(mSession); } +VRHMDSensorState +HMDInfoOculus::GetSensorState() +{ + VRHMDSensorState result; + double frameTiming = 0.0f; + if (gfxPrefs::VRPosePredictionEnabled()) { + frameTiming = ovr_GetPredictedDisplayTime(mSession, mInputFrameID); + } + result = GetSensorState(frameTiming); + result.inputFrameID = mInputFrameID; + mLastSensorState[mInputFrameID % kMaxLatencyFrames] = result; + return result; +} + +VRHMDSensorState +HMDInfoOculus::GetImmediateSensorState() +{ + return GetSensorState(0.0); +} + VRHMDSensorState HMDInfoOculus::GetSensorState(double timeOffset) { VRHMDSensorState result; result.Clear(); - // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize - // the Oculus time base and the browser one. - ovrTrackingState state = ovr_GetTrackingState(mSession, ovr_GetTimeInSeconds() + timeOffset, true); + ovrTrackingState state = ovr_GetTrackingState(mSession, timeOffset, true); ovrPoseStatef& pose(state.HeadPose); result.timestamp = pose.TimeInSeconds; @@ -400,8 +404,6 @@ HMDInfoOculus::GetSensorState(double timeOffset) result.linearAcceleration[1] = pose.LinearAcceleration.y; result.linearAcceleration[2] = pose.LinearAcceleration.z; } - - mLastTrackingState = state; return result; } @@ -525,6 +527,13 @@ HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) MOZ_ASSERT(rts->hmd != nullptr); MOZ_ASSERT(rts->textureSet != nullptr); + VRHMDSensorState sensorState = mLastSensorState[aInputFrameID % kMaxLatencyFrames]; + // It is possible to get a cache miss on mLastSensorState if latency is + // longer than kMaxLatencyFrames. An optimization would be to find a frame + // that is closer than the one selected with the modulus. + // If we hit this; however, latency is already so high that the site is + // un-viewable and a more accurate pose prediction is not likely to + // compensate. ovrLayerEyeFov layer; layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = 0; @@ -545,7 +554,23 @@ HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) const Point3D& r = rts->hmd->mDeviceInfo.mEyeTranslation[1]; const ovrVector3f hmdToEyeViewOffset[2] = { { l.x, l.y, l.z }, { r.x, r.y, r.z } }; - do_CalcEyePoses(rts->hmd->mLastTrackingState.HeadPose.ThePose, hmdToEyeViewOffset, layer.RenderPose); + + for (uint32_t i = 0; i < 2; ++i) { + gfx::Quaternion o(sensorState.orientation[0], + sensorState.orientation[1], + sensorState.orientation[2], + sensorState.orientation[3]); + Point3D vo(hmdToEyeViewOffset[i].x, hmdToEyeViewOffset[i].y, hmdToEyeViewOffset[i].z); + Point3D p = o.RotatePoint(vo); + + layer.RenderPose[i].Orientation.x = o.x; + layer.RenderPose[i].Orientation.y = o.y; + layer.RenderPose[i].Orientation.z = o.z; + layer.RenderPose[i].Orientation.w = o.w; + layer.RenderPose[i].Position.x = p.x + sensorState.position[0]; + layer.RenderPose[i].Position.y = p.y + sensorState.position[1]; + layer.RenderPose[i].Position.z = p.z + sensorState.position[2]; + } ovrLayerHeader *layers = &layer.Header; ovrResult orv = ovr_SubmitFrame(mSession, aInputFrameID, nullptr, &layers, 1); diff --git a/gfx/vr/gfxVROculus.h b/gfx/vr/gfxVROculus.h index cf47660c151..76edef7d72d 100644 --- a/gfx/vr/gfxVROculus.h +++ b/gfx/vr/gfxVROculus.h @@ -28,7 +28,8 @@ public: bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight, double zNear, double zFar) override; - VRHMDSensorState GetSensorState(double timeOffset) override; + virtual VRHMDSensorState GetSensorState() override; + virtual VRHMDSensorState GetImmediateSensorState() override; void ZeroSensor() override; bool KeepSensorTracking() override; void NotifyVsync(const TimeStamp& aVsyncTimestamp) override; @@ -67,8 +68,19 @@ protected: ovrSession mSession; ovrHmdDesc mDesc; ovrFovPort mFOVPort[2]; - ovrTrackingState mLastTrackingState; - int mInputFrameID; + + VRHMDSensorState GetSensorState(double timeOffset); + + // The maximum number of frames of latency that we would expect before we + // should give up applying pose prediction. + // If latency is greater than one second, then the experience is not likely + // to be corrected by pose prediction. Setting this value too + // high may result in unnecessary memory allocation. + // As the current fastest refresh rate is 90hz, 100 is selected as a + // conservative value. + static const int kMaxLatencyFrames = 100; + VRHMDSensorState mLastSensorState[kMaxLatencyFrames]; + int32_t mInputFrameID; }; } // namespace impl diff --git a/gfx/vr/gfxVROculus050.cpp b/gfx/vr/gfxVROculus050.cpp index af867f16569..dd526d3a484 100644 --- a/gfx/vr/gfxVROculus050.cpp +++ b/gfx/vr/gfxVROculus050.cpp @@ -462,14 +462,20 @@ HMDInfoOculus050::ZeroSensor() } VRHMDSensorState -HMDInfoOculus050::GetSensorState(double timeOffset) +HMDInfoOculus050::GetImmediateSensorState() +{ + return GetSensorState(); +} + +VRHMDSensorState +HMDInfoOculus050::GetSensorState() { VRHMDSensorState result; result.Clear(); // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize // the Oculus time base and the browser one. - ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds() + timeOffset); + ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds()); ovrPoseStatef& pose(state.HeadPose); result.timestamp = pose.TimeInSeconds; diff --git a/gfx/vr/gfxVROculus050.h b/gfx/vr/gfxVROculus050.h index 9005f14640f..9a439bc333f 100644 --- a/gfx/vr/gfxVROculus050.h +++ b/gfx/vr/gfxVROculus050.h @@ -26,7 +26,8 @@ public: bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight, double zNear, double zFar) override; - VRHMDSensorState GetSensorState(double timeOffset) override; + virtual VRHMDSensorState GetSensorState() override; + virtual VRHMDSensorState GetImmediateSensorState() override; void ZeroSensor() override; bool KeepSensorTracking() override; void NotifyVsync(const TimeStamp& aVsyncTimestamp) override; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 93cbdebe587..26efccc3546 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4782,6 +4782,11 @@ pref("dom.vr.oculus050.enabled", true); pref("dom.vr.cardboard.enabled", false); // 0 = never; 1 = only if real devices aren't there; 2 = always pref("dom.vr.add-test-devices", 0); +// Pose prediction reduces latency effects by returning future predicted HMD +// poses to callers of the WebVR API. This currently only has an effect for +// Oculus Rift on SDK 0.8 or greater. It is disabled by default for now due to +// frame uniformity issues with e10s. +pref("dom.vr.poseprediction.enabled", false); // true = show the VR textures in our compositing output; false = don't. // true might have performance impact pref("gfx.vr.mirror-textures", false); From 9d058b994976e9a7226f491c7f2f44baadacac8a Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Mon, 22 Feb 2016 14:47:46 -0500 Subject: [PATCH 066/252] Bug 1245241 - fix SharedMemoryBasic_android CloseHandle to null out handle. r=billm a=kwierso --- ipc/glue/SharedMemoryBasic_android.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ipc/glue/SharedMemoryBasic_android.cpp b/ipc/glue/SharedMemoryBasic_android.cpp index eb91794b6ee..1f0a5da792b 100644 --- a/ipc/glue/SharedMemoryBasic_android.cpp +++ b/ipc/glue/SharedMemoryBasic_android.cpp @@ -130,8 +130,9 @@ SharedMemoryBasic::Unmap() void SharedMemoryBasic::CloseHandle() { - if (mShmFd > 0) { + if (mShmFd != -1) { close(mShmFd); + mShmFd = -1; } } From f056b17e13c48a8965e060c8c6220f15328c1953 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Mon, 22 Feb 2016 19:07:24 +0000 Subject: [PATCH 067/252] Bug 1249639: upgrade to glibc-2.12-1.166.el6_7.7; r=Callek DONTBUILD a=kwierso --- testing/docker/centos6-build-upd/VERSION | 2 +- testing/docker/desktop-build/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/docker/centos6-build-upd/VERSION b/testing/docker/centos6-build-upd/VERSION index 1e0cabeb156..7555e0453db 100644 --- a/testing/docker/centos6-build-upd/VERSION +++ b/testing/docker/centos6-build-upd/VERSION @@ -1 +1 @@ -0.1.3.20160122142300 +0.1.3.20160222133000 diff --git a/testing/docker/desktop-build/Dockerfile b/testing/docker/desktop-build/Dockerfile index c584c8baca8..915f87bd148 100644 --- a/testing/docker/desktop-build/Dockerfile +++ b/testing/docker/desktop-build/Dockerfile @@ -1,4 +1,4 @@ -FROM taskcluster/centos6-build-upd:0.1.3.20160122142300 +FROM taskcluster/centos6-build-upd:0.1.3.20160222133000 MAINTAINER Dustin J. Mitchell # Add build scripts; these are the entry points from the taskcluster worker, and From 45802e7d3b1703d441b8ef771c59cbb97b325455 Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Thu, 18 Feb 2016 14:10:35 -0800 Subject: [PATCH 068/252] Bug 1232685 - Prevent forcing illegal return values in derived class constructors. (r=shu, a=kwierso) --- js/src/doc/Debugger/Conventions.md | 4 +- js/src/jit-test/tests/debug/class-01.js | 20 +++++ js/src/jit-test/tests/debug/class-02.js | 20 +++++ js/src/jit-test/tests/debug/class-03.js | 23 ++++++ js/src/jit-test/tests/debug/class-04.js | 22 ++++++ js/src/jit-test/tests/debug/class-05.js | 31 ++++++++ js/src/jit-test/tests/debug/class-06.js | 22 ++++++ js/src/jit-test/tests/debug/class-07.js | 21 +++++ js/src/jit/JitFrames.cpp | 2 +- js/src/jit/VMFunctions.cpp | 2 +- js/src/vm/Debugger-inl.h | 4 +- js/src/vm/Debugger.cpp | 101 +++++++++++++++++++----- js/src/vm/Debugger.h | 29 +++++-- js/src/vm/Interpreter.cpp | 8 +- js/src/vm/Stack-inl.h | 6 ++ js/src/vm/Stack.h | 2 + 16 files changed, 285 insertions(+), 32 deletions(-) create mode 100644 js/src/jit-test/tests/debug/class-01.js create mode 100644 js/src/jit-test/tests/debug/class-02.js create mode 100644 js/src/jit-test/tests/debug/class-03.js create mode 100644 js/src/jit-test/tests/debug/class-04.js create mode 100644 js/src/jit-test/tests/debug/class-05.js create mode 100644 js/src/jit-test/tests/debug/class-06.js create mode 100644 js/src/jit-test/tests/debug/class-07.js diff --git a/js/src/doc/Debugger/Conventions.md b/js/src/doc/Debugger/Conventions.md index 4a62e650b9a..ecbce2ebec1 100644 --- a/js/src/doc/Debugger/Conventions.md +++ b/js/src/doc/Debugger/Conventions.md @@ -111,7 +111,9 @@ resumption value has one of the following forms: was called as a constructor (that is, via a `new` expression), then value serves as the value returned by the function's body, not that produced by the `new` expression: if the value is not an object, - the `new` expression returns the frame's `this` value. + the `new` expression returns the frame's `this` value. Similarly, if + the function is the constructor for a subclass, then a non-object + value may result in a TypeError. { yield: value } : (Not yet implemented.) Yield value immediately as the diff --git a/js/src/jit-test/tests/debug/class-01.js b/js/src/jit-test/tests/debug/class-01.js new file mode 100644 index 00000000000..66f390bd4ef --- /dev/null +++ b/js/src/jit-test/tests/debug/class-01.js @@ -0,0 +1,20 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will throw for using |this| uninitialized. + constructor() { } + }) +`); + +dbg.onExceptionUnwind = function() { + return { + // Force the return of an illegal value. + return: 1 + } +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-02.js b/js/src/jit-test/tests/debug/class-02.js new file mode 100644 index 00000000000..3821eea26ea --- /dev/null +++ b/js/src/jit-test/tests/debug/class-02.js @@ -0,0 +1,20 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive immediately. + constructor() { return {}; } + }) +`); + +dbg.onEnterFrame = function() { + return { + // Force the return of an illegal value. + return: 1 + } +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-03.js b/js/src/jit-test/tests/debug/class-03.js new file mode 100644 index 00000000000..da1a4f43450 --- /dev/null +++ b/js/src/jit-test/tests/debug/class-03.js @@ -0,0 +1,23 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive immediately. + constructor() { + debugger; + return {}; + } + }) +`); + +dbg.onDebuggerStatement = function() { + return { + // Force the return of an illegal value. + return: 1 + } +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-04.js b/js/src/jit-test/tests/debug/class-04.js new file mode 100644 index 00000000000..5f772e4d384 --- /dev/null +++ b/js/src/jit-test/tests/debug/class-04.js @@ -0,0 +1,22 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive on return. + constructor() { return {}; } + }) +`); + +dbg.onEnterFrame = function(f) { + f.onPop = function() { + return { + // Force the return of an illegal value. + return: 1 + } + } +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-05.js b/js/src/jit-test/tests/debug/class-05.js new file mode 100644 index 00000000000..4af7c23f832 --- /dev/null +++ b/js/src/jit-test/tests/debug/class-05.js @@ -0,0 +1,31 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive immediately. + constructor() { + debugger; + return {}; + } + }) +`); + +let handler = { + hit() { + return { + // Force the return of an illegal value. + return: 1 + } + } +}; + +dbg.onDebuggerStatement = function(frame) { + var line0 = frame.script.getOffsetLocation(frame.offset).lineNumber; + var offs = frame.script.getLineOffsets(line0 + 1); + frame.script.setBreakpoint(offs[0], handler); +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-06.js b/js/src/jit-test/tests/debug/class-06.js new file mode 100644 index 00000000000..fc6ebdbaa95 --- /dev/null +++ b/js/src/jit-test/tests/debug/class-06.js @@ -0,0 +1,22 @@ +// |jit-test| error: TypeError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive immediately. + constructor() { return {}; } + }) +`); + +dbg.onEnterFrame = function(f) { + f.onStep = function() { + return { + // Force the return of an illegal value. + return: 1 + } + } +} + +new forceException; diff --git a/js/src/jit-test/tests/debug/class-07.js b/js/src/jit-test/tests/debug/class-07.js new file mode 100644 index 00000000000..8613e737bfe --- /dev/null +++ b/js/src/jit-test/tests/debug/class-07.js @@ -0,0 +1,21 @@ +// |jit-test| error: ReferenceError + +let g = newGlobal(); +let dbg = Debugger(g); + +let forceException = g.eval(` + (class extends class {} { + // Calling this will return a primitive immediately. + constructor() { return {}; } + }) +`); + +dbg.onEnterFrame = function() { + return { + // Force the return undefined, which will throw for returning + // while |this| is still undefined. + return: undefined + } +} +print("break here"); +new forceException; diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 0b86e67cde1..0438fdb5303 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -688,7 +688,7 @@ HandleExceptionBaseline(JSContext* cx, const JitFrameIterator& frame, ResumeFrom } frameOk = HandleClosingGeneratorReturn(cx, frame.baselineFrame(), frameOk); - frameOk = Debugger::onLeaveFrame(cx, frame.baselineFrame(), frameOk); + frameOk = Debugger::onLeaveFrame(cx, frame.baselineFrame(), pc, frameOk); } else if (script->hasTrynotes()) { CloseLiveIteratorsBaselineForUncatchableException(cx, frame, pc); } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 2abbb2837bf..a087e9789a1 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -710,7 +710,7 @@ DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool ok) // If Debugger::onLeaveFrame returns |true| we have to return the frame's // return value. If it returns |false|, the debugger threw an exception. // In both cases we have to pop debug scopes. - ok = Debugger::onLeaveFrame(cx, frame, ok); + ok = Debugger::onLeaveFrame(cx, frame, pc, ok); // Unwind to the outermost scope and set pc to the end of the script, // regardless of error. diff --git a/js/src/vm/Debugger-inl.h b/js/src/vm/Debugger-inl.h index 20c5f7cd8df..2538260ad45 100644 --- a/js/src/vm/Debugger-inl.h +++ b/js/src/vm/Debugger-inl.h @@ -12,7 +12,7 @@ #include "vm/Stack-inl.h" /* static */ inline bool -js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok) +js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool ok) { MOZ_ASSERT_IF(frame.isInterpreterFrame(), frame.asInterpreterFrame() == cx->interpreterFrame()); MOZ_ASSERT_IF(frame.script()->isDebuggee(), frame.isDebuggee()); @@ -21,7 +21,7 @@ js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok) frame.script()->hasAnyBreakpointsOrStepMode(); MOZ_ASSERT_IF(evalTraps, frame.isDebuggee()); if (frame.isDebuggee()) - ok = slowPathOnLeaveFrame(cx, frame, ok); + ok = slowPathOnLeaveFrame(cx, frame, pc, ok); MOZ_ASSERT(!inFrameMaps(frame)); return ok; } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index d8eb93d3ccb..8f031709a62 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -744,7 +744,7 @@ DebuggerFrame_freeScriptFrameIterData(FreeOp* fop, JSObject* obj); * |cx->fp()|'s return value, and return a new success value. */ /* static */ bool -Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool frameOk) +Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool frameOk) { Handle global = cx->global(); @@ -788,7 +788,8 @@ Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool frame EnterDebuggeeNoExecute nx(cx, *dbg); if (dbg->enabled && - !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined()) { + !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined()) + { RootedValue handler(cx, frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER)); Maybe ac; @@ -805,7 +806,8 @@ Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool frame bool hookOk = Invoke(cx, ObjectValue(*frameobj), handler, 1, completion.address(), &rval); RootedValue nextValue(cx); - JSTrapStatus nextStatus = dbg->parseResumptionValue(ac, hookOk, rval, &nextValue); + JSTrapStatus nextStatus = dbg->parseResumptionValue(ac, hookOk, rval, + frame, pc, &nextValue); /* * At this point, we are back in the debuggee compartment, and any error has @@ -1150,7 +1152,9 @@ private: JSTrapStatus Debugger::handleUncaughtExceptionHelper(Maybe& ac, - MutableHandleValue* vp, bool callHook) + MutableHandleValue* vp, bool callHook, + const Maybe& thisVForCheck, + AbstractFramePtr frame) { JSContext* cx = ac->context()->asJSContext(); @@ -1166,8 +1170,10 @@ Debugger::handleUncaughtExceptionHelper(Maybe& ac, cx->clearPendingException(); RootedValue fval(cx, ObjectValue(*uncaughtExceptionHook)); RootedValue rv(cx); - if (Invoke(cx, ObjectValue(*object), fval, 1, exc.address(), &rv)) - return vp ? parseResumptionValue(ac, true, rv, *vp, false) : JSTRAP_CONTINUE; + if (Invoke(cx, ObjectValue(*object), fval, 1, exc.address(), &rv)) { + return vp ? parseResumptionValueHelper(ac, true, rv, thisVForCheck, frame, *vp, false) + : JSTRAP_CONTINUE; + } } if (cx->isExceptionPending()) { @@ -1204,15 +1210,16 @@ Debugger::handleUncaughtExceptionHelper(Maybe& ac, } JSTrapStatus -Debugger::handleUncaughtException(Maybe& ac, MutableHandleValue vp, bool callHook) +Debugger::handleUncaughtException(Maybe& ac, MutableHandleValue vp, bool callHook, + const Maybe& thisVForCheck, AbstractFramePtr frame) { - return handleUncaughtExceptionHelper(ac, &vp, callHook); + return handleUncaughtExceptionHelper(ac, &vp, callHook, thisVForCheck, frame); } JSTrapStatus Debugger::handleUncaughtException(Maybe& ac, bool callHook) { - return handleUncaughtExceptionHelper(ac, nullptr, callHook); + return handleUncaughtExceptionHelper(ac, nullptr, callHook, mozilla::Nothing(), NullFramePtr()); } /* static */ void @@ -1329,12 +1336,13 @@ ParseResumptionValueAsObject(JSContext* cx, HandleValue rv, JSTrapStatus* status } JSTrapStatus -Debugger::parseResumptionValue(Maybe& ac, bool ok, const Value& rv, MutableHandleValue vp, - bool callHook) +Debugger::parseResumptionValueHelper(Maybe& ac, bool ok, const Value& rv, + const Maybe& thisVForCheck, AbstractFramePtr frame, + MutableHandleValue vp, bool callHook) { vp.setUndefined(); if (!ok) - return handleUncaughtException(ac, vp, callHook); + return handleUncaughtException(ac, vp, callHook, thisVForCheck, frame); if (rv.isUndefined()) { ac.reset(); return JSTRAP_CONTINUE; @@ -1348,10 +1356,25 @@ Debugger::parseResumptionValue(Maybe& ac, bool ok, const Value& JSTrapStatus status = JSTRAP_CONTINUE; RootedValue v(cx); RootedValue rvRoot(cx, rv); + if (!ParseResumptionValueAsObject(cx, rvRoot, &status, &v) || !unwrapDebuggeeValue(cx, &v)) { - return handleUncaughtException(ac, vp, callHook); + return handleUncaughtException(ac, vp, callHook, thisVForCheck, frame); + } + + if (status == JSTRAP_RETURN && thisVForCheck.isSome() && v.isPrimitive()) { + if (v.isUndefined()) { + if (thisVForCheck.ref().isMagic(JS_UNINITIALIZED_LEXICAL)) { + MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx, frame)); + return handleUncaughtException(ac, vp, callHook, thisVForCheck, frame); + } + + v = thisVForCheck.ref(); + } else { + ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v, nullptr); + return handleUncaughtException(ac, vp, callHook, thisVForCheck, frame); + } } ac.reset(); @@ -1364,6 +1387,44 @@ Debugger::parseResumptionValue(Maybe& ac, bool ok, const Value& return status; } +JSTrapStatus +Debugger::parseResumptionValue(Maybe& ac, bool ok, const Value& rv, + AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp, + bool callHook) +{ + JSContext* cx = ac->context()->asJSContext(); + RootedValue rootThis(cx); + Maybe thisArg; + if (frame.debuggerNeedsCheckPrimitiveReturn()) { + bool success; + { + AutoCompartment ac2(cx, frame.scopeChain()); + success = GetThisValueForDebuggerMaybeOptimizedOut(cx, frame, pc, &rootThis); + } + if (!success || !cx->compartment()->wrap(cx, &rootThis)) { + ac.reset(); + return JSTRAP_ERROR; + } + MOZ_ASSERT_IF(rootThis.isMagic(), rootThis.isMagic(JS_UNINITIALIZED_LEXICAL)); + thisArg.emplace(HandleValue(rootThis)); + } + return parseResumptionValueHelper(ac, ok, rv, thisArg, frame, vp, callHook); +} + +JSTrapStatus +Debugger::parseResumptionValue(Maybe& ac, bool ok, const Value& rv, + const Value& thisV, AbstractFramePtr frame, MutableHandleValue vp, + bool callHook) +{ + JSContext* cx = ac->context()->asJSContext(); + RootedValue rootThis(cx, thisV); + Maybe thisArg; + if (frame.debuggerNeedsCheckPrimitiveReturn()) + thisArg.emplace(rootThis); + + return parseResumptionValueHelper(ac, ok, rv, thisArg, frame, vp, callHook); +} + static bool CallMethodIfPresent(JSContext* cx, HandleObject obj, const char* name, int argc, Value* argv, MutableHandleValue rval) @@ -1396,7 +1457,7 @@ Debugger::fireDebuggerStatement(JSContext* cx, MutableHandleValue vp) RootedValue rv(cx); bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, scriptFrame.address(), &rv); - return parseResumptionValue(ac, ok, rv, vp); + return parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp); } JSTrapStatus @@ -1424,7 +1485,7 @@ Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp) RootedValue rv(cx); bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 2, argv.begin(), &rv); - JSTrapStatus st = parseResumptionValue(ac, ok, rv, vp); + JSTrapStatus st = parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp); if (st == JSTRAP_CONTINUE) cx->setPendingException(exc); return st; @@ -1446,7 +1507,8 @@ Debugger::fireEnterFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleVal RootedValue rv(cx); bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, scriptFrame.address(), &rv); - return parseResumptionValue(ac, ok, rv, vp); + + return parseResumptionValue(ac, ok, rv, MagicValue(JS_UNINITIALIZED_LEXICAL), frame, vp); } void @@ -1677,7 +1739,8 @@ Debugger::onTrap(JSContext* cx, MutableHandleValue vp) RootedValue rv(cx); Rooted handler(cx, bp->handler); bool ok = CallMethodIfPresent(cx, handler, "hit", 1, scriptFrame.address(), &rv); - JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rv, vp, true); + JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), + iter.pc(), vp, true); if (st != JSTRAP_CONTINUE) return st; @@ -1767,8 +1830,10 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp) const Value& handler = frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER); RootedValue rval(cx); + bool ok = Invoke(cx, ObjectValue(*frame), handler, 0, nullptr, &rval); - JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rval, vp); + JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rval, iter.abstractFramePtr(), + iter.pc(), vp); if (st != JSTRAP_CONTINUE) return st; } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 8725c561b73..87c74626e01 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -479,10 +479,13 @@ class Debugger : private mozilla::LinkedListElement * debuggee compartment. */ JSTrapStatus handleUncaughtException(mozilla::Maybe& ac, bool callHook); - JSTrapStatus handleUncaughtException(mozilla::Maybe& ac, MutableHandleValue vp, bool callHook); + JSTrapStatus handleUncaughtException(mozilla::Maybe& ac, MutableHandleValue vp, bool callHook, + const mozilla::Maybe& thisVForCheck = mozilla::Nothing(), + AbstractFramePtr frame = NullFramePtr()); JSTrapStatus handleUncaughtExceptionHelper(mozilla::Maybe& ac, - MutableHandleValue* vp, bool callHook); + MutableHandleValue* vp, bool callHook, + const mozilla::Maybe& thisVForCheck, AbstractFramePtr frame); /* * Handle the result of a hook that is expected to return a resumption @@ -509,9 +512,25 @@ class Debugger : private mozilla::LinkedListElement * anything else - Make a new TypeError the pending exception and * return handleUncaughtException(ac, vp, callHook). */ - JSTrapStatus parseResumptionValue(mozilla::Maybe& ac, bool ok, const Value& rv, + JSTrapStatus parseResumptionValue(mozilla::Maybe& ac, bool OK, const Value& rv, + AbstractFramePtr frame, jsbytecode* pc, MutableHandleValue vp, + bool callHook = true); + + /* + * When we run the onEnterFrame hook, the |this| slot hasn't been fully + * initialized, because the initialzation happens in the function's + * prologue. To combat this, we pass the this for the primitive return + * check directly. When bug 1249193 is fixed, this overload should be + * removed. + */ + JSTrapStatus parseResumptionValue(mozilla::Maybe& ac, bool OK, const Value& rv, + const Value& thisVForCheck, AbstractFramePtr frame, MutableHandleValue vp, bool callHook = true); + JSTrapStatus parseResumptionValueHelper(mozilla::Maybe& ac, bool ok, const Value& rv, + const mozilla::Maybe& thisVForCheck, AbstractFramePtr frame, + MutableHandleValue vp, bool callHook); + GlobalObject* unwrapDebuggeeArgument(JSContext* cx, const Value& v); static void traceObject(JSTracer* trc, JSObject* obj); @@ -617,7 +636,7 @@ class Debugger : private mozilla::LinkedListElement static bool slowPathCheckNoExecute(JSContext* cx, HandleScript script); static JSTrapStatus slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame); - static bool slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok); + static bool slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool ok); static JSTrapStatus slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame); static JSTrapStatus slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame); static void slowPathOnNewScript(JSContext* cx, HandleScript script); @@ -785,7 +804,7 @@ class Debugger : private mozilla::LinkedListElement * throw, or vice versa: we can redirect to a complete copy of the * alternative path, containing its own call to onLeaveFrame.) */ - static inline bool onLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok); + static inline bool onLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc, bool ok); static inline void onNewScript(JSContext* cx, HandleScript script); static inline void onNewGlobalObject(JSContext* cx, Handle global); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 943119b230d..036e2263226 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1021,7 +1021,7 @@ js::UnwindScopeToTryPc(JSScript* script, JSTryNote* tn) static bool ForcedReturn(JSContext* cx, ScopeIter& si, InterpreterRegs& regs, bool frameOk = true) { - bool ok = Debugger::onLeaveFrame(cx, regs.fp(), frameOk); + bool ok = Debugger::onLeaveFrame(cx, regs.fp(), regs.pc, frameOk); UnwindAllScopesInFrame(cx, si); // Point the frame to the end of the script, regardless of error. The // caller must jump to the correct continuation depending on 'ok'. @@ -1207,7 +1207,7 @@ HandleError(JSContext* cx, InterpreterRegs& regs) } ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok); - ok = Debugger::onLeaveFrame(cx, regs.fp(), ok); + ok = Debugger::onLeaveFrame(cx, regs.fp(), regs.pc, ok); } else { // We may be propagating a forced return from the interrupt // callback, which cannot easily force a return. @@ -1907,7 +1907,7 @@ CASE(JSOP_RETRVAL) TraceLogStopEvent(logger, TraceLogger_Engine); TraceLogStopEvent(logger, TraceLogger_Scripts); - interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK); + interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK); REGS.fp()->epilogue(cx); @@ -3993,7 +3993,7 @@ DEFAULT() MOZ_CRASH("Invalid HandleError continuation"); exit: - interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK); + interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK); REGS.fp()->epilogue(cx); diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index e58bdfb28ca..c688bc4f7a9 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -850,6 +850,12 @@ AbstractFramePtr::popWith(JSContext* cx) const asBaselineFrame()->popWith(cx); } +inline bool +AbstractFramePtr::debuggerNeedsCheckPrimitiveReturn() const +{ + return script()->isDerivedClassConstructor(); +} + ActivationEntryMonitor::~ActivationEntryMonitor() { if (entryMonitor_) diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 7738375a8b5..8e12fbf0687 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -216,6 +216,8 @@ class AbstractFramePtr inline Value newTarget() const; + inline bool debuggerNeedsCheckPrimitiveReturn() const; + inline bool isFunctionFrame() const; inline bool isNonStrictDirectEvalFrame() const; inline bool isStrictEvalFrame() const; From f72ae83b222a9d1a6e6b3395370204071f17595a Mon Sep 17 00:00:00 2001 From: Kim Moir Date: Mon, 22 Feb 2016 15:51:22 -0500 Subject: [PATCH 069/252] Bug 1210538 - Add antivirus checks to release promotion graph a=rail --- release/docker/beet-mover/Dockerfile | 19 ++ .../external_tools/extract_and_run_command.py | 205 ++++++++++++++++++ .../mozharness/scripts/release/beet_mover.py | 117 +++++++++- 3 files changed, 329 insertions(+), 12 deletions(-) create mode 100644 release/docker/beet-mover/Dockerfile create mode 100644 testing/mozharness/external_tools/extract_and_run_command.py diff --git a/release/docker/beet-mover/Dockerfile b/release/docker/beet-mover/Dockerfile new file mode 100644 index 00000000000..f109c0e247d --- /dev/null +++ b/release/docker/beet-mover/Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:vivid + +RUN apt-get -q update \ + && apt-get install --yes -q \ + mercurial \ + python-dev \ + python-pip \ + python-virtualenv \ + libffi-dev \ + libssl-dev \ + libyaml-dev \ + libmysqlclient-dev \ + clamav \ + clamav-freshclam \ + curl \ + wget \ + && apt-get clean + +RUN freshclam --verbose diff --git a/testing/mozharness/external_tools/extract_and_run_command.py b/testing/mozharness/external_tools/extract_and_run_command.py new file mode 100644 index 00000000000..ab48ee1dff6 --- /dev/null +++ b/testing/mozharness/external_tools/extract_and_run_command.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +"""\ +Usage: extract_and_run_command.py [-j N] [command to run] -- [files and/or directories] + -j is the number of workers to start, defaulting to 1. + [command to run] must be a command that can accept one or many files + to process as arguments. + +WARNING: This script does NOT respond to SIGINT. You must use SIGQUIT or SIGKILL to + terminate it early. + """ + +### The canonical location for this file is +### https://hg.mozilla.org/build/tools/file/default/stage/extract_and_run_command.py +### +### Please update the copy in puppet to deploy new changes to +### stage.mozilla.org, see +# https://wiki.mozilla.org/ReleaseEngineering/How_To/Modify_scripts_on_stage + +import logging +import os +from os import path +import sys +from Queue import Queue +import shutil +import subprocess +import tempfile +from threading import Thread +import time + +logging.basicConfig( + stream=sys.stdout, level=logging.INFO, format="%(message)s") +log = logging.getLogger(__name__) + +try: + # the future - https://github.com/mozilla/build-mar via a venv + from mardor.marfile import BZ2MarFile +except: + # the past - http://hg.mozilla.org/build/tools/file/default/buildfarm/utils/mar.py + sys.path.append( + path.join(path.dirname(path.realpath(__file__)), "../buildfarm/utils")) + from mar import BZ2MarFile + +SEVENZIP = "7za" + + +def extractMar(filename, tempdir): + m = BZ2MarFile(filename) + m.extractall(path=tempdir) + + +def extractExe(filename, tempdir): + try: + # We don't actually care about output, put we redirect to a tempfile + # to avoid deadlocking in wait() when stdout=PIPE + fd = tempfile.TemporaryFile() + proc = subprocess.Popen([SEVENZIP, 'x', '-o%s' % tempdir, filename], + stdout=fd, stderr=subprocess.STDOUT) + proc.wait() + except subprocess.CalledProcessError: + # Not all EXEs are 7-zip files, so we have to ignore extraction errors + pass + +# The keys here are matched against the last 3 characters of filenames. +# The values are callables that accept two string arguments. +EXTRACTORS = { + '.mar': extractMar, + '.exe': extractExe, +} + + +def find_files(d): + """yields all of the files in `d'""" + for root, dirs, files in os.walk(d): + for f in files: + yield path.abspath(path.join(root, f)) + + +def rchmod(d, mode=0755): + """chmods everything in `d' to `mode', including `d' itself""" + os.chmod(d, mode) + for root, dirs, files in os.walk(d): + for item in dirs: + os.chmod(path.join(root, item), mode) + for item in files: + os.chmod(path.join(root, item), mode) + + +def maybe_extract(filename): + """If an extractor is found for `filename', extracts it to a temporary + directory and chmods it. The consumer is responsible for removing + the extracted files, if desired.""" + ext = path.splitext(filename)[1] + if ext not in EXTRACTORS.keys(): + return None + # Append the full filepath to the tempdir + tempdir_root = tempfile.mkdtemp() + tempdir = path.join(tempdir_root, filename.lstrip('/')) + os.makedirs(tempdir) + EXTRACTORS[ext](filename, tempdir) + rchmod(tempdir_root) + return tempdir_root + + +def process(item, command): + def format_time(t): + return time.strftime("%H:%M:%S", time.localtime(t)) + # Buffer output to avoid interleaving of multiple workers' + logs = [] + args = [item] + proc = None + start = time.time() + logs.append("START %s: %s" % (format_time(start), item)) + # If the file was extracted, we need to process all of its files, too. + tempdir = maybe_extract(item) + if tempdir: + for f in find_files(tempdir): + args.append(f) + + try: + fd = tempfile.TemporaryFile() + proc = subprocess.Popen(command + args, stdout=fd) + proc.wait() + if proc.returncode != 0: + raise Exception("returned %s" % proc.returncode) + finally: + if tempdir: + shutil.rmtree(tempdir) + fd.seek(0) + # rstrip() here to avoid an unnecessary newline, if it exists. + logs.append(fd.read().rstrip()) + end = time.time() + elapsed = end - start + logs.append("END %s (%d seconds elapsed): %s\n" % ( + format_time(end), elapsed, item)) + # Now that we've got all of our output, print it. It's important that + # the logging module is used for this, because "print" is not + # thread-safe. + log.info("\n".join(logs)) + + +def worker(command, errors): + item = q.get() + while item != None: + try: + process(item, command) + except: + errors.put(item) + item = q.get() + +if __name__ == '__main__': + # getopt is used in favour of optparse to enable "--" as a separator + # between the command and list of files. optparse doesn't allow that. + from getopt import getopt + options, args = getopt(sys.argv[1:], 'j:h', ['help']) + + concurrency = 1 + for o, a in options: + if o == '-j': + concurrency = int(a) + elif o in ('-h', '--help'): + log.info(__doc__) + sys.exit(0) + + if len(args) < 3 or '--' not in args: + log.error(__doc__) + sys.exit(1) + + command = [] + while args[0] != "--": + command.append(args.pop(0)) + args.pop(0) + + q = Queue() + errors = Queue() + threads = [] + for i in range(concurrency): + t = Thread(target=worker, args=(command, errors)) + t.start() + threads.append(t) + + # find_files is a generator, so work will begin prior to it finding + # all of the files + for arg in args: + if path.isfile(arg): + q.put(arg) + else: + for f in find_files(arg): + q.put(f) + # Because the workers are started before we start populating the q + # they can't use .empty() to determine whether or not their done. + # We also can't use q.join() or j.task_done(), because we need to + # support Python 2.4. We know that find_files won't yield None, + # so we can detect doneness by having workers die when they get None + # as an item. + for i in range(concurrency): + q.put(None) + + for t in threads: + t.join() + + if not errors.empty(): + log.error("Command failed for the following files:") + while not errors.empty(): + log.error(" %s" % errors.get()) + sys.exit(1) diff --git a/testing/mozharness/scripts/release/beet_mover.py b/testing/mozharness/scripts/release/beet_mover.py index 0d6ebf037c9..4a0634acd14 100755 --- a/testing/mozharness/scripts/release/beet_mover.py +++ b/testing/mozharness/scripts/release/beet_mover.py @@ -6,17 +6,21 @@ # ***** END LICENSE BLOCK ***** """beet_mover.py. -downloads artifacts and uploads them to s3 +downloads artifacts, scans them and uploads them to s3 """ import hashlib import sys import os import pprint +import re +from os import listdir +from os.path import isfile, join sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0]))) from mozharness.base.log import FATAL from mozharness.base.python import VirtualenvMixin from mozharness.base.script import BaseScript +import mozharness def get_hash(content, hash_type="md5"): @@ -85,8 +89,39 @@ CONFIG_OPTIONS = [ "default": False, "help": "taskcluster task id to download artifacts from", }], + [["--exclude"], { + "dest": "excludes", + "action": "append", + "help": "List of filename patterns to exclude. See script source for default", + }], + [["-s", "--scan-parallelization"], { + "dest": "scan_parallelization", + "default": 4, + "type": "int", + "help": "Number of concurrent file scans", + }], ] +DEFAULT_EXCLUDES = [ + r"^.*tests.*$", + r"^.*crashreporter.*$", + r"^.*\.zip(\.asc)?$", + r"^.*\.log$", + r"^.*\.txt$", + r"^.*\.asc$", + r"^.*/partner-repacks.*$", + r"^.*.checksums(\.asc)?$", + r"^.*/logs/.*$", + r"^.*/jsshell.*$", + r"^.*json$", + r"^.*/host.*$", + r"^.*/mar-tools/.*$", + r"^.*gecko-unsigned-unaligned.apk$", + r"^.*robocop.apk$", + r"^.*contrib.*" +] +CACHE_DIR = 'cache' + class BeetMover(BaseScript, VirtualenvMixin, object): def __init__(self, aws_creds): @@ -98,6 +133,8 @@ class BeetMover(BaseScript, VirtualenvMixin, object): 'activate-virtualenv', 'generate-candidates-manifest', 'verify-bits', # beets + 'download-bits', # beets + 'scan-bits', # beets 'upload-bits', # beets ], 'require_config_file': False, @@ -111,6 +148,8 @@ class BeetMover(BaseScript, VirtualenvMixin, object): "boto", "PyYAML", "Jinja2", + "redo", + "mar", ], "virtualenv_path": "venv", 'buckets': { @@ -120,6 +159,7 @@ class BeetMover(BaseScript, VirtualenvMixin, object): 'product': 'firefox', }, } + #todo do excludes need to be configured via command line for specific builds? super(BeetMover, self).__init__(**beetmover_kwargs) c = self.config @@ -128,6 +168,10 @@ class BeetMover(BaseScript, VirtualenvMixin, object): self.virtualenv_imports = None self.bucket = c['buckets']['production'] if c['production'] else c['buckets']['development'] self.aws_key_id, self.aws_secret_key = aws_creds + # if excludes is set from command line, use it otherwise use defaults + self.excludes = self.config.get('excludes', DEFAULT_EXCLUDES) + dirs = self.query_abs_dirs() + self.dest_dir = os.path.join(dirs['abs_work_dir'], CACHE_DIR) def activate_virtualenv(self): """ @@ -172,7 +216,7 @@ class BeetMover(BaseScript, VirtualenvMixin, object): # mirror current release folder structure "s3_prefix": 'pub/{}/candidates'.format(self.config['product']), "artifact_base_url": self.config['artifact_base_url'].format( - taskid=self.config['taskid'], subdir=self.config['artifact_sudbir'] + taskid=self.config['taskid'], subdir=self.config['artifact_subdir'] ) } self.manifest = yaml.safe_load(template.render(**template_vars)) @@ -187,37 +231,60 @@ class BeetMover(BaseScript, VirtualenvMixin, object): # TODO self.log('skipping verification. unimplemented...') + def download_bits(self): + """ + downloads list of artifacts to self.dest_dir dir based on a given manifest + """ + self.log('downloading and uploading artifacts to self_dest_dir...') + + # TODO - do we want to mirror/upload to more than one region? + dirs = self.query_abs_dirs() + + for locale in self.manifest['mapping']: + for deliverable in self.manifest['mapping'][locale]: + self.log("downloading '{}' deliverable for '{}' locale".format(deliverable, locale)) + # download locally to working dir + source=self.manifest['mapping'][locale][deliverable]['artifact'] + file_name = self.retry(self.download_file, + args=[source], + kwargs={'parent_dir': dirs['abs_work_dir']}, + error_level=FATAL) + self.log('Success!') + def upload_bits(self): """ - downloads and uploads list of artifacts to s3 candidates dir based on a given manifest + uploads list of artifacts to s3 candidates dir based on a given manifest """ - self.log('downloading and uploading artifacts to s3...') + self.log('uploading artifacts to s3...') + dirs = self.query_abs_dirs() # connect to s3 boto = self.virtualenv_imports['boto'] conn = boto.connect_s3(self.aws_key_id, self.aws_secret_key) bucket = conn.get_bucket(self.bucket) + #todo change so this is not every entry in manifest - should exclude those that don't pass virus sign + #not sure how to determine this for locale in self.manifest['mapping']: for deliverable in self.manifest['mapping'][locale]: self.log("uploading '{}' deliverable for '{}' locale".format(deliverable, locale)) + #we have already downloaded the files locally so we can use that version + source = self.manifest['mapping'][locale][deliverable]['artifact'] + downloaded_file = os.path.join(dirs['abs_work_dir'], self.get_filename_from_url(source)) self.upload_bit( - source=self.manifest['mapping'][locale][deliverable]['artifact'], + source=downloaded_file, s3_key=self.manifest['mapping'][locale][deliverable]['s3_key'], bucket=bucket, ) self.log('Success!') + def upload_bit(self, source, s3_key, bucket): # TODO - do we want to mirror/upload to more than one region? dirs = self.query_abs_dirs() boto = self.virtualenv_imports['boto'] - # download locally - file_name = self.retry(self.download_file, - args=[source], - kwargs={'parent_dir': dirs['abs_work_dir']}, - error_level=FATAL) + #todo need to copy from dir to s3 self.info('uploading to s3 with key: {}'.format(s3_key)) key = boto.s3.key.Key(bucket) # create new key @@ -230,20 +297,46 @@ class BeetMover(BaseScript, VirtualenvMixin, object): key = bucket.new_key(s3_key) # set key value - self.retry(key.set_contents_from_filename, args=[file_name], error_level=FATAL), + self.retry(key.set_contents_from_filename, args=[source], error_level=FATAL), # key.make_public() may lead to race conditions, because # it doesn't pass version_id, so it may not set permissions bucket.set_canned_acl(acl_str='public-read', key_name=s3_key, version_id=key.version_id) else: - if not get_hash(key.get_contents_as_string()) == get_hash(open(file_name).read()): + if not get_hash(key.get_contents_as_string()) == get_hash(open(source).read()): # for now, let's halt. If necessary, we can revisit this and allow for overwrites # to the same buildnum release with different bits self.fatal("`{}` already exists with different checksum.".format(s3_key)) self.log("`{}` has the same MD5 checksum, not uploading".format(s3_key)) + def scan_bits(self): + dirs = self.query_abs_dirs() + + filenames = [f for f in listdir(dirs['abs_work_dir']) if isfile(join(dirs['abs_work_dir'], f))] + self.mkdir_p(self.dest_dir) + for file_name in filenames: + if self._matches_exclude(file_name): + self.info("Excluding {} from virus scan".format(file_name)) + else: + self.info('Copying {} to {}'.format(file_name,self.dest_dir)) + self.copyfile(os.path.join(dirs['abs_work_dir'], file_name), os.path.join(self.dest_dir,file_name)) + self._scan_files() + self.info('Emptying {}'.format(self.dest_dir)) + self.rmtree(self.dest_dir) + + def _scan_files(self): + """Scan the files we've collected. We do the download and scan concurrently to make + it easier to have a coherent log afterwards. Uses the venv python.""" + external_tools_path = os.path.join( + os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), 'external_tools') + self.run_command([self.query_python_path(), os.path.join(external_tools_path,'extract_and_run_command.py'), + '-j{}'.format(self.config['scan_parallelization']), + 'clamscan', '--no-summary', '--', self.dest_dir]) + + def _matches_exclude(self, keyname): + return any(re.search(exclude, keyname) for exclude in self.excludes) if __name__ == '__main__': beet_mover = BeetMover(get_aws_auth()) From 81b8c3a644dbd5faec870348966ea9bb162773a2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 22 Feb 2016 11:53:59 -0500 Subject: [PATCH 070/252] Bug 1250196 - Part 1: Import mozilla::Forward and mozilla::UniqePtr into the std namespace in a way that is compatible with libc++; r=lsalzman --- gfx/skia/skia/include/private/SkTLogic.h | 15 ++++++++++++++- gfx/skia/skia/include/private/SkUniquePtr.h | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gfx/skia/skia/include/private/SkTLogic.h b/gfx/skia/skia/include/private/SkTLogic.h index 7072b516e96..f94d13ecf8e 100644 --- a/gfx/skia/skia/include/private/SkTLogic.h +++ b/gfx/skia/skia/include/private/SkTLogic.h @@ -32,10 +32,23 @@ #include "mozilla/Function.h" #endif -namespace std { +// In libc++, symbols such as std::forward may be defined in std::__1. +// The _LIBCPP_BEGIN_NAMESPACE_STD and _LIBCPP_END_NAMESPACE_STD macros +// will expand to the correct namespace. +#ifdef _LIBCPP_BEGIN_NAMESPACE_STD +#define MOZ_BEGIN_STD_NAMESPACE _LIBCPP_BEGIN_NAMESPACE_STD +#define MOZ_END_STD_NAMESPACE _LIBCPP_END_NAMESPACE_STD +#else +#define MOZ_BEGIN_STD_NAMESPACE namespace std { +#define MOZ_END_STD_NAMESPACE } +#endif + +MOZ_BEGIN_STD_NAMESPACE using mozilla::Forward; #define forward Forward +MOZ_END_STD_NAMESPACE +namespace std { #if SKIA_IMPLEMENTATION using mozilla::IntegralConstant; using mozilla::IsEmpty; diff --git a/gfx/skia/skia/include/private/SkUniquePtr.h b/gfx/skia/skia/include/private/SkUniquePtr.h index 43ce3172f0d..474fc9ed420 100644 --- a/gfx/skia/skia/include/private/SkUniquePtr.h +++ b/gfx/skia/skia/include/private/SkUniquePtr.h @@ -15,6 +15,11 @@ #ifdef MOZ_SKIA #include "mozilla/UniquePtr.h" +namespace std { + using mozilla::DefaultDelete; + using mozilla::UniquePtr; +} + namespace skstd { using mozilla::DefaultDelete; using mozilla::UniquePtr; From 98a72eadcd47af2eb992eeff1a2eb08c9c9deaa5 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 22 Feb 2016 11:54:36 -0500 Subject: [PATCH 071/252] Bug 1250196 - Part 2: Rename UniquePtr::getDeleter() to get_deleter() in order to make it compatible with std::unique_ptr; r=froydnj --- mfbt/UniquePtr.h | 22 +++++++++++----------- mfbt/tests/TestUniquePtr.cpp | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mfbt/UniquePtr.h b/mfbt/UniquePtr.h index 5dc15cd01c1..9381cca5a4a 100644 --- a/mfbt/UniquePtr.h +++ b/mfbt/UniquePtr.h @@ -226,7 +226,7 @@ public: } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -247,7 +247,7 @@ public: ? IsSame::value : IsConvertible::value), int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) { } @@ -256,7 +256,7 @@ public: UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -270,7 +270,7 @@ public: "can't assign from UniquePtr holding an array"); reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -291,8 +291,8 @@ public: Pointer get() const { return ptr(); } - DeleterType& getDeleter() { return del(); } - const DeleterType& getDeleter() const { return del(); } + DeleterType& get_deleter() { return del(); } + const DeleterType& get_deleter() const { return del(); } MOZ_WARN_UNUSED_RESULT Pointer release() { @@ -306,7 +306,7 @@ public: Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { - getDeleter()(old); + get_deleter()(old); } } @@ -395,7 +395,7 @@ public: = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -411,7 +411,7 @@ public: UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -426,8 +426,8 @@ public: T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } Pointer get() const { return mTuple.first(); } - DeleterType& getDeleter() { return mTuple.second(); } - const DeleterType& getDeleter() const { return mTuple.second(); } + DeleterType& get_deleter() { return mTuple.second(); } + const DeleterType& get_deleter() const { return mTuple.second(); } MOZ_WARN_UNUSED_RESULT Pointer release() { diff --git a/mfbt/tests/TestUniquePtr.cpp b/mfbt/tests/TestUniquePtr.cpp index 3455d649734..27d13e596c2 100644 --- a/mfbt/tests/TestUniquePtr.cpp +++ b/mfbt/tests/TestUniquePtr.cpp @@ -292,7 +292,7 @@ TestReferenceDeleterGuts() IntDeleterRef id2(Move(id1)); CHECK(id1 == nullptr); CHECK(nullptr != id2); - CHECK(&id1.getDeleter() == &id2.getDeleter()); + CHECK(&id1.get_deleter() == &id2.get_deleter()); IntDeleterRef id3(Move(id2)); From 688fa7af226e948301a1c179b6cc636e8f0dd4ba Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 22 Feb 2016 13:18:13 +0000 Subject: [PATCH 072/252] Bug 1242655 - Have ActionChain#dispatchActions return a promise; r=automatedtester MozReview-Commit-ID: ITqAH4rVsHc --- testing/marionette/action.js | 78 +++++++++++++++++----------------- testing/marionette/driver.js | 7 +-- testing/marionette/listener.js | 15 +++---- 3 files changed, 48 insertions(+), 52 deletions(-) diff --git a/testing/marionette/action.js b/testing/marionette/action.js index c74d667bde1..b6620e6ad74 100644 --- a/testing/marionette/action.js +++ b/testing/marionette/action.js @@ -34,9 +34,6 @@ action.Chain = function(checkForInterrupted) { this.mouseEventsOnly = false; this.checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - // callbacks for command completion - this.onSuccess = null; - this.onError = null; if (typeof checkForInterrupted == "function") { this.checkForInterrupted = checkForInterrupted; } else { @@ -52,7 +49,6 @@ action.Chain.prototype.dispatchActions = function( touchId, container, elementManager, - callbacks, touchProvider) { // Some touch events code in the listener needs to do ipc, so we can't // share this code across chrome/content. @@ -62,8 +58,6 @@ action.Chain.prototype.dispatchActions = function( this.elementManager = elementManager; let commandArray = elementManager.convertWrappedArguments(args, container); - this.onSuccess = callbacks.onSuccess; - this.onError = callbacks.onError; this.container = container; if (touchId == null) { @@ -78,15 +72,12 @@ action.Chain.prototype.dispatchActions = function( shiftKey: false, ctrlKey: false, altKey: false, - metaKey: false + metaKey: false, }; - try { - this.actions(commandArray, touchId, 0, keyModifiers); - } catch (e) { - callbacks.onError(e); - this.resetValues(); - } + return new Promise(resolve => { + this.actions(commandArray, touchId, 0, keyModifiers, resolve); + }).catch(this.resetValues); }; /** @@ -115,10 +106,10 @@ action.Chain.prototype.emitMouseEvent = function( modifiers) { if (!this.checkForInterrupted()) { logger.debug(`Emitting ${type} mouse event ` + - `at coordinates (${elClientX}, ${elClientY}) ` + - `relative to the viewport, ` + - `button: ${button}, ` + - `clickCount: ${clickCount}`); + `at coordinates (${elClientX}, ${elClientY}) ` + + `relative to the viewport, ` + + `button: ${button}, ` + + `clickCount: ${clickCount}`); let win = doc.defaultView; let domUtils = win.QueryInterface(Ci.nsIInterfaceRequestor) @@ -148,8 +139,6 @@ action.Chain.prototype.emitMouseEvent = function( * Reset any persisted values after a command completes. */ action.Chain.prototype.resetValues = function() { - this.onSuccess = null; - this.onError = null; this.container = null; this.elementManager = null; this.touchProvider = null; @@ -157,15 +146,28 @@ action.Chain.prototype.resetValues = function() { }; /** - * Function to emit touch events for each finger. e.g. - * finger=[['press', id], ['wait', 5], ['release']] touchId represents - * the finger id, i keeps track of the current action of the chain - * keyModifiers is an object keeping track keyDown/keyUp pairs through - * an action chain. + * Emit events for each action in the provided chain. + * + * To emit touch events for each finger, one might send a [["press", id], + * ["wait", 5], ["release"]] chain. + * + * @param {Array.>} chain + * A multi-dimensional array of actions. + * @param {Object.} touchId + * Represents the finger ID. + * @param {number} i + * Keeps track of the current action of the chain. + * @param {Object.} keyModifiers + * Keeps track of keyDown/keyUp pairs through an action chain. + * @param {function(?)} cb + * Called on success. + * + * @return {Object.} + * Last finger ID, or an empty object. */ -action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { +action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers, cb) { if (i == chain.length) { - this.onSuccess(touchId || null); + cb(touchId || null); this.resetValues(); return; } @@ -184,15 +186,15 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { } } - switch(command) { + switch (command) { case "keyDown": event.sendKeyDown(pack[1], keyModifiers, this.container.frame); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "keyUp": event.sendKeyUp(pack[1], keyModifiers, this.container.frame); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "click": @@ -205,7 +207,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { this.emitMouseEvent(el.ownerDocument, "contextmenu", c.x, c.y, button, clickCount, keyModifiers); } - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "press": @@ -230,7 +232,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { el = this.elementManager.getKnownElement(pack[1], this.container); c = this.coordinates(el, pack[2], pack[3]); touchId = this.generateEvents("press", c.x, c.y, null, el, keyModifiers); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "release": @@ -241,7 +243,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { touchId, null, keyModifiers); - this.actions(chain, null, i, keyModifiers); + this.actions(chain, null, i, keyModifiers, cb); this.scrolling = false; break; @@ -249,7 +251,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { el = this.elementManager.getKnownElement(pack[1], this.container); c = this.coordinates(el); this.generateEvents("move", c.x, c.y, touchId, null, keyModifiers); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "moveByOffset": @@ -260,7 +262,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { touchId, null, keyModifiers); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; case "wait": @@ -277,10 +279,10 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { time = standard; } this.checkTimer.initWithCallback( - () => this.actions(chain, touchId, i, keyModifiers), + () => this.actions(chain, touchId, i, keyModifiers, cb), time, Ci.nsITimer.TYPE_ONE_SHOT); } else { - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); } break; @@ -292,7 +294,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { touchId, null, keyModifiers); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); this.scrolling = false; break; @@ -304,7 +306,7 @@ action.Chain.prototype.actions = function(chain, touchId, i, keyModifiers) { touchId, null, keyModifiers); - this.actions(chain, touchId, i, keyModifiers); + this.actions(chain, touchId, i, keyModifiers, cb); break; } }; diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index 94de6262352..9eda1e608d5 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -1859,13 +1859,10 @@ GeckoDriver.prototype.actionChain = function*(cmd, resp) { "Command 'actionChain' is not available in chrome context"); } - let cbs = {}; - cbs.onSuccess = val => resp.body.value = val; - cbs.onError = err => { throw err; }; - let win = this.getCurrentWindow(); let elm = this.curBrowser.elementManager; - this.actions.dispatchActions(chain, nextId, {frame: win}, elm, cbs); + resp.body.value = yield this.actions.dispatchActions( + chain, nextId, {frame: win}, elm); break; case Context.CONTENT: diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index cc11b3c8029..333a20ea538 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -935,15 +935,12 @@ function actionChain(chain, touchId) { touchProvider.createATouch = createATouch; touchProvider.emitTouchEvent = emitTouchEvent; - return new Promise((resolve, reject) => { - actions.dispatchActions( - chain, - touchId, - curContainer, - elementManager, - {onSuccess: resolve, onError: reject}, - touchProvider); - }); + return actions.dispatchActions( + chain, + touchId, + curContainer, + elementManager, + touchProvider); } /** From 6d5885d0088a133688dcc1f434166d6e470e424f Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Fri, 19 Feb 2016 16:59:37 -0500 Subject: [PATCH 073/252] Bug 1249777: Added support for 10.11 in the blocklisting code as well. r=mstange MozReview-Commit-ID: JCkFwfkEyEa --- widget/GfxDriverInfo.h | 1 + widget/GfxInfoBase.cpp | 2 ++ widget/cocoa/GfxInfo.mm | 2 ++ 3 files changed, 5 insertions(+) diff --git a/widget/GfxDriverInfo.h b/widget/GfxDriverInfo.h index eeb8d58db6e..356a96767a1 100644 --- a/widget/GfxDriverInfo.h +++ b/widget/GfxDriverInfo.h @@ -54,6 +54,7 @@ enum OperatingSystem { DRIVER_OS_OS_X_10_8, DRIVER_OS_OS_X_10_9, DRIVER_OS_OS_X_10_10, + DRIVER_OS_OS_X_10_11, DRIVER_OS_ANDROID, DRIVER_OS_IOS, DRIVER_OS_ALL diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index 3e24ac89599..a17ec74e4ea 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -280,6 +280,8 @@ BlacklistOSToOperatingSystem(const nsAString& os) return DRIVER_OS_OS_X_10_9; else if (os.EqualsLiteral("Darwin 14")) return DRIVER_OS_OS_X_10_10; + else if (os.EqualsLiteral("Darwin 15")) + return DRIVER_OS_OS_X_10_11; else if (os.EqualsLiteral("Android")) return DRIVER_OS_ANDROID; else if (os.EqualsLiteral("All")) diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 2b8949c7d26..1dacc621c4d 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -50,6 +50,8 @@ OSXVersionToOperatingSystem(uint32_t aOSXVersion) return DRIVER_OS_OS_X_10_9; case 10: return DRIVER_OS_OS_X_10_10; + case 11: + return DRIVER_OS_OS_X_10_11; } } From d0a4cb821ebc79db2b00be6bc5a1a001c2b1cfad Mon Sep 17 00:00:00 2001 From: Rail Aliiev Date: Mon, 22 Feb 2016 12:51:09 -0800 Subject: [PATCH 074/252] Bug 1178286 - switch release automation source builder to taskcluster r=jlund --- .../releng_sub_linux_configs/64_source.py | 6 +-- .../mozharness/mozilla/building/buildbase.py | 37 +++++++++++++++++-- .../mozharness/mozharness/mozilla/signing.py | 17 +++++++++ .../mozharness/scripts/fx_desktop_build.py | 1 + 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_source.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_source.py index b6e5509680e..dfc87cdf1b0 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_source.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_source.py @@ -5,6 +5,7 @@ config = { 'checkout-sources', 'setup-mock', 'package-source', + 'generate-source-signing-manifest', ], 'stage_platform': 'source', # Not used, but required by the script 'buildbot_json_path': 'buildprops.json', @@ -15,8 +16,5 @@ config = { 'TINDERBOX_OUTPUT': '1', 'LC_ALL': 'C', }, - 'tooltool_script': ["/builds/tooltool.py"], - 'tooltool_bootstrap': "setup.sh", - 'tooltool_manifest_src': "browser/config/tooltool-manifests/linux64/releng.manifest", - 'src_mozconfig': 'browser/config/mozconfigs/linux64/nightly', + 'src_mozconfig': 'browser/config/mozconfigs/linux64/source', } diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py index 64d0c7eba1b..4f9157a4338 100755 --- a/testing/mozharness/mozharness/mozilla/building/buildbase.py +++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py @@ -1883,28 +1883,57 @@ or run without that action (ie: --no-{action})" def preflight_package_source(self): self._get_mozconfig() - self._run_tooltool() def package_source(self): """generates source archives and uploads them""" env = self.query_build_env() env.update(self.query_mach_build_env()) python = self.query_exe('python2.7') + dirs = self.query_abs_dirs() self.run_command_m( command=[python, 'mach', '--log-no-times', 'configure'], - cwd=self.query_abs_dirs()['abs_src_dir'], + cwd=dirs['abs_src_dir'], env=env, output_timeout=60*3, halt_on_failure=True, ) self.run_command_m( command=[ - 'make', 'source-package', 'hg-bundle', + 'make', 'source-package', 'hg-bundle', 'source-upload', 'HG_BUNDLE_REVISION=%s' % self.query_revision(), + 'UPLOAD_HG_BUNDLE=1', ], - cwd=self.query_abs_dirs()['abs_obj_dir'], + cwd=dirs['abs_obj_dir'], env=env, output_timeout=60*45, halt_on_failure=True, ) + def generate_source_signing_manifest(self): + """Sign source checksum file""" + env = self.query_build_env() + env.update(self.query_mach_build_env()) + if env.get("UPLOAD_HOST") != "localhost": + self.warning("Skipping signing manifest generation. Set " + "UPLOAD_HOST to `localhost' to enable.") + return + + if not env.get("UPLOAD_PATH"): + self.warning("Skipping signing manifest generation. Set " + "UPLOAD_PATH to enable.") + return + + dirs = self.query_abs_dirs() + objdir = dirs['abs_obj_dir'] + + output = self.get_output_from_command_m( + command=['make', 'echo-variable-SOURCE_CHECKSUM_FILE'], + cwd=objdir, + ) + files = shlex.split(output) + abs_files = [os.path.abspath(os.path.join(objdir, f)) for f in files] + manifest_file = os.path.join(env["UPLOAD_PATH"], + "signing_manifest.json") + self.write_to_file(manifest_file, + self.generate_signing_manifest(abs_files)) + def check_test(self): c = self.config dirs = self.query_abs_dirs() diff --git a/testing/mozharness/mozharness/mozilla/signing.py b/testing/mozharness/mozharness/mozilla/signing.py index 386d30aceae..3b16ce59523 100755 --- a/testing/mozharness/mozharness/mozilla/signing.py +++ b/testing/mozharness/mozharness/mozilla/signing.py @@ -9,6 +9,7 @@ import os import re +import json from mozharness.base.errors import BaseErrorList from mozharness.base.log import ERROR, FATAL @@ -60,6 +61,22 @@ class SigningMixin(BaseSigningMixin): cmd += ['-H', h] return cmd + def generate_signing_manifest(self, files): + """Generate signing manifest for signingworkers + + Every entry in the manifest requires a dictionary of + "file_to_sign" (basename) and "hash" (SHA512) of every file to be + signed. Signing format is defined in the signing task. + """ + manifest_content = [ + { + "file_to_sign": os.path.basename(f), + "hash": self.query_sha512sum(f) + } + for f in files + ] + return json.dumps(manifest_content) + # MobileSigningMixin {{{1 class MobileSigningMixin(AndroidSigningMixin, SigningMixin): diff --git a/testing/mozharness/scripts/fx_desktop_build.py b/testing/mozharness/scripts/fx_desktop_build.py index d360a6bcf60..ddda2774c99 100755 --- a/testing/mozharness/scripts/fx_desktop_build.py +++ b/testing/mozharness/scripts/fx_desktop_build.py @@ -37,6 +37,7 @@ class FxDesktopBuild(BuildScript, object): 'sendchange', 'check-test', 'package-source', + 'generate-source-signing-manifest', 'multi-l10n', 'generate-build-stats', 'update', From 1cd4aa0ba8387181eba93d69c693a4878e79663a Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Fri, 19 Feb 2016 17:33:54 -0800 Subject: [PATCH 075/252] Bug 1249604 - Don't use gtk_drag_set_icon_surface on GTK versions that use X SHAPE for dnd with cairo. r=karlt MozReview-Commit-ID: 2XxnJfvfOXl --- widget/gtk/nsDragService.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp index 5d654e41806..43b52d2dda6 100644 --- a/widget/gtk/nsDragService.cpp +++ b/widget/gtk/nsDragService.cpp @@ -468,6 +468,13 @@ nsDragService::SetAlphaPixmap(SourceSurface *aSurface, #ifdef cairo_image_surface_create #error "Looks like we're including Mozilla's cairo instead of system cairo" #endif + // Prior to GTK 3.9.12, cairo surfaces passed into gtk_drag_set_icon_surface + // had their shape information derived from the alpha channel and used with + // the X SHAPE extension instead of being displayed as an ARGB window. + // See bug 1249604. + if (gtk_check_version(3, 9, 12)) + return false; + // TODO: grab X11 pixmap or image data instead of expensive readback. cairo_surface_t *surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dragRect.width, From 8dd639ccf96d2d5037a7f3db616474889ed51741 Mon Sep 17 00:00:00 2001 From: Dylan Roeh Date: Tue, 9 Feb 2016 15:33:34 -0600 Subject: [PATCH 076/252] Bug 1148544 - Figure out UA override once per LoadGroup and cache it, rather than once per channel. r=nwgh --- netwerk/base/nsILoadGroup.idl | 8 ++++- netwerk/base/nsLoadGroup.cpp | 24 ++++++++++--- netwerk/base/nsLoadGroup.h | 6 ++-- netwerk/protocol/http/HttpBaseChannel.cpp | 35 +++++++++++++++++++ netwerk/protocol/http/HttpBaseChannel.h | 2 ++ netwerk/protocol/http/HttpChannelChild.cpp | 5 ++- netwerk/protocol/http/UserAgentOverrides.jsm | 8 ++--- netwerk/protocol/http/nsHttpChannel.cpp | 5 +++ netwerk/protocol/http/nsHttpHandler.h | 6 ++++ .../protocol/http/nsIHttpProtocolHandler.idl | 9 +++++ 10 files changed, 95 insertions(+), 13 deletions(-) diff --git a/netwerk/base/nsILoadGroup.idl b/netwerk/base/nsILoadGroup.idl index ae4a1ebabcb..7b9d6735dfd 100644 --- a/netwerk/base/nsILoadGroup.idl +++ b/netwerk/base/nsILoadGroup.idl @@ -58,7 +58,7 @@ interface nsILoadGroup : nsIRequest * By the time this call ends, aRequest will have been removed from the * loadgroup, even if this function throws an exception. */ - void removeRequest(in nsIRequest aRequest, + void removeRequest(in nsIRequest aRequest, in nsISupports aContext, in nsresult aStatus); @@ -97,4 +97,10 @@ interface nsILoadGroup : nsIRequest * the docShell has created the default request.) */ attribute nsLoadFlags defaultLoadFlags; + + /** + * The cached user agent override created by UserAgentOverrides.jsm. Used + * for all sub-resource requests in the loadgroup. + */ + attribute ACString userAgentOverrideCache; }; diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp index 1c922910e28..a68dad72ae1 100644 --- a/netwerk/base/nsLoadGroup.cpp +++ b/netwerk/base/nsLoadGroup.cpp @@ -172,7 +172,7 @@ nsLoadGroup::GetName(nsACString &result) result.Truncate(); return NS_OK; } - + return mDefaultLoadRequest->GetName(result); } @@ -188,9 +188,9 @@ nsLoadGroup::GetStatus(nsresult *status) { if (NS_SUCCEEDED(mStatus) && mDefaultLoadRequest) return mDefaultLoadRequest->GetStatus(status); - + *status = mStatus; - return NS_OK; + return NS_OK; } static bool @@ -480,7 +480,7 @@ nsLoadGroup::AddRequest(nsIRequest *request, nsISupports* ctxt) rv = MergeLoadFlags(request, flags); } if (NS_FAILED(rv)) return rv; - + // // Add the request to the list of active requests... // @@ -810,10 +810,24 @@ nsLoadGroup::SetDefaultLoadFlags(uint32_t aFlags) return NS_OK; } +NS_IMETHODIMP +nsLoadGroup::GetUserAgentOverrideCache(nsACString & aUserAgentOverrideCache) +{ + aUserAgentOverrideCache = mUserAgentOverrideCache; + return NS_OK; +} + +NS_IMETHODIMP +nsLoadGroup::SetUserAgentOverrideCache(const nsACString & aUserAgentOverrideCache) +{ + mUserAgentOverrideCache = aUserAgentOverrideCache; + return NS_OK; +} + //////////////////////////////////////////////////////////////////////////////// -void +void nsLoadGroup::TelemetryReport() { if (mDefaultLoadIsTimed) { diff --git a/netwerk/base/nsLoadGroup.h b/netwerk/base/nsLoadGroup.h index c45111a4c09..9349e79a610 100644 --- a/netwerk/base/nsLoadGroup.h +++ b/netwerk/base/nsLoadGroup.h @@ -29,7 +29,7 @@ class nsLoadGroup : public nsILoadGroup, { public: NS_DECL_AGGREGATED - + //////////////////////////////////////////////////////////////////////////// // nsIRequest methods: NS_DECL_NSIREQUEST @@ -79,7 +79,7 @@ protected: nsWeakPtr mObserver; nsWeakPtr mParentLoadGroup; - + nsresult mStatus; int32_t mPriority; bool mIsCanceling; @@ -92,6 +92,8 @@ protected: /* For nsPILoadGroupInternal */ uint32_t mTimedNonCachedRequestsUntilOnEndPageLoad; + + nsCString mUserAgentOverrideCache; }; #endif // nsLoadGroup_h__ diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index cae772d8a72..47c5c1a5e28 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -2476,6 +2476,41 @@ HttpBaseChannel::ShouldIntercept(nsIURI* aURI) return shouldIntercept; } +void +HttpBaseChannel::SetLoadGroupUserAgentOverride() +{ + nsCOMPtr uri; + GetURI(getter_AddRefs(uri)); + nsAutoCString uriScheme; + if (uri) { + uri->GetScheme(uriScheme); + } + nsCOMPtr childLoadGroup = do_QueryInterface(mLoadGroup); + nsCOMPtr rootLoadGroup; + if (childLoadGroup) { + childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup)); + } + if (rootLoadGroup && !uriScheme.EqualsLiteral("file")) { + nsAutoCString ua; + if (nsContentUtils::IsNonSubresourceRequest(this)) { + gHttpHandler->OnUserAgentRequest(this); + GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), ua); + rootLoadGroup->SetUserAgentOverrideCache(ua); + } else { + GetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), ua); + // Don't overwrite the UA if it is already set (eg by an XHR with explicit UA). + if (ua.IsEmpty()) { + rootLoadGroup->GetUserAgentOverrideCache(ua); + SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), ua, false); + } + } + } else { + // If the root loadgroup doesn't exist or if the channel's URI's scheme is "file", + // fall back on getting the UA override per channel. + gHttpHandler->OnUserAgentRequest(this); + } +} + //----------------------------------------------------------------------------- // nsHttpChannel::nsITraceableChannel //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 860416d5686..85de8d78977 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -353,6 +353,8 @@ protected: // for a possible synthesized response instead. bool ShouldIntercept(nsIURI* aURI = nullptr); + void SetLoadGroupUserAgentOverride(); + friend class PrivateBrowsingChannel; friend class InterceptFailedOnStop; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 1587164bd21..c8b368fabdc 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1805,9 +1805,12 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) return NS_OK; } - // Set user agent override + // Set user agent override from docshell HttpBaseChannel::SetDocshellUserAgentOverride(); + // Set user agent override from loadgroup + HttpBaseChannel::SetLoadGroupUserAgentOverride(); + MOZ_ASSERT_IF(mPostRedirectChannelShouldUpgrade, mPostRedirectChannelShouldIntercept); bool shouldUpgrade = mPostRedirectChannelShouldUpgrade; diff --git a/netwerk/protocol/http/UserAgentOverrides.jsm b/netwerk/protocol/http/UserAgentOverrides.jsm index 037aa575b2a..22c676f068b 100644 --- a/netwerk/protocol/http/UserAgentOverrides.jsm +++ b/netwerk/protocol/http/UserAgentOverrides.jsm @@ -46,9 +46,9 @@ this.UserAgentOverrides = { Services.prefs.addObserver(PREF_OVERRIDES_ENABLED, buildOverrides, false); try { - Services.obs.addObserver(HTTP_on_modify_request, "http-on-modify-request", false); + Services.obs.addObserver(HTTP_on_useragent_request, "http-on-useragent-request", false); } catch (x) { - // The http-on-modify-request notification is disallowed in content processes. + // The http-on-useragent-request notification is disallowed in content processes. } UserAgentUpdates.init(function(overrides) { @@ -118,7 +118,7 @@ this.UserAgentOverrides = { Services.prefs.removeObserver(PREF_OVERRIDES_ENABLED, buildOverrides); - Services.obs.removeObserver(HTTP_on_modify_request, "http-on-modify-request"); + Services.obs.removeObserver(HTTP_on_useragent_request, "http-on-useragent-request"); }, receiveMessage: function(aMessage) { @@ -169,7 +169,7 @@ function buildOverrides() { } } -function HTTP_on_modify_request(aSubject, aTopic, aData) { +function HTTP_on_useragent_request(aSubject, aTopic, aData) { let channel = aSubject.QueryInterface(Ci.nsIHttpChannel); for (let callback of gOverrideFunctions) { diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index dd487b8e397..c57bad8793c 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -5228,6 +5228,11 @@ nsHttpChannel::BeginConnect() // notify "http-on-modify-request" observers CallOnModifyRequestObservers(); + // If mLoadGroup is null, e10s is enabled and this will be handled by HttpChannelChild. + if (mLoadGroup) { + HttpBaseChannel::SetLoadGroupUserAgentOverride(); + } + // Check to see if we should redirect this channel elsewhere by // nsIHttpChannel.redirectTo API request if (mAPIRedirectToURI) { diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index 654b0b8bc3a..c6f1cc6dd48 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -275,6 +275,12 @@ public: NotifyObservers(chan, NS_HTTP_ON_MODIFY_REQUEST_TOPIC); } + // Called by the channel and cached in the loadGroup + void OnUserAgentRequest(nsIHttpChannel *chan) + { + NotifyObservers(chan, NS_HTTP_ON_USERAGENT_REQUEST_TOPIC); + } + // Called by the channel once headers are available void OnExamineResponse(nsIHttpChannel *chan) { diff --git a/netwerk/protocol/http/nsIHttpProtocolHandler.idl b/netwerk/protocol/http/nsIHttpProtocolHandler.idl index 82ac83fe478..f333a557ced 100644 --- a/netwerk/protocol/http/nsIHttpProtocolHandler.idl +++ b/netwerk/protocol/http/nsIHttpProtocolHandler.idl @@ -113,5 +113,14 @@ interface nsIHttpProtocolHandler : nsIProxiedProtocolHandler */ #define NS_HTTP_ON_EXAMINE_CACHED_RESPONSE_TOPIC "http-on-examine-cached-response" +/** + * Before an HTTP request corresponding to a channel with the LOAD_DOCUMENT_URI + * flag is sent to the server, this observer topic is notified. The observer of + * this topic can then choose to modify the user agent for this request before + * the request is actually sent to the server. Additionally, the modified user + * agent will be propagated to sub-resource requests from the same load group. + */ +#define NS_HTTP_ON_USERAGENT_REQUEST_TOPIC "http-on-useragent-request" + %} From 03b59166e2cffa3c6ab2f1a1d2ee1e161b2b0167 Mon Sep 17 00:00:00 2001 From: Dylan Roeh Date: Fri, 19 Feb 2016 17:06:46 -0600 Subject: [PATCH 077/252] Bug 1148544 - Update tests to work with new way of handling user agent overrides. r=jchen --- .../mochitests/test_user_agent_overrides.html | 181 ++++++++---------- .../mochitests/test_user_agent_updates.html | 74 ++++--- netwerk/test/mochitests/user_agent.sjs | 15 +- netwerk/test/mochitests/user_agent_update.sjs | 1 - 4 files changed, 140 insertions(+), 131 deletions(-) diff --git a/netwerk/test/mochitests/test_user_agent_overrides.html b/netwerk/test/mochitests/test_user_agent_overrides.html index 64862a7da1f..fb80482f7e1 100644 --- a/netwerk/test/mochitests/test_user_agent_overrides.html +++ b/netwerk/test/mochitests/test_user_agent_overrides.html @@ -5,8 +5,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782453 --> Test for User Agent Overrides - - + + Mozilla Bug 782453 @@ -29,95 +29,80 @@ const UA_PARTIAL_TO = UA_WHOLE_OVERRIDE; const UA_PARTIAL_OVERRIDE = UA_PARTIAL_FROM + UA_PARTIAL_SEP + UA_PARTIAL_TO; const UA_PARTIAL_EXPECTED = DEFAULT_UA.replace(new RegExp(UA_PARTIAL_FROM, 'g'), UA_PARTIAL_TO); -function getUA(host) { - var url = location.pathname; +function testUAIFrame(host, expected, sameQ, message, testNavQ, navSameQ, navMessage, callback) { + let url = location.pathname; url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs'; + let ifr = document.createElement('IFRAME'); - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); // sync request - xhr.send(); - is(xhr.status, 200, 'request failed'); - is(typeof xhr.response, 'string', 'invalid response'); - return xhr.response; + ifr.src = url; + + document.getElementById('content').appendChild(ifr); + + window.addEventListener("message", function recv(e) { + ok(sameQ == (e.data.header.indexOf(expected) != -1), message); + if (testNavQ) { + ok(navSameQ == (e.data.nav.indexOf(expected) != -1), navMessage); + } + window.removeEventListener("message", recv, false); + callback(); + }, false); + +} + +function testUAIFrameNoNav(host, expected, sameQ, message, callback) { + testUAIFrame(host, expected, sameQ, message, false, true, '', callback); } function testUA(options, callback) { - var [domain, override, test_hosts, expected] = [options.domain, options.override, options.test_hosts, options.expected]; - info('Overriding ' + domain + ' with ' + override); + (function nextTest() { + let test_host = test_hosts.shift(); - function is_subdomain(host) { - var [test_domain] = host.slice(host.lastIndexOf('/') + 1).split(':', 1); - return test_domain === domain || test_domain.endsWith('.' + domain); - } + info("Overriding " + domain + " with " + override + " for " + test_host); - var localhost = location.origin; - var overrideNavigator = is_subdomain(localhost); - var navigator_ua, test_ua = []; + function is_subdomain(host) { + var [test_domain] = host.slice(host.lastIndexOf('/') + 1).split(':', 1); + return test_domain === domain || test_domain.endsWith('.' + domain); + } - // store UA before pref change, to be compared later - if (overrideNavigator) { - navigator_ua = navigator.userAgent; - } - test_hosts.forEach(function (test_host) { - test_ua.push(getUA(test_host)); - }); - // set the override pref to override the UA - SpecialPowers.pushPrefEnv({ - set: [[PREF_OVERRIDES_BRANCH + domain, override]], - }, function () { - var ifr = document.createElement('IFRAME'); - ifr.src = "about:blank"; + var localhost = location.origin; + var overrideNavigator = is_subdomain(localhost); + var navigator_ua, test_ua; - ifr.addEventListener('load', function() { - var nav = ifr.contentWindow.navigator; + if (overrideNavigator) { + navigator_ua = navigator.userAgent; + } - // check that the UA has changed after pref change - if (overrideNavigator) { - is(nav.userAgent, expected, - 'Navigator UA not overridden at step ' + (++step)); - } else { - is(nav.userAgent, DEFAULT_UA, - 'Navigator UA should not be overridden at step ' + (++step)); - } - - test_hosts.forEach(function (test_host) { - is(getUA(test_host), expected, - 'Header UA not overridden at step ' + (++step)); - }); - - // clear the override pref to undo overriding the UA - SpecialPowers.pushPrefEnv({ - clear: [[PREF_OVERRIDES_BRANCH + domain]], - }, function () { - var ifr = document.createElement('IFRAME'); - ifr.src = "about:blank"; - - ifr.addEventListener('load', function() { - var nav = ifr.contentWindow.navigator; - - // check that the UA has changed back - if (overrideNavigator) { - is(nav.userAgent, navigator_ua, - 'Navigator UA not restored at step ' + (++step)); - } - test_hosts.forEach(function (test_host, i) { - is(getUA(test_host), test_ua[i], - 'Header UA not restored at step ' + (++step)); - }); - callback(); - }); - - document.getElementById('content').appendChild(ifr); - }); - }, false); + let url = location.pathname; + url = test_host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs'; + let ifr = document.createElement('IFRAME'); + ifr.src = url; document.getElementById('content').appendChild(ifr); - }); -} + window.addEventListener("message", function recv(e) { + test_ua = e.data.header; + SpecialPowers.pushPrefEnv({ + set: [[PREF_OVERRIDES_BRANCH + domain, override]], + }, function () { + testUAIFrame(test_host, expected, true, 'Header UA not overridden at step ' + (++step), true, + true, 'Navigator UA not overridden at step ' + (++step), function () { + // clear the override pref to undo overriding the UA + SpecialPowers.pushPrefEnv({ + clear: [[PREF_OVERRIDES_BRANCH + domain]], + }, function () { + testUAIFrameNoNav(test_host, test_ua, true, 'Header UA not restored at step ' + (++step), function() { + test_hosts.length ? nextTest() : callback(); + }); + }); + }); + }); + window.removeEventListener("message", recv, false); + }, false); + })(); +} var step = 0; // for logging var tests = [ @@ -175,16 +160,15 @@ function testInactive(callback) { [PREF_OVERRIDES_BRANCH + location.hostname, UA_WHOLE_OVERRIDE] ] }, function () { - isnot(navigator.userAgent, UA_WHOLE_OVERRIDE, - 'Failed to disable navigator UA override'); - isnot(getUA(location.origin), UA_WHOLE_OVERRIDE, - 'Failed to disable header UA override'); - SpecialPowers.pushPrefEnv({ - clear: [ - [PREF_OVERRIDES_ENABLED], - [PREF_OVERRIDES_BRANCH + location.hostname] - ] - }, callback); + testUAIFrame(location.origin, UA_WHOLE_OVERRIDE, false, 'Failed to disabled header UA override at step ' + (++step), + true, false, 'Failed to disable navigator UA override at step + ' + (++step), function () { + SpecialPowers.pushPrefEnv({ + clear: [ + [PREF_OVERRIDES_ENABLED], + [PREF_OVERRIDES_BRANCH + location.hostname] + ] + }, callback); + }); }); } @@ -206,22 +190,22 @@ function testPriority(callback) { ] }, function () { // should use first override at this point - is(getUA(host), - UA_WHOLE_EXPECTED, 'UA not overridden'); - // add a second override that should be used - testUA({ - domain: level2, - override: UA_PARTIAL_OVERRIDE, - test_hosts: [host], - expected: UA_PARTIAL_EXPECTED - }, function () { - // add a third override that should not be used + testUAIFrameNoNav(host, UA_WHOLE_EXPECTED, true, 'UA not overridden at step ' + (++step), function() { + // add a second override that should be used testUA({ - domain: level0, + domain: level2, override: UA_PARTIAL_OVERRIDE, test_hosts: [host], - expected: UA_WHOLE_EXPECTED - }, tests.length ? nextTest : callback); + expected: UA_PARTIAL_EXPECTED + }, function () { + // add a third override that should not be used + testUA({ + domain: level0, + override: UA_PARTIAL_OVERRIDE, + test_hosts: [host], + expected: UA_WHOLE_EXPECTED + }, tests.length ? nextTest : callback); + }); }); }); })(); @@ -240,6 +224,7 @@ SpecialPowers.wrap(UserAgentOverrides).init(); SimpleTest.waitForExplicitFinish(); SimpleTest.requestCompleteLog(); +SimpleTest.requestLongerTimeout(5); info(SpecialPowers.Cc["@mozilla.org/dom/site-specific-user-agent;1"].number); diff --git a/netwerk/test/mochitests/test_user_agent_updates.html b/netwerk/test/mochitests/test_user_agent_updates.html index 243f4387cbe..652dfaaa4b3 100644 --- a/netwerk/test/mochitests/test_user_agent_updates.html +++ b/netwerk/test/mochitests/test_user_agent_updates.html @@ -48,6 +48,29 @@ function getUA(host) { return xhr.response; } +function testUAIFrame(host, expected, sameQ, message, testNavQ, navSameQ, navMessage, callback) { + let url = location.pathname; + url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs'; + let ifr = document.createElement('IFRAME'); + + ifr.src = url; + + document.getElementById('content').appendChild(ifr); + + window.addEventListener("message", function recv(e) { + ok(sameQ == (e.data.header.indexOf(expected) != -1), message); + if (testNavQ) { + ok(navSameQ == (e.data.nav.indexOf(expected) != -1), navMessage); + } + window.removeEventListener("message", recv, false); + callback(); + }, false); +} + +function testUAIFrameNoNav(host, expected, sameQ, message, callback) { + testUAIFrame(host, expected, sameQ, message, false, true, '', callback); +} + const OVERRIDES = [ { domain: 'example.org', @@ -120,33 +143,25 @@ function testDownload(callback) { [PREF_UPDATES_TIMEOUT, 10000], [PREF_UPDATES_INTERVAL, 1] // 1 second interval ] - }, function waitForUpdate() { setTimeout(function () { - var ifr = document.createElement('IFRAME'); - ifr.src = "about:blank"; - - ifr.addEventListener('load', function() { - var nav = ifr.contentWindow.navigator; - if (nav.userAgent !== UA_OVERRIDE) { - waitForUpdate(); - return; - } - - info('Overrode navigator UA'); - is(getUA(location.origin), UA_OVERRIDE, 'Header UA not overridden'); - + }, function waitForUpdate() { setTimeout( function() { + testUAIFrameNoNav(location.origin, UA_OVERRIDE, true, 'Header UA not overridden', function() { var updateTime = parseInt(getUA('http://example.org')); - ok(startTime <= updateTime, 'Update was before start time'); - ok(updateTime <= Date.now(), 'Update was after present time'); + todo(startTime <= updateTime, 'Update was before start time'); + todo(updateTime <= Date.now(), 'Update was after present time'); - OVERRIDES.forEach(function (val) { - val.expected && is(getUA(val.host), val.expected, - 'Incorrect URL parameter: ' + val.override); - }); - callback(); - }, false); - - document.getElementById('content').appendChild(ifr); - }, 100); }); + let overs = OVERRIDES; + (function nextOverride() { + val = overs.shift(); + if (val.expected) { + testUAIFrameNoNav(val.host, val.expected, true, 'Incorrect URL parameter: ' + val.override, function() { + overs.length ? nextOverride() : callback(); + }); + } else { + nextOverride(); + } + })(); + }); + }, 1000); }); } function testBadUpdate(callback) { @@ -204,10 +219,11 @@ function testProfileLoad(callback) { setTimeout(waitForLoad, 100); return; } - is(getUA(location.origin), UA_ALT_OVERRIDE, 'Did not apply saved override'); - saveFilePreviousSize = file.fileSize; - callback(); - }, false); + testUAIFrameNoNav(location.origin, UA_ALT_OVERRIDE, true, 'Did not apply saved override', function () { + saveFilePreviousSize = file.fileSize; + callback(); + }); + }, true); document.getElementById('content').appendChild(ifr); })(); diff --git a/netwerk/test/mochitests/user_agent.sjs b/netwerk/test/mochitests/user_agent.sjs index 1fce5f6d052..dea299a2040 100644 --- a/netwerk/test/mochitests/user_agent.sjs +++ b/netwerk/test/mochitests/user_agent.sjs @@ -3,10 +3,19 @@ function handleRequest(request, response) { // avoid confusing cache behaviors response.setHeader("Cache-Control", "no-cache", false); - response.setHeader("Content-Type", "text/plain", false); + response.setHeader("Content-Type", "text/html", false); response.setHeader("Access-Control-Allow-Origin", "*", false); // used by test_user_agent tests - response.write(request.getHeader('User-Agent')); + response.write( + "\ + \ + " + ); } - diff --git a/netwerk/test/mochitests/user_agent_update.sjs b/netwerk/test/mochitests/user_agent_update.sjs index 9a0bd700aa3..649ceb9036f 100644 --- a/netwerk/test/mochitests/user_agent_update.sjs +++ b/netwerk/test/mochitests/user_agent_update.sjs @@ -8,4 +8,3 @@ function handleRequest(request, response) // used by test_user_agent_updates test response.write(decodeURIComponent(request.queryString)); } - From 3990969b81b2ecf5cb30f3f0ac8bd2b0c6f853e2 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Mon, 22 Feb 2016 14:00:55 -0800 Subject: [PATCH 078/252] Bug 1193093 - Tighten up these checks a little. r=Gijs --- browser/components/feeds/WebContentConverter.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/browser/components/feeds/WebContentConverter.js b/browser/components/feeds/WebContentConverter.js index f8c7c36ba1c..5132683dcf4 100644 --- a/browser/components/feeds/WebContentConverter.js +++ b/browser/components/feeds/WebContentConverter.js @@ -157,10 +157,11 @@ const Utils = { // We also reject handlers registered from a different host (see bug 402287) // The pref allows us to test the feature let pb = Services.prefs; - if ((!pb.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST) || - !pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST)) && - aContentWindow.location.hostname != uri.host) + if (!pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST) && + (!["http", "https"].includes(aContentWindow.location.protocol) || + aContentWindow.location.hostname != uri.host)) { throw("Permission denied to add " + uri.spec + " as a content or protocol handler"); + } // If the uri doesn't contain '%s', it won't be a good handler if (uri.spec.indexOf("%s") < 0) From d9218d5911a3babcbb130c2996e836ea5e4c4074 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 22 Feb 2016 17:13:38 -0500 Subject: [PATCH 079/252] Bug 1249351 part 1. When doing importScripts of multiple scripts in a service worker, make sure to track the cache streams per-loadinfo, instead of trying to make them all wait on the same stream. r=bkelly --- dom/workers/ScriptLoader.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index a837cf982ca..3fa4b8c2ae5 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -240,6 +240,10 @@ struct ScriptLoadInfo // resolution. RefPtr mCachePromise; + // The reader stream the cache entry should be filled from, for those cases + // when we're going to have an mCachePromise. + nsCOMPtr mCacheReadStream; + nsCOMPtr mChannel; char16_t* mScriptTextBuf; size_t mScriptTextLength; @@ -534,7 +538,6 @@ class ScriptLoaderRunnable final : public WorkerFeature nsCOMPtr mSyncLoopTarget; nsTArray mLoadInfos; RefPtr mCacheCreator; - nsCOMPtr mReader; bool mIsMainScript; WorkerScriptType mWorkerScriptType; bool mCanceled; @@ -641,7 +644,10 @@ private: // We synthesize the result code, but its never exposed to content. RefPtr ir = new mozilla::dom::InternalResponse(200, NS_LITERAL_CSTRING("OK")); - ir->SetBody(mReader); + ir->SetBody(loadInfo.mCacheReadStream); + // Drop our reference to the stream now that we've passed it along, so it + // doesn't hang around once the cache is done with it and keep data alive. + loadInfo.mCacheReadStream = nullptr; // Set the channel info of the channel on the response so that it's // saved in the cache. @@ -917,7 +923,8 @@ private: // In case we return early. loadInfo.mCacheStatus = ScriptLoadInfo::Cancel; - rv = NS_NewPipe(getter_AddRefs(mReader), getter_AddRefs(writer), 0, + rv = NS_NewPipe(getter_AddRefs(loadInfo.mCacheReadStream), + getter_AddRefs(writer), 0, UINT32_MAX, // unlimited size to avoid writer WOULD_BLOCK case true, false); // non-blocking reader, blocking writer if (NS_WARN_IF(NS_FAILED(rv))) { From b628e01d5c92643233925104fdfc22b362f79a30 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 22 Feb 2016 17:13:42 -0500 Subject: [PATCH 080/252] Bug 1249351 part 2. Clean up test_importscript.html and add multiple-url importScript() case. r=bz --- .../test/serviceworkers/importscript_worker.js | 16 ++++++++++++---- dom/workers/test/serviceworkers/lorem_script.js | 8 ++++++++ dom/workers/test/serviceworkers/mochitest.ini | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 dom/workers/test/serviceworkers/lorem_script.js diff --git a/dom/workers/test/serviceworkers/importscript_worker.js b/dom/workers/test/serviceworkers/importscript_worker.js index ac75a2937ff..3cddec1947d 100644 --- a/dom/workers/test/serviceworkers/importscript_worker.js +++ b/dom/workers/test/serviceworkers/importscript_worker.js @@ -3,13 +3,17 @@ function callByScript() { ++counter; } -importScripts(['importscript.sjs']); -importScripts(['importscript.sjs']); +// Use multiple scripts in this load to verify we support that case correctly. +// See bug 1249351 for a case where we broke this. +importScripts('lorem_script.js', 'importscript.sjs'); +importScripts('importscript.sjs'); + +var missingScriptFailed = false; try { importScripts(['there-is-nothing-here.js']); -} catch (ex) { - // Importing a non-existent script should not abort the SW load, bug 1198982. +} catch(e) { + missingScriptFailed = true; } onmessage = function(e) { @@ -18,6 +22,10 @@ onmessage = function(e) { dump("ERROR: no clients are currently controlled.\n"); } + if (!missingScriptFailed) { + res[0].postMessage("KO"); + } + try { importScripts(['importscript.sjs']); res[0].postMessage("KO"); diff --git a/dom/workers/test/serviceworkers/lorem_script.js b/dom/workers/test/serviceworkers/lorem_script.js new file mode 100644 index 00000000000..5502a44daab --- /dev/null +++ b/dom/workers/test/serviceworkers/lorem_script.js @@ -0,0 +1,8 @@ +var lorem_str = ` +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, +sunt in culpa qui officia deserunt mollit anim id est laborum. +` diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index c5fb718db59..6a12e24ef18 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -197,6 +197,7 @@ support-files = openWindow_worker.js redirect.sjs open_window/client.html + lorem_script.js [test_bug1151916.html] skip-if = e10s && debug && os == 'win' From 1ef6cc1d975979c1b2bbac67a5496812d24c6b5a Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 22 Feb 2016 14:14:20 -0500 Subject: [PATCH 081/252] Bug 1243267 - Guard against reentrancy into the dispatch of a scroll event. r=mats MozReview-Commit-ID: 5saxPwxOuc8 --- layout/generic/nsGfxScrollFrame.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 820d5275b3c..e3331174e37 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -4385,13 +4385,17 @@ ScrollFrameHelper::ScrollEvent::ScrollEvent(ScrollFrameHelper* aHelper) ScrollFrameHelper::ScrollEvent::~ScrollEvent() { - mDriver->RemoveRefreshObserver(this, Flush_Style); - mDriver = nullptr; + if (mDriver) { + mDriver->RemoveRefreshObserver(this, Flush_Style); + mDriver = nullptr; + } } void ScrollFrameHelper::ScrollEvent::WillRefresh(mozilla::TimeStamp aTime) { + mDriver->RemoveRefreshObserver(this, Flush_Style); + mDriver = nullptr; mHelper->FireScrollEvent(); } From 22aee51b88298b9dbfae83cd93fa8d0331170d5c Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 10 Feb 2016 13:51:25 -0800 Subject: [PATCH 082/252] Bug 1247126: Remove Debugger's tenure promotion log. r=fitzgen --- js/src/doc/Debugger/Debugger.Memory.md | 59 -------- js/src/gc/Marking.cpp | 4 - js/src/gc/Nursery.cpp | 9 +- js/src/gc/Zone.cpp | 23 --- js/src/gc/Zone.h | 12 -- .../debug/Memory-tenurePromotionsLog-01.js | 43 ------ .../debug/Memory-tenurePromotionsLog-02.js | 72 --------- .../debug/Memory-tenurePromotionsLog-03.js | 81 ---------- .../debug/Memory-tenurePromotionsLog-04.js | 12 -- .../debug/Memory-tenurePromotionsLog-05.js | 30 ---- .../debug/Memory-tenurePromotionsLog-06.js | 73 --------- .../debug/Memory-tenurePromotionsLog-07.js | 48 ------ js/src/vm/Debugger.cpp | 36 ----- js/src/vm/Debugger.h | 26 ---- js/src/vm/DebuggerMemory.cpp | 141 ------------------ js/src/vm/DebuggerMemory.h | 7 - 16 files changed, 1 insertion(+), 675 deletions(-) delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-01.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-02.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-03.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-04.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-05.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-06.js delete mode 100644 js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-07.js diff --git a/js/src/doc/Debugger/Debugger.Memory.md b/js/src/doc/Debugger/Debugger.Memory.md index 676dbcd9aed..1cc47a18791 100644 --- a/js/src/doc/Debugger/Debugger.Memory.md +++ b/js/src/doc/Debugger/Debugger.Memory.md @@ -109,25 +109,6 @@ following accessor properties from its prototype: [`drainAllocationsLog`][#drain-alloc-log] was called and some data has been lost. Returns `false` otherwise. -`trackingTenurePromotions` -: A boolean value indicating whether this `Debugger.Memory` instance is - observing promotions from the nursery to the tenured heap. It is an accessor - property that has both a getter and setter: assigning to it enables or - disables the tenure promotion tracking. Reading the accessor produces `true` - if the Debugger is logging promotions, and `false` otherwise. Tenure - promotion tracking is initially disabled in a new Debugger. - -maxTenurePromotionsLogLength -: The maximum number of entries to accumulate in the tenure promotions log at - a time. This accessor can be both fetched and stored to. Its default value - is `5000`. - -`tenurePromotionsLogOverflowed` -: Returns `true` if there have been more than - [`maxTenurePromotionsLogLength`][#max-tenure-log] allocations since the last time - [`drainTenurePromotionsLog`][#drain-tenure-log] was called and some data has been - lost. Returns `false` otherwise. - Debugger.Memory Handler Functions --------------------------------- @@ -276,46 +257,6 @@ Function Properties of the `Debugger.Memory.prototype` Object When `trackingAllocationSites` is `false`, `drainAllocationsLog()` throws an `Error`. -drainTenurePromotionsLog -: When `trackingTenurePromotions` is `true`, this method returns an array of - recent promotions from the nursery to the tenured heap within this - Debugger's set of debuggees. *Recent* is defined as the - `maxTenurePromotionsLogLength` most recent promotions since the last call to - `drainTenurePromotionsLog`. Therefore, calling this method effectively - clears the log. - - Objects in the array are of the form: - -

-    {
-      "timestamp": timestamp,
-      "frame": allocationSite,
-      "class": className,
-      "size": byteSize,
-    }
-    
- - Where - - * *timestamp* is the [timestamp][timestamps] of the allocation event. - - * *allocationSite* is an allocation site (as a - [captured stack][saved-frame]) if the promoted object's allocation site - was captured. Note that this property can be `null` if the object was - allocated with no JavaScript frames on the stack, the object's allocation - site was not [sampled](#alloc-sampling-probability), or if allocation - sites are not being [tracked](#trackingallocationsites'). - - * *className* is the string name of the allocated object's internal - `[[Class]]` property, for example "Array", "Date", "RegExp", or (most - commonly) "Object". - - * *byteSize* is the size of the newly tenured object (within the tenured - heap, not the nursery) in bytes. - - When `trackingTenurePromotions` is `false`, `drainTenurePromotionsLog()` - throws an `Error`. - takeCensus(options) : Carry out a census of the debuggee compartments' contents. A *census* is a complete traversal of the graph of all reachable memory items belonging to a diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 2700e1f01c0..76d491085bb 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2131,10 +2131,6 @@ js::TenuringTracer::moveToTenured(JSObject* src) overlay->forwardTo(dst); insertIntoFixupList(overlay); - if (MOZ_UNLIKELY(zone->hasDebuggers())) { - zone->enqueueForPromotionToTenuredLogging(*dst); - } - TracePromoteToTenured(src, dst); MemProfiler::MoveNurseryToTenured(src, dst); return dst; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 5e981c9712e..9e98f99bccb 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -525,12 +525,6 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList } TIME_END(pretenure); - TIME_START(logPromotionsToTenured); - for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { - zone->logPromotionsToTenured(); - } - TIME_END(logPromotionsToTenured); - // We ignore gcMaxBytes when allocating for minor collection. However, if we // overflowed, we disable the nursery. The next time we allocate, we'll fail // because gcBytes >= gcMaxBytes. @@ -569,8 +563,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList {" clrSB", TIME_TOTAL(clearStoreBuffer)}, {" sweep", TIME_TOTAL(sweep)}, {"resize", TIME_TOTAL(resize)}, - {"pretnr", TIME_TOTAL(pretenure)}, - {"logPtT", TIME_TOTAL(logPromotionsToTenured)} + {"pretnr", TIME_TOTAL(pretenure)} }; static int printedHeader = 0; if ((printedHeader++ % 200) == 0) { diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 260f06dbe47..7d1a9de66a7 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -133,29 +133,6 @@ Zone::getOrCreateDebuggers(JSContext* cx) return debuggers; } -void -Zone::logPromotionsToTenured() -{ - auto* dbgs = getDebuggers(); - if (MOZ_LIKELY(!dbgs)) - return; - - auto now = JS_GetCurrentEmbedderTime(); - JSRuntime* rt = runtimeFromAnyThread(); - - for (auto** dbgp = dbgs->begin(); dbgp != dbgs->end(); dbgp++) { - if (!(*dbgp)->isEnabled() || !(*dbgp)->isTrackingTenurePromotions()) - continue; - - for (auto range = awaitingTenureLogging.all(); !range.empty(); range.popFront()) { - if ((*dbgp)->isDebuggeeUnbarriered(range.front()->compartment())) - (*dbgp)->logTenurePromotion(rt, *range.front(), now); - } - } - - awaitingTenureLogging.clear(); -} - void Zone::sweepBreakpoints(FreeOp* fop) { diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index efeda7604a1..ed160573674 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -260,9 +260,6 @@ struct Zone : public JS::shadow::Zone, private: DebuggerVector* debuggers; - using LogTenurePromotionQueue = js::Vector; - LogTenurePromotionQueue awaitingTenureLogging; - void sweepBreakpoints(js::FreeOp* fop); void sweepUniqueIds(js::FreeOp* fop); void sweepWeakMaps(); @@ -282,15 +279,6 @@ struct Zone : public JS::shadow::Zone, DebuggerVector* getDebuggers() const { return debuggers; } DebuggerVector* getOrCreateDebuggers(JSContext* cx); - void enqueueForPromotionToTenuredLogging(JSObject& obj) { - MOZ_ASSERT(hasDebuggers()); - MOZ_ASSERT(!IsInsideNursery(&obj)); - js::AutoEnterOOMUnsafeRegion oomUnsafe; - if (!awaitingTenureLogging.append(&obj)) - oomUnsafe.crash("Zone::enqueueForPromotionToTenuredLogging"); - } - void logPromotionsToTenured(); - js::gc::ArenaLists arenas; js::TypeZone types; diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-01.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-01.js deleted file mode 100644 index aa9011d9849..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-01.js +++ /dev/null @@ -1,43 +0,0 @@ -// Test basic usage of drainTenurePromotionsLog() with various objects. - -const root = newGlobal(); -const dbg = new Debugger(); -const wrappedRoot = dbg.addDebuggee(root) - -dbg.memory.trackingAllocationSites = true; -dbg.memory.trackingTenurePromotions = true; - -root.eval(` - (function immediate() { - this.tests = [ - { name: "({})", cls: "Object", obj: ({}) }, - { name: "[]", cls: "Array", obj: [] }, - { name: "new Object", cls: "Object", obj: new Object() }, - { name: "new Array", cls: "Array", obj: new Array() }, - { name: "new Date", cls: "Date", obj: new Date() }, - ]; - }()); - minorgc(); -`); - -const promotions = dbg.memory.drainTenurePromotionsLog(); - -// Assert that the promotions happen in chronological order. -let lastWhen = -Infinity; -for (let p of promotions) { - assertEq(p.timestamp >= lastWhen, true); - lastWhen = p.timestamp; -} - -for (let { name, cls, obj } of root.tests) { - print(name + ": " + cls); - - // The promoted object's allocation site should be in the log. - let wrappedObj = wrappedRoot.makeDebuggeeValue(obj); - let allocSite = wrappedObj.allocationSite; - let idx = promotions.map(x => x.frame).indexOf(allocSite); - assertEq(idx >= 0, true); - - // The promoted object's class name should be present. - assertEq(promotions.map(x => x.class).indexOf(cls) >= 0, true); -} diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-02.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-02.js deleted file mode 100644 index 79f15c57ffc..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-02.js +++ /dev/null @@ -1,72 +0,0 @@ -// Test usage of drainTenurePromotionsLog() with multiple debuggees. - -const root1 = newGlobal(); -const root2 = newGlobal(); -const dbg = new Debugger(); - -function tenureObjectsAndDrainLog(root) { - gc(); - - dbg.memory.trackingAllocationSites = true; - dbg.memory.trackingTenurePromotions = true; - - root.eval( - ` - (function immediate() { - this.tests = [ - { name: "({})", cls: "Object", obj: ({}) }, - { name: "[]", cls: "Array", obj: [] }, - { name: "new Object", cls: "Object", obj: new Object() }, - { name: "new Array", cls: "Array", obj: new Array() }, - { name: "new Date", cls: "Date", obj: new Date() }, - ]; - }()); - minorgc(); - ` - ); - - const promotions = dbg.memory.drainTenurePromotionsLog(); - - dbg.memory.trackingAllocationSites = false; - dbg.memory.trackingTenurePromotions = false; - - return promotions; -} - -{ - dbg.addDebuggee(root1); - dbg.addDebuggee(root2); - - // Should get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, true); - // and logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, true); -} - -{ - dbg.removeAllDebuggees(); - - // Should *not* get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, false); - // nor logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, false); -} - -{ - dbg.addDebuggee(root1); - - // Should get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, true); - // but *not* logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, false); -} - -{ - dbg.removeAllDebuggees(); - dbg.addDebuggee(root2); - - // Should *not* get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, false); - // but should get logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, true); -} diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-03.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-03.js deleted file mode 100644 index 0449493d08f..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-03.js +++ /dev/null @@ -1,81 +0,0 @@ -// Test usage of drainTenurePromotionsLog() with multiple debuggers. - -const root = newGlobal(); -const dbg1 = new Debugger(root); -const dbg2 = new Debugger(root); - -function setTracking(dbg, bool) { - dbg.memory.trackingAllocationSites = bool; - dbg.memory.trackingTenurePromotions = bool; -} - -function tenureObjectsAndDrainLog() { - gc(); - - root.eval( - ` - (function immediate() { - this.tests = [ - { name: "({})", cls: "Object", obj: ({}) }, - { name: "[]", cls: "Array", obj: [] }, - { name: "new Object", cls: "Object", obj: new Object() }, - { name: "new Array", cls: "Array", obj: new Array() }, - { name: "new Date", cls: "Date", obj: new Date() }, - ]; - }()); - minorgc(); - ` - ); - - const promotions2 = dbg2.memory.trackingTenurePromotions ? dbg2.memory.drainTenurePromotionsLog() : []; - const promotions1 = dbg1.memory.trackingTenurePromotions ? dbg1.memory.drainTenurePromotionsLog() : []; - - setTracking(dbg1, false); - setTracking(dbg2, false); - - return { promotions1, promotions2 }; -} - -{ - setTracking(dbg1, true); - setTracking(dbg2, true); - const { promotions1, promotions2 } = tenureObjectsAndDrainLog(); - - // Should get logs in dbg1, - assertEq(!!promotions1.length, true); - // and logs in dbg2. - assertEq(!!promotions2.length, true); -} - -{ - setTracking(dbg1, false); - setTracking(dbg2, false); - const { promotions1, promotions2 } = tenureObjectsAndDrainLog(); - - // Should *not* get logs in dbg1, - assertEq(!!promotions1.length, false); - // nor logs in dbg2. - assertEq(!!promotions2.length, false); -} - -{ - setTracking(dbg1, true); - setTracking(dbg2, false); - const { promotions1, promotions2 } = tenureObjectsAndDrainLog(); - - // Should get logs in dbg1, - assertEq(!!promotions1.length, true); - // but *not* logs in dbg2. - assertEq(!!promotions2.length, false); -} - -{ - setTracking(dbg1, false); - setTracking(dbg2, true); - const { promotions1, promotions2 } = tenureObjectsAndDrainLog(); - - // Should *not* get logs in dbg1, - assertEq(!!promotions1.length, false); - // but *should* get logs in dbg2. - assertEq(!!promotions2.length, true); -} diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-04.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-04.js deleted file mode 100644 index ff8586aae4b..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-04.js +++ /dev/null @@ -1,12 +0,0 @@ -// Test draining tenure log without tracking tenures. - -const root = newGlobal(); -const dbg = new Debugger(root); - -let threw = false; -try { - dbg.drainTenurePromotionsLog(); -} catch (e) { - threw = true; -} -assertEq(threw, true); diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-05.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-05.js deleted file mode 100644 index fb9df3b7c93..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-05.js +++ /dev/null @@ -1,30 +0,0 @@ -// Test that objects that do not get tenured do not go in the log. - -// Can't let gc zeal mess with our assumptions about gc behavior here. -gczeal(0); - -const root = newGlobal(); -const dbg = root.dbg = new Debugger(root); - -root.eval( - ` - this.forceLazyInstantiation = new Date; - gc(); - - this.allocTemp = function allocTemp() { - gc(); - this.dbg.memory.trackingTenurePromotions = true; - // Create an object, remove references to it, and then do a minor gc. It - // should not be in the tenure promotions log because it should have died in - // the nursery. We use a Date object so it is easier to find when asserting. - var d = new Date; - d = null; - minorgc(); - }; - ` -); - -root.allocTemp(); - -const promotions = dbg.memory.drainTenurePromotionsLog(); -assertEq(promotions.some(e => e.class === "Date"), false); diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-06.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-06.js deleted file mode 100644 index 58884c0cb1d..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-06.js +++ /dev/null @@ -1,73 +0,0 @@ -// Test usage of drainTenurePromotionsLog() with multiple debuggees in the same -// zone. - -const root1 = newGlobal(); -const root2 = newGlobal({ sameZoneAs: root1 }); -const dbg = new Debugger(); - -function tenureObjectsAndDrainLog(root) { - gc(); - - dbg.memory.trackingAllocationSites = true; - dbg.memory.trackingTenurePromotions = true; - - root.eval( - ` - (function immediate() { - this.tests = [ - { name: "({})", cls: "Object", obj: ({}) }, - { name: "[]", cls: "Array", obj: [] }, - { name: "new Object", cls: "Object", obj: new Object() }, - { name: "new Array", cls: "Array", obj: new Array() }, - { name: "new Date", cls: "Date", obj: new Date() }, - ]; - }()); - minorgc(); - ` - ); - - const promotions = dbg.memory.drainTenurePromotionsLog(); - - dbg.memory.trackingAllocationSites = false; - dbg.memory.trackingTenurePromotions = false; - - return promotions; -} - -{ - dbg.addDebuggee(root1); - dbg.addDebuggee(root2); - - // Should get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, true); - // and logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, true); -} - -{ - dbg.removeAllDebuggees(); - - // Should *not* get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, false); - // nor logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, false); -} - -{ - dbg.addDebuggee(root1); - - // Should get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, true); - // but *not* logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, false); -} - -{ - dbg.removeAllDebuggees(); - dbg.addDebuggee(root2); - - // Should *not* get logs from root1, - assertEq(!!tenureObjectsAndDrainLog(root1).length, false); - // but should get logs from root2. - assertEq(!!tenureObjectsAndDrainLog(root2).length, true); -} diff --git a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-07.js b/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-07.js deleted file mode 100644 index e4ab5de459c..00000000000 --- a/js/src/jit-test/tests/debug/Memory-tenurePromotionsLog-07.js +++ /dev/null @@ -1,48 +0,0 @@ -// Test basic sizes of entries in the tenure promotions log. Does not attempt to -// test the actual object sizes in depth, as heap-analysis/byteSize-of-object.js -// does that pretty thoroughly, just that they are present where expected. - -const root = newGlobal(); -const dbg = root.dbg = new Debugger(); -const wrappedRoot = dbg.addDebuggee(root) - -root.eval(` - this.tests = []; - - function Ctor() { } - - function AsmModule(stdlib, foreign, heap) { - "use asm"; - - function test() { - return 5|0; - } - - return { test: test }; - } - const buf = new ArrayBuffer(1024*8); - - (function immediate() { - this.dbg.memory.trackingTenurePromotions = true; - - this.tests.push( new Object() ); - this.tests.push( new Array() ); - this.tests.push( new Uint8Array(256) ); - this.tests.push( (function () { return arguments; }()) ); - this.tests.push( AsmModule(this, {}, buf) ); - this.tests.push( /2manyproblemz/g ); - this.tests.push( [1,2,3][Symbol.iterator]() ); - this.tests.push( Error() ); - this.tests.push( new Ctor ); - this.tests.push( {} ); - this.tests.push( new Date ); - this.tests.push( [1,2,3] ); - - }).call(this); - - minorgc(); -`); - -const promotions = dbg.memory.drainTenurePromotionsLog(); -print(uneval(promotions)); -assertEq(promotions.every(p => p.size >= 1), true); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 8f031709a62..c3207f17498 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -513,10 +513,6 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg) allowUnobservedAsmJS(false), collectCoverageInfo(false), observedGCs(cx->runtime()), - tenurePromotionsLog(cx), - trackingTenurePromotions(false), - maxTenurePromotionsLogLength(DEFAULT_MAX_LOG_LENGTH), - tenurePromotionsLogOverflowed(false), allocationsLog(cx), trackingAllocationSites(false), allocationSamplingProbability(1.0), @@ -545,7 +541,6 @@ Debugger::~Debugger() { MOZ_ASSERT_IF(debuggees.initialized(), debuggees.empty()); allocationsLog.clear(); - tenurePromotionsLog.clear(); /* * Since the inactive state for this link is a singleton cycle, it's always @@ -1980,30 +1975,6 @@ Debugger::isDebuggeeUnbarriered(const JSCompartment* compartment) const return compartment->isDebuggee() && debuggees.has(compartment->unsafeUnbarrieredMaybeGlobal()); } -Debugger::TenurePromotionsLogEntry::TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when) - : className(obj.getClass()->name), - when(when), - frame(getObjectAllocationSite(obj)), - size(JS::ubi::Node(&obj).size(rt->debuggerMallocSizeOf)) -{ } - - -void -Debugger::logTenurePromotion(JSRuntime* rt, JSObject& obj, double when) -{ - AutoEnterOOMUnsafeRegion oomUnsafe; - - if (!tenurePromotionsLog.emplaceBack(rt, obj, when)) - oomUnsafe.crash("Debugger::logTenurePromotion"); - - if (tenurePromotionsLog.length() > maxTenurePromotionsLogLength) { - if (!tenurePromotionsLog.popFront()) - oomUnsafe.crash("Debugger::logTenurePromotion"); - MOZ_ASSERT(tenurePromotionsLog.length() == maxTenurePromotionsLogLength); - tenurePromotionsLogOverflowed = true; - } -} - bool Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame, double when) @@ -2680,12 +2651,6 @@ Debugger::markCrossCompartmentEdges(JSTracer* trc) environments.markCrossCompartmentEdges(trc); scripts.markCrossCompartmentEdges(trc); sources.markCrossCompartmentEdges(trc); - - // Because we don't have access to a `cx` inside - // `Debugger::logTenurePromotion`, we can't hold onto CCWs inside the log, - // and instead have unwrapped cross-compartment edges. We need to be sure to - // mark those here. - tenurePromotionsLog.trace(trc); } /* @@ -2862,7 +2827,6 @@ Debugger::trace(JSTracer* trc) } allocationsLog.trace(trc); - tenurePromotionsLog.trace(trc); /* Trace the weak map from JSScript instances to Debugger.Script objects. */ scripts.trace(trc); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 87c74626e01..d56d7b56791 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -273,32 +273,12 @@ class Debugger : private mozilla::LinkedListElement return observedGCs.put(majorGCNumber); } - bool isTrackingTenurePromotions() const { - return trackingTenurePromotions; - } - bool isEnabled() const { return enabled; } - void logTenurePromotion(JSRuntime* rt, JSObject& obj, double when); static SavedFrame* getObjectAllocationSite(JSObject& obj); - struct TenurePromotionsLogEntry - { - TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when); - - const char* className; - double when; - RelocatablePtrObject frame; - size_t size; - - void trace(JSTracer* trc) { - if (frame) - TraceEdge(trc, &frame, "Debugger::TenurePromotionsLogEntry::frame"); - } - }; - struct AllocationsLogEntry { AllocationsLogEntry(HandleObject frame, double when, const char* className, @@ -346,12 +326,6 @@ class Debugger : private mozilla::LinkedListElement using GCNumberSet = HashSet, RuntimeAllocPolicy>; GCNumberSet observedGCs; - using TenurePromotionsLog = js::TraceableFifo; - TenurePromotionsLog tenurePromotionsLog; - bool trackingTenurePromotions; - size_t maxTenurePromotionsLogLength; - bool tenurePromotionsLogOverflowed; - using AllocationsLog = js::TraceableFifo; AllocationsLog allocationsLog; diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 97d4498bbeb..fa2ef033de1 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -337,142 +337,6 @@ DebuggerMemory::getAllocationsLogOverflowed(JSContext* cx, unsigned argc, Value* return true; } -/* static */ bool -DebuggerMemory::setTrackingTenurePromotions(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set trackingTenurePromotions)", args, memory); - if (!args.requireAtLeast(cx, "(set trackingTenurePromotions)", 1)) - return false; - - Debugger* dbg = memory->getDebugger(); - dbg->trackingTenurePromotions = ToBoolean(args[0]); - return undefined(args); -} - -/* static */ bool -DebuggerMemory::getTrackingTenurePromotions(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get trackingTenurePromotions)", args, memory); - args.rval().setBoolean(memory->getDebugger()->trackingTenurePromotions); - return true; -} - -/* static */ bool -DebuggerMemory::drainTenurePromotionsLog(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "drainTenurePromotionsLog", args, memory); - Debugger* dbg = memory->getDebugger(); - - if (!dbg->trackingTenurePromotions) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_TRACKING_TENURINGS, - "drainTenurePromotionsLog"); - return false; - } - - size_t length = dbg->tenurePromotionsLog.length(); - - RootedArrayObject result(cx, NewDenseFullyAllocatedArray(cx, length)); - if (!result) - return false; - result->ensureDenseInitializedLength(cx, 0, length); - - for (size_t i = 0; i < length; i++) { - RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); - if (!obj) - return false; - - // Don't pop the TenurePromotionsEntry yet. The queue's links are - // followed by the GC to find the TenurePromotionsEntry, but are not - // barriered, so we must edit them with great care. Use the queue entry - // in place, and then pop and delete together. - auto& entry = dbg->tenurePromotionsLog.front(); - - RootedValue frame(cx, ObjectOrNullValue(entry.frame)); - if (!cx->compartment()->wrap(cx, &frame) || - !DefineProperty(cx, obj, cx->names().frame, frame)) - { - return false; - } - - RootedValue timestampValue(cx, NumberValue(entry.when)); - if (!DefineProperty(cx, obj, cx->names().timestamp, timestampValue)) - return false; - - RootedString className(cx, Atomize(cx, entry.className, strlen(entry.className))); - if (!className) - return false; - RootedValue classNameValue(cx, StringValue(className)); - if (!DefineProperty(cx, obj, cx->names().class_, classNameValue)) - return false; - - RootedValue sizeValue(cx, NumberValue(entry.size)); - if (!DefineProperty(cx, obj, cx->names().size, sizeValue)) - return false; - - result->setDenseElement(i, ObjectValue(*obj)); - - // Pop the front queue entry, and delete it immediately, so that the GC - // sees the TenurePromotionsEntry's RelocatablePtr barriers run - // atomically with the change to the graph (the queue link). - if (!dbg->tenurePromotionsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } - } - - dbg->tenurePromotionsLogOverflowed = false; - args.rval().setObject(*result); - return true; -} - -/* static */ bool -DebuggerMemory::getMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get maxTenurePromotionsLogLength)", args, memory); - args.rval().setInt32(memory->getDebugger()->maxTenurePromotionsLogLength); - return true; -} - -/* static */ bool -DebuggerMemory::setMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "(set maxTenurePromotionsLogLength)", args, memory); - if (!args.requireAtLeast(cx, "(set maxTenurePromotionsLogLength)", 1)) - return false; - - int32_t max; - if (!ToInt32(cx, args[0], &max)) - return false; - - if (max < 1) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, - "(set maxTenurePromotionsLogLength)'s parameter", - "not a positive integer"); - return false; - } - - Debugger* dbg = memory->getDebugger(); - dbg->maxTenurePromotionsLogLength = max; - - while (dbg->tenurePromotionsLog.length() > dbg->maxAllocationsLogLength) { - if (!dbg->tenurePromotionsLog.popFront()) { - ReportOutOfMemory(cx); - return false; - } - } - - args.rval().setUndefined(); - return true; -} - -/* static */ bool -DebuggerMemory::getTenurePromotionsLogOverflowed(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER_MEMORY(cx, argc, vp, "(get tenurePromotionsLogOverflowed)", args, memory); - args.rval().setBoolean(memory->getDebugger()->tenurePromotionsLogOverflowed); - return true; -} - /* static */ bool DebuggerMemory::getOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp) { @@ -584,17 +448,12 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp) JS_PSGS("allocationSamplingProbability", getAllocationSamplingProbability, setAllocationSamplingProbability, 0), JS_PSG("allocationsLogOverflowed", getAllocationsLogOverflowed, 0), - JS_PSGS("trackingTenurePromotions", getTrackingTenurePromotions, setTrackingTenurePromotions, 0), - JS_PSGS("maxTenurePromotionsLogLength", getMaxTenurePromotionsLogLength, setMaxTenurePromotionsLogLength, 0), - JS_PSG("tenurePromotionsLogOverflowed", getTenurePromotionsLogOverflowed, 0), - JS_PSGS("onGarbageCollection", getOnGarbageCollection, setOnGarbageCollection, 0), JS_PS_END }; /* static */ const JSFunctionSpec DebuggerMemory::methods[] = { JS_FN("drainAllocationsLog", DebuggerMemory::drainAllocationsLog, 0, 0), - JS_FN("drainTenurePromotionsLog", DebuggerMemory::drainTenurePromotionsLog, 0, 0), JS_FN("takeCensus", takeCensus, 0, 0), JS_FS_END }; diff --git a/js/src/vm/DebuggerMemory.h b/js/src/vm/DebuggerMemory.h index 8c214ad32fe..a5fadc35e53 100644 --- a/js/src/vm/DebuggerMemory.h +++ b/js/src/vm/DebuggerMemory.h @@ -45,12 +45,6 @@ class DebuggerMemory : public NativeObject { static bool getAllocationSamplingProbability(JSContext* cx, unsigned argc, Value* vp); static bool getAllocationsLogOverflowed(JSContext* cx, unsigned argc, Value* vp); - static bool setTrackingTenurePromotions(JSContext* cx, unsigned argc, Value* vp); - static bool getTrackingTenurePromotions(JSContext* cx, unsigned argc, Value* vp); - static bool setMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Value* vp); - static bool getMaxTenurePromotionsLogLength(JSContext* cx, unsigned argc, Value* vp); - static bool getTenurePromotionsLogOverflowed(JSContext* cx, unsigned argc, Value* vp); - static bool getOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp); static bool setOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp); @@ -58,7 +52,6 @@ class DebuggerMemory : public NativeObject { static bool takeCensus(JSContext* cx, unsigned argc, Value* vp); static bool drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp); - static bool drainTenurePromotionsLog(JSContext* cx, unsigned argc, Value* vp); }; } /* namespace js */ From e947e272c0192d60d55643ab0f9285e5da8d8b4f Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 22 Feb 2016 14:02:38 -0800 Subject: [PATCH 083/252] Bug 1221378: Properly root object passed to the allocation metadata callback. r=fitzgen --- js/src/builtin/TestingFunctions.cpp | 2 +- js/src/jscompartment.cpp | 6 +++--- js/src/jscompartment.h | 2 +- js/src/jsfriendapi.h | 2 +- js/src/jsobjinlines.h | 21 +++++++++++++++++---- js/src/vm/Runtime-inl.h | 2 +- js/src/vm/SavedStacks.cpp | 2 +- js/src/vm/SavedStacks.h | 4 ++-- 8 files changed, 27 insertions(+), 14 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 59e702d3ba7..e2153ce45bc 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1650,7 +1650,7 @@ DisplayName(JSContext* cx, unsigned argc, Value* vp) } static JSObject* -ShellObjectMetadataCallback(JSContext* cx, JSObject*) +ShellObjectMetadataCallback(JSContext* cx, HandleObject) { AutoEnterOOMUnsafeRegion oomUnsafe; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index ea17b9fe406..37c4969279f 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -886,7 +886,7 @@ JSCompartment::clearObjectMetadata() } void -JSCompartment::setNewObjectMetadata(JSContext* cx, JSObject* obj) +JSCompartment::setNewObjectMetadata(JSContext* cx, HandleObject obj) { assertSameCompartment(cx, this, obj); @@ -1193,13 +1193,13 @@ AutoSetNewObjectMetadata::~AutoSetNewObjectMetadata() return; if (!cx_->isExceptionPending() && cx_->compartment()->hasObjectPendingMetadata()) { - JSObject* obj = cx_->compartment()->objectMetadataState.as(); + RootedObject obj(cx_, cx_->compartment()->objectMetadataState.as()); // Make sure to restore the previous state before setting the object's // metadata. SetNewObjectMetadata asserts that the state is not // PendingMetadata in order to ensure that metadata callbacks are called // in order. cx_->compartment()->objectMetadataState = prevState_; - SetNewObjectMetadata(cx_, obj); + obj = SetNewObjectMetadata(cx_, obj); } else { cx_->compartment()->objectMetadataState = prevState_; } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index c0197f97e30..cbddea4a4ef 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -588,7 +588,7 @@ struct JSCompartment void forgetObjectMetadataCallback() { objectMetadataCallback = nullptr; } - void setNewObjectMetadata(JSContext* cx, JSObject* obj); + void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj); void clearObjectMetadata(); const void* addressOfMetadataCallback() const { return &objectMetadataCallback; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index c152c26c348..7f318f5a1d0 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2676,7 +2676,7 @@ class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { }; typedef JSObject* -(* ObjectMetadataCallback)(JSContext* cx, JSObject* obj); +(* ObjectMetadataCallback)(JSContext* cx, JS::HandleObject obj); /** * Specify a callback to invoke when creating each JS object in the current diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index c76aecd47e1..967e416bccc 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -275,7 +275,17 @@ ClassCanHaveFixedData(const Class* clasp) || js::IsTypedArrayClass(clasp); } -static MOZ_ALWAYS_INLINE void +// This function is meant to be called from allocation fast paths. +// +// If we do have an allocation metadata hook, it can cause a GC, so the object +// must be rooted. The usual way to do this would be to make our callers pass a +// HandleObject, but that would require them to pay the cost of rooting the +// object unconditionally, even though collecting metadata is rare. Instead, +// SetNewObjectMetadata's contract is that the caller must use the pointer +// returned in place of the pointer passed. If a GC occurs, the returned pointer +// may be the passed pointer, relocated by GC. If no GC could occur, it's just +// passed through. We root nothing unless necessary. +static MOZ_ALWAYS_INLINE MOZ_WARN_UNUSED_RESULT JSObject* SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj) { MOZ_ASSERT(!cxArg->compartment()->hasObjectPendingMetadata()); @@ -290,10 +300,13 @@ SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj) // callback, and any reentering of JS via Invoke() etc. AutoEnterAnalysis enter(cx); - RootedObject hobj(cx, obj); - cx->compartment()->setNewObjectMetadata(cx, hobj); + RootedObject rooted(cx, obj); + cx->compartment()->setNewObjectMetadata(cx, rooted); + return rooted; } } + + return obj; } } // namespace js @@ -357,7 +370,7 @@ JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::Initi if (group->clasp()->shouldDelayMetadataCallback()) cx->compartment()->setObjectPendingMetadata(cx, obj); else - SetNewObjectMetadata(cx, obj); + obj = SetNewObjectMetadata(cx, obj); js::gc::TraceCreateObject(obj); diff --git a/js/src/vm/Runtime-inl.h b/js/src/vm/Runtime-inl.h index d63c04f2b08..afc98fe4412 100644 --- a/js/src/vm/Runtime-inl.h +++ b/js/src/vm/Runtime-inl.h @@ -70,7 +70,7 @@ NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::Initi if (group->clasp()->shouldDelayMetadataCallback()) cx->compartment()->setObjectPendingMetadata(cx, obj); else - SetNewObjectMetadata(cx, obj); + obj = static_cast(SetNewObjectMetadata(cx, obj)); probes::CreateObject(cx, obj); gc::TraceCreateObject(obj); diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 5b2409859c1..d1c4f541139 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -1413,7 +1413,7 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment) } JSObject* -SavedStacksMetadataCallback(JSContext* cx, JSObject* target) +SavedStacksMetadataCallback(JSContext* cx, HandleObject target) { RootedObject obj(cx, target); diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 207b0498073..023c9ab1976 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -149,7 +149,7 @@ namespace js { class SavedStacks { friend class SavedFrame; - friend JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target); + friend JSObject* SavedStacksMetadataCallback(JSContext* cx, HandleObject target); friend bool JS::ubi::ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& ubiFrame, MutableHandleObject outSavedFrameStack); @@ -300,7 +300,7 @@ class SavedStacks { bool getLocation(JSContext* cx, const FrameIter& iter, MutableHandle locationp); }; -JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target); +JSObject* SavedStacksMetadataCallback(JSContext* cx, HandleObject target); template <> class RootedBase From 8ae2ac46df71abbba480adb2519b3afb03f735a6 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 2 Feb 2016 18:20:57 -0800 Subject: [PATCH 084/252] Bug 1221378: Add JSCLASS_DELAY_METADATA_CALLBACK flag to UnboxedPlainObject. r=jandem --- js/src/vm/UnboxedObject.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index fb35282f8a1..b1bd78c0ae5 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -634,6 +634,8 @@ UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj) UnboxedPlainObject* UnboxedPlainObject::create(ExclusiveContext* cx, HandleObjectGroup group, NewObjectKind newKind) { + AutoSetNewObjectMetadata metadata(cx); + MOZ_ASSERT(group->clasp() == &class_); gc::AllocKind allocKind = group->unboxedLayout().getAllocKind(); @@ -916,7 +918,8 @@ const Class UnboxedExpandoObject::class_ = { const Class UnboxedPlainObject::class_ = { js_Object_str, Class::NON_NATIVE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object), + JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | + JSCLASS_DELAY_METADATA_CALLBACK, nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ From 4ebdd1db72e8889edc543a4192179b66d6ac36ea Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 22 Feb 2016 14:02:49 -0800 Subject: [PATCH 085/252] Bug 1221378: Root Debuggers in js::Debugger::slowPathOnLogAllocationSite, in case logging causes a GC. r=fitzgen --- js/src/vm/Debugger.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index c3207f17498..67ec195aa78 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1933,6 +1933,19 @@ Debugger::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSav MOZ_ASSERT(!dbgs.empty()); mozilla::DebugOnly begin = dbgs.begin(); + // Root all the Debuggers while we're iterating over them; + // appendAllocationSite calls JSCompartment::wrap, and thus can GC. + // + // SpiderMonkey protocol is generally for the caller to prove that it has + // rooted the stuff it's asking you to operate on (i.e. by passing a + // Handle), but in this case, we're iterating over a global's list of + // Debuggers, and globals only hold their Debuggers weakly. + Rooted> activeDebuggers(cx, GCVector(cx)); + for (Debugger** dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) { + if (!activeDebuggers.append((*dbgp)->object)) + return false; + } + for (Debugger** dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) { // The set of debuggers had better not change while we're iterating, // such that the vector gets reallocated. From cf23a0371d53b329d31b13187493e298e676f845 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 22 Feb 2016 12:21:56 -0800 Subject: [PATCH 086/252] Bug 1221378: Use a dedicated flag on JS::Zone to disable allocation metadata collection, instead of abusing AutoEnterAnalysis. r=fitzgen --- .../automation/cgc-jittest-timeouts.txt | 3 ++- js/src/gc/Zone.cpp | 1 + js/src/gc/Zone.h | 11 ++++++++++ js/src/jscompartment.cpp | 15 ++++++++++++- js/src/jscompartment.h | 21 +++++++++++++++++++ js/src/jsfriendapi.cpp | 3 +-- js/src/jsobjinlines.h | 12 +++++++---- js/src/vm/TypeInference-inl.h | 7 +++++-- 8 files changed, 63 insertions(+), 10 deletions(-) diff --git a/js/src/devtools/automation/cgc-jittest-timeouts.txt b/js/src/devtools/automation/cgc-jittest-timeouts.txt index 28cc9b36fa7..6cd4819a437 100644 --- a/js/src/devtools/automation/cgc-jittest-timeouts.txt +++ b/js/src/devtools/automation/cgc-jittest-timeouts.txt @@ -1,3 +1,4 @@ +SIMD/nursery-overflow.js asm.js/testParallelCompile.js auto-regress/bug653395.js auto-regress/bug654392.js @@ -19,9 +20,9 @@ gc/bug-906241.js ion/bug787921.js parallel/alloc-many-objs.js parallel/alloc-too-many-objs.js +saved-stacks/bug-1006876-too-much-recursion.js self-test/assertDeepEq.js v8-v5/check-earley-boyer.js v8-v5/check-raytrace.js v8-v5/check-regexp.js v8-v5/check-splay.js -SIMD/nursery-overflow.js diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 7d1a9de66a7..73124d43e16 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -25,6 +25,7 @@ Zone * const Zone::NotOnList = reinterpret_cast(1); JS::Zone::Zone(JSRuntime* rt) : JS::shadow::Zone(rt, &rt->gc.marker), debuggers(nullptr), + suppressObjectMetadataCallback(false), arenas(rt), types(this), compartments(), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index ed160573674..c43dcf3df6c 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -279,6 +279,17 @@ struct Zone : public JS::shadow::Zone, DebuggerVector* getDebuggers() const { return debuggers; } DebuggerVector* getOrCreateDebuggers(JSContext* cx); + /* + * When true, skip calling the metadata callback. We use this: + * - to avoid invoking the callback recursively; + * - to avoid observing lazy prototype setup (which confuses callbacks that + * want to use the types being set up!); + * - to avoid attaching allocation stacks to allocation stack nodes, which + * is silly + * And so on. + */ + bool suppressObjectMetadataCallback; + js::gc::ArenaLists arenas; js::TypeZone types; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 37c4969279f..25057c102ce 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -1193,12 +1193,25 @@ AutoSetNewObjectMetadata::~AutoSetNewObjectMetadata() return; if (!cx_->isExceptionPending() && cx_->compartment()->hasObjectPendingMetadata()) { - RootedObject obj(cx_, cx_->compartment()->objectMetadataState.as()); + // This destructor often runs upon exit from a function that is + // returning an unrooted pointer to a Cell. The allocation metadata + // callback often allocates; if it causes a GC, then the Cell pointer + // being returned won't be traced or relocated. + // + // The only extant callbacks are those internal to SpiderMonkey that + // capture the JS stack. In fact, we're considering removing general + // callbacks altogther in bug 1236748. Since it's not running arbitrary + // code, it's adequate to simply suppress GC while we run the callback. + AutoSuppressGC autoSuppressGC(cx_); + + JSObject* obj = cx_->compartment()->objectMetadataState.as(); + // Make sure to restore the previous state before setting the object's // metadata. SetNewObjectMetadata asserts that the state is not // PendingMetadata in order to ensure that metadata callbacks are called // in order. cx_->compartment()->objectMetadataState = prevState_; + obj = SetNewObjectMetadata(cx_, obj); } else { cx_->compartment()->objectMetadataState = prevState_; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index cbddea4a4ef..9af4272d4e1 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -940,6 +940,27 @@ class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter { MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +class MOZ_RAII AutoSuppressObjectMetadataCallback { + JS::Zone* zone; + bool saved; + + public: + explicit AutoSuppressObjectMetadataCallback(ExclusiveContext* cx) + : AutoSuppressObjectMetadataCallback(cx->compartment()->zone()) + { } + + explicit AutoSuppressObjectMetadataCallback(JS::Zone* zone) + : zone(zone), + saved(zone->suppressObjectMetadataCallback) + { + zone->suppressObjectMetadataCallback = true; + } + + ~AutoSuppressObjectMetadataCallback() { + zone->suppressObjectMetadataCallback = saved; + } +}; + } /* namespace js */ #endif /* jscompartment_h */ diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 8b70a529c25..e70118bb910 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -138,8 +138,7 @@ JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, HandleObject pro JS_FRIEND_API(JSObject*) JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle proto) { - // Use an AutoEnterAnalysis to suppress invocation of the metadata callback. - AutoEnterAnalysis enter(cx); + AutoSuppressObjectMetadataCallback suppressMetadata(cx); return JS_NewObjectWithGivenProto(cx, clasp, proto); } diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 967e416bccc..ed7595c78a3 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -294,11 +294,10 @@ SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj) // thread, except when analysis/compilation is active, to avoid recursion. if (JSContext* cx = cxArg->maybeJSContext()) { if (MOZ_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) && - !cx->zone()->types.activeAnalysis) + !cx->zone()->suppressObjectMetadataCallback) { - // Use AutoEnterAnalysis to prohibit both any GC activity under the - // callback, and any reentering of JS via Invoke() etc. - AutoEnterAnalysis enter(cx); + // Don't collect metadata on objects that represent metadata. + AutoSuppressObjectMetadataCallback suppressMetadata(cx); RootedObject rooted(cx, obj); cx->compartment()->setNewObjectMetadata(cx, rooted); @@ -365,6 +364,11 @@ JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::Initi size_t size = kind == js::gc::AllocKind::FUNCTION ? sizeof(JSFunction) : sizeof(js::FunctionExtended); memset(obj->as().fixedSlots(), 0, size - sizeof(js::NativeObject)); + if (kind == js::gc::AllocKind::FUNCTION_EXTENDED) { + // SetNewObjectMetadata may gc, which will be unhappy if flags & + // EXTENDED doesn't match the arena's AllocKind. + obj->as().setFlags(JSFunction::EXTENDED); + } } if (group->clasp()->shouldDelayMetadataCallback()) diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index ef0b441369c..da00b634bd0 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -283,17 +283,20 @@ struct AutoEnterAnalysis // Pending recompilations to perform before execution of JIT code can resume. RecompileInfoVector pendingRecompiles; + // Prevent us from calling the objectMetadataCallback. + js::AutoSuppressObjectMetadataCallback suppressMetadata; + FreeOp* freeOp; Zone* zone; explicit AutoEnterAnalysis(ExclusiveContext* cx) - : suppressGC(cx), oom(cx->zone()) + : suppressGC(cx), oom(cx->zone()), suppressMetadata(cx) { init(cx->defaultFreeOp(), cx->zone()); } AutoEnterAnalysis(FreeOp* fop, Zone* zone) - : suppressGC(zone->runtimeFromMainThread()), oom(zone) + : suppressGC(zone->runtimeFromMainThread()), oom(zone), suppressMetadata(zone) { init(fop, zone); } From 68848b877fbc89fe2c725e7025f36f4dabe1c3b5 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 11 Jan 2016 23:31:40 -0800 Subject: [PATCH 087/252] Bug 1221378: SpiderMonkey: Assert against re-entrant constructor resolution. r=fitzgen --- js/src/vm/GlobalObject.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 554f15fe98e..5d64e7068c5 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -179,6 +179,13 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle global, JS if (!proto) return false; + // Make sure that creating the prototype didn't recursively resolve our + // own constructor. We can't just assert that there's no prototype; OOMs + // can result in incomplete resolutions in which the prototype is saved + // but not the constructor. So use the same criteria that protects entry + // into this function. + MOZ_ASSERT(!global->isStandardClassResolved(key)); + global->setPrototype(key, ObjectValue(*proto)); } From c1d2b77507f9a07e5b687e2b8a89526eabc48d5a Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 4 Jan 2016 20:47:03 -0800 Subject: [PATCH 088/252] Bug 1221378: Don't collect allocation metadata when lazily creating standard prototypes. r=fitzgen --- js/src/jit-test/tests/debug/bug1221378.js | 11 +++++++++++ js/src/vm/GlobalObject.cpp | 6 ++++++ 2 files changed, 17 insertions(+) create mode 100644 js/src/jit-test/tests/debug/bug1221378.js diff --git a/js/src/jit-test/tests/debug/bug1221378.js b/js/src/jit-test/tests/debug/bug1221378.js new file mode 100644 index 00000000000..8327fda4f8c --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1221378.js @@ -0,0 +1,11 @@ +// Bug 1221378: allocating an array from within the object metadata callback +// shouldn't cause re-entrant resolution of lazy prototypes. + +// To test for this regression, we need some way to make the code that collects +// metadata about object allocations allocate an Array. Presently, +// enableShellObjectMetadataCallback installs a callback that does this, but if +// that hook gets removed (in production there's only ever one callback we +// actually use), then the ability to make whatever metadata collection code +// remains allocate an Array will cover this regression. For example, it could +// be a flag that one can only set in debug builds from TestingFunctions.cpp. +newGlobal().eval('enableShellObjectMetadataCallback(); Array'); diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 5d64e7068c5..3c6ff907de0 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -120,6 +120,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle global, JS { MOZ_ASSERT(!global->isStandardClassResolved(key)); + // Prohibit collection of allocation metadata. Metadata builders shouldn't + // need to observe lazily-constructed prototype objects coming into + // existence. And assertions start to fail when the builder itself attempts + // an allocation that re-entrantly tries to create the same prototype. + AutoSuppressObjectMetadataCallback suppressMetadata(cx); + // There are two different kinds of initialization hooks. One of them is // the class js::InitFoo hook, defined in a JSProtoKey-keyed table at the // top of this file. The other lives in the ClassSpec for classes that From c01aabe0f59b416683ebe696d28671ac7ec6e3dd Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 19 Feb 2016 21:21:19 -0600 Subject: [PATCH 089/252] Bug 1225944 - Allow reinstalling temp add-ons. r=Mossop MozReview-Commit-ID: JTbCaKGJ7wW --- toolkit/mozapps/extensions/internal/XPIProvider.jsm | 7 +------ .../mozapps/extensions/test/xpcshell/test_temporary.js | 10 +--------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 70e3828ae19..e5451ab6399 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -3822,12 +3822,7 @@ this.XPIProvider = { let oldAddon = yield new Promise( resolve => XPIDatabase.getVisibleAddonForID(addon.id, resolve)); if (oldAddon) { - if (oldAddon.location == KEY_APP_TEMPORARY) { - logger.warn("temporary add-on already installed:", addon.id); - throw new Error("Add-on with ID " + oldAddon.id + " is already" - + " temporarily installed"); - } - else if (!oldAddon.bootstrap) { + if (!oldAddon.bootstrap) { logger.warn("Non-restartless Add-on is already installed", addon.id); throw new Error("Non-restartless add-on with ID " + oldAddon.id + " is already installed"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js index 93bf6c8acff..8c26ce895aa 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js @@ -425,15 +425,7 @@ add_task(function*() { do_check_eq(addon.type, "extension"); do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED); - try { - yield AddonManager.installTemporaryAddon(do_get_addon("test_bootstrap1_1")); - do_throw("Installing a temporary second temporary add-on should return" - + " a rejected promise"); - } catch (err) { - do_check_eq(err.message, - "Add-on with ID bootstrap1@tests.mozilla.org is already temporarily" - + " installed"); - } + yield AddonManager.installTemporaryAddon(do_get_addon("test_bootstrap1_1")); BootstrapMonitor.checkAddonInstalled(ID, "1.0"); BootstrapMonitor.checkAddonStarted(ID, "1.0"); From f6f75f08c602f7b0bd6f965a2178ff24e548ddc9 Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 23 Feb 2016 10:31:02 +0000 Subject: [PATCH 090/252] Bug 1090656 - re-enable already-passing test in e10s, rs=checked-e10s-test-on-try MozReview-Commit-ID: 6h7c4ie9D3j --- browser/components/customizableui/test/browser.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini index 9e5f7146ae7..2ff93150858 100644 --- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -33,7 +33,6 @@ skip-if = os == "mac" skip-if = os == "linux" [browser_901207_searchbar_in_panel.js] -skip-if = e10s # bug 1090656 [browser_913972_currentset_overflow.js] skip-if = os == "linux" From 413be0d7c5ea9fdd4294bd5e0fd2829e9c298746 Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 23 Feb 2016 10:32:21 +0000 Subject: [PATCH 091/252] Bug 1091561 - fix tab bookkeeping for cut/copy/paste tests to make them work on e10s, rs=trivial MozReview-Commit-ID: 4b1ZMZ6q3Yh --- .../customizableui/test/browser.ini | 6 +- .../test/browser_947914_button_copy.js | 77 +++++++++---------- .../test/browser_947914_button_cut.js | 75 +++++++++--------- .../test/browser_947914_button_paste.js | 46 +++++------ 4 files changed, 94 insertions(+), 110 deletions(-) diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini index 2ff93150858..507a4fb3861 100644 --- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -68,9 +68,9 @@ skip-if = os == "linux" [browser_947914_button_addons.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_copy.js] -skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 +skip-if = os == "linux" # Intermittent failures on Linux [browser_947914_button_cut.js] -skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 +skip-if = os == "linux" # Intermittent failures on Linux [browser_947914_button_find.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_history.js] @@ -80,7 +80,7 @@ skip-if = os == "linux" # Intermittent failures [browser_947914_button_newWindow.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_paste.js] -skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 +skip-if = os == "linux" # Intermittent failures on Linux [browser_947914_button_print.js] skip-if = os == "linux" || (os == "win" && e10s) # Intermittent failures on Linux, e10s issues on Windows (bug 1088714) [browser_947914_button_savePage.js] diff --git a/browser/components/customizableui/test/browser_947914_button_copy.js b/browser/components/customizableui/test/browser_947914_button_copy.js index 60967dfb3cf..c778c956f16 100644 --- a/browser/components/customizableui/test/browser_947914_button_copy.js +++ b/browser/components/customizableui/test/browser_947914_button_copy.js @@ -8,57 +8,52 @@ var initialLocation = gBrowser.currentURI.spec; var globalClipboard; add_task(function*() { - info("Check copy button existence and functionality"); + yield BrowserTestUtils.withNewTab({gBrowser, url: "about:blank"}, function*() { + info("Check copy button existence and functionality"); - let testText = "copy text test"; + let testText = "copy text test"; - gURLBar.focus(); - info("The URL bar was focused"); - yield PanelUI.show(); - info("Menu panel was opened"); + gURLBar.focus(); + info("The URL bar was focused"); + yield PanelUI.show(); + info("Menu panel was opened"); - let copyButton = document.getElementById("copy-button"); - ok(copyButton, "Copy button exists in Panel Menu"); - ok(copyButton.getAttribute("disabled"), "Copy button is initially disabled"); + let copyButton = document.getElementById("copy-button"); + ok(copyButton, "Copy button exists in Panel Menu"); + ok(copyButton.getAttribute("disabled"), "Copy button is initially disabled"); - // copy text from URL bar - gURLBar.value = testText; - gURLBar.focus(); - gURLBar.select(); - yield PanelUI.show(); - info("Menu panel was opened"); + // copy text from URL bar + gURLBar.value = testText; + gURLBar.focus(); + gURLBar.select(); + yield PanelUI.show(); + info("Menu panel was opened"); - ok(!copyButton.hasAttribute("disabled"), "Copy button is enabled when selecting"); + ok(!copyButton.hasAttribute("disabled"), "Copy button is enabled when selecting"); - copyButton.click(); - is(gURLBar.value, testText, "Selected text is unaltered when clicking copy"); + copyButton.click(); + is(gURLBar.value, testText, "Selected text is unaltered when clicking copy"); - // check that the text was added to the clipboard - let clipboard = Services.clipboard; - let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); - globalClipboard = clipboard.kGlobalClipboard; + // check that the text was added to the clipboard + let clipboard = Services.clipboard; + let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); + globalClipboard = clipboard.kGlobalClipboard; - transferable.init(null); - transferable.addDataFlavor("text/unicode"); - clipboard.getData(transferable, globalClipboard); - let str = {}, strLength = {}; - transferable.getTransferData("text/unicode", str, strLength); - let clipboardValue = ""; + transferable.init(null); + transferable.addDataFlavor("text/unicode"); + clipboard.getData(transferable, globalClipboard); + let str = {}, strLength = {}; + transferable.getTransferData("text/unicode", str, strLength); + let clipboardValue = ""; - if (str.value) { - str.value.QueryInterface(Ci.nsISupportsString); - clipboardValue = str.value.data; - } - is(clipboardValue, testText, "Data was copied to the clipboard."); + if (str.value) { + str.value.QueryInterface(Ci.nsISupportsString); + clipboardValue = str.value.data; + } + is(clipboardValue, testText, "Data was copied to the clipboard."); + }); }); -add_task(function* asyncCleanup() { - // clear the clipboard +registerCleanupFunction(function cleanup() { Services.clipboard.emptyClipboard(globalClipboard); - info("Clipboard was cleared"); - - // restore the tab as it was at the begining of the test - gBrowser.addTab(initialLocation); - gBrowser.removeTab(gBrowser.selectedTab); - info("Tabs were restored"); }); diff --git a/browser/components/customizableui/test/browser_947914_button_cut.js b/browser/components/customizableui/test/browser_947914_button_cut.js index 8a2b4bd3506..e6e6143686f 100644 --- a/browser/components/customizableui/test/browser_947914_button_cut.js +++ b/browser/components/customizableui/test/browser_947914_button_cut.js @@ -8,55 +8,50 @@ var initialLocation = gBrowser.currentURI.spec; var globalClipboard; add_task(function*() { - info("Check cut button existence and functionality"); + yield BrowserTestUtils.withNewTab({gBrowser, url: "about:blank"}, function*() { + info("Check cut button existence and functionality"); - let testText = "cut text test"; + let testText = "cut text test"; - gURLBar.focus(); - yield PanelUI.show(); - info("Menu panel was opened"); + gURLBar.focus(); + yield PanelUI.show(); + info("Menu panel was opened"); - let cutButton = document.getElementById("cut-button"); - ok(cutButton, "Cut button exists in Panel Menu"); - ok(cutButton.hasAttribute("disabled"), "Cut button is disabled"); + let cutButton = document.getElementById("cut-button"); + ok(cutButton, "Cut button exists in Panel Menu"); + ok(cutButton.hasAttribute("disabled"), "Cut button is disabled"); - // cut text from URL bar - gURLBar.value = testText; - gURLBar.focus(); - gURLBar.select(); - yield PanelUI.show(); - info("Menu panel was opened"); + // cut text from URL bar + gURLBar.value = testText; + gURLBar.focus(); + gURLBar.select(); + yield PanelUI.show(); + info("Menu panel was opened"); - ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled when selecting"); - cutButton.click(); - is(gURLBar.value, "", "Selected text is removed from source when clicking on cut"); + ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled when selecting"); + cutButton.click(); + is(gURLBar.value, "", "Selected text is removed from source when clicking on cut"); - // check that the text was added to the clipboard - let clipboard = Services.clipboard; - let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); - globalClipboard = clipboard.kGlobalClipboard; + // check that the text was added to the clipboard + let clipboard = Services.clipboard; + let transferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable); + globalClipboard = clipboard.kGlobalClipboard; - transferable.init(null); - transferable.addDataFlavor("text/unicode"); - clipboard.getData(transferable, globalClipboard); - let str = {}, strLength = {}; - transferable.getTransferData("text/unicode", str, strLength); - let clipboardValue = ""; + transferable.init(null); + transferable.addDataFlavor("text/unicode"); + clipboard.getData(transferable, globalClipboard); + let str = {}, strLength = {}; + transferable.getTransferData("text/unicode", str, strLength); + let clipboardValue = ""; - if (str.value) { - str.value.QueryInterface(Ci.nsISupportsString); - clipboardValue = str.value.data; - } - is(clipboardValue, testText, "Data was copied to the clipboard."); + if (str.value) { + str.value.QueryInterface(Ci.nsISupportsString); + clipboardValue = str.value.data; + } + is(clipboardValue, testText, "Data was copied to the clipboard."); + }); }); -add_task(function* asyncCleanup() { - // clear the clipboard +registerCleanupFunction(function cleanup() { Services.clipboard.emptyClipboard(globalClipboard); - info("Clipboard was cleared"); - - // restore the tab as it was at the begining of the test - gBrowser.addTab(initialLocation); - gBrowser.removeTab(gBrowser.selectedTab); - info("Tabs were restored"); }); diff --git a/browser/components/customizableui/test/browser_947914_button_paste.js b/browser/components/customizableui/test/browser_947914_button_paste.js index 1abdcf11b93..fc83ead56f0 100644 --- a/browser/components/customizableui/test/browser_947914_button_paste.js +++ b/browser/components/customizableui/test/browser_947914_button_paste.js @@ -8,40 +8,34 @@ var initialLocation = gBrowser.currentURI.spec; var globalClipboard; add_task(function*() { - info("Check paste button existence and functionality"); + yield BrowserTestUtils.withNewTab({gBrowser, url: "about:blank"}, function*() { + info("Check paste button existence and functionality"); - let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); - globalClipboard = Services.clipboard.kGlobalClipboard; + let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); + globalClipboard = Services.clipboard.kGlobalClipboard; - yield PanelUI.show(); - info("Menu panel was opened"); + yield PanelUI.show(); + info("Menu panel was opened"); - let pasteButton = document.getElementById("paste-button"); - ok(pasteButton, "Paste button exists in Panel Menu"); + let pasteButton = document.getElementById("paste-button"); + ok(pasteButton, "Paste button exists in Panel Menu"); - // add text to clipboard - let text = "Sample text for testing"; - clipboard.copyString(text); + // add text to clipboard + let text = "Sample text for testing"; + clipboard.copyString(text); - // test paste button by pasting text to URL bar - gURLBar.focus(); - yield PanelUI.show(); - info("Menu panel was opened"); + // test paste button by pasting text to URL bar + gURLBar.focus(); + yield PanelUI.show(); + info("Menu panel was opened"); - ok(!pasteButton.hasAttribute("disabled"), "Paste button is enabled"); - pasteButton.click(); + ok(!pasteButton.hasAttribute("disabled"), "Paste button is enabled"); + pasteButton.click(); - is(gURLBar.value, text, "Text pasted successfully"); + is(gURLBar.value, text, "Text pasted successfully"); + }); }); -add_task(function* asyncCleanup() { - // clear the clipboard +registerCleanupFunction(function cleanup() { Services.clipboard.emptyClipboard(globalClipboard); - info("Clipboard was cleared"); - - // restore the tab as it was at the begining of the test - gBrowser.addTab(initialLocation); - gBrowser.removeTab(gBrowser.selectedTab); - info("Tabs were restored"); }); - From 6d05331f9e6747a8fd68e26d78490cb5f0bd5b04 Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 23 Feb 2016 10:33:43 +0000 Subject: [PATCH 092/252] Bug 1088714, bug 1090635, bug 1102900 - re-enable various CUI tests now the test framework deals with e10s in a way that makes them pass, rs=checked-e10s-test-on-try MozReview-Commit-ID: FPnT7qj3qeC --- browser/components/customizableui/test/browser.ini | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini index 507a4fb3861..b48485abcab 100644 --- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -82,7 +82,7 @@ skip-if = os == "linux" # Intermittent failures [browser_947914_button_paste.js] skip-if = os == "linux" # Intermittent failures on Linux [browser_947914_button_print.js] -skip-if = os == "linux" || (os == "win" && e10s) # Intermittent failures on Linux, e10s issues on Windows (bug 1088714) +skip-if = os == "linux" # Intermittent failures on Linux [browser_947914_button_savePage.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_zoomIn.js] @@ -122,7 +122,6 @@ skip-if = os == "linux" [browser_984455_bookmarks_items_reparenting.js] skip-if = os == "linux" [browser_985815_propagate_setToolbarVisibility.js] -skip-if = e10s # bug 1090635 [browser_987177_destroyWidget_xul.js] [browser_987177_xul_wrapper_updating.js] [browser_987185_syncButton.js] @@ -132,7 +131,6 @@ skip-if = e10s # Bug 1088710 [browser_988072_sidebar_events.js] [browser_989338_saved_placements_not_resaved.js] [browser_989751_subviewbutton_class.js] -skip-if = os == "linux" && e10s # Bug 1102900, bug 1104745, bug 1104761 [browser_992747_toggle_noncustomizable_toolbar.js] [browser_993322_widget_notoolbar.js] [browser_995164_registerArea_during_customize_mode.js] From d3b3109adc724016910196c13ed4cd102e732837 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 23 Feb 2016 10:10:10 -0500 Subject: [PATCH 093/252] Bug 1250383 - Upgrade to CodeMirror 5.12.0 r=vporof --- .../codemirror/addon/dialog/dialog.js | 4 +- .../codemirror/addon/edit/matchtags.js | 0 .../codemirror/addon/edit/trailingspace.js | 0 .../codemirror/addon/fold/brace-fold.js | 0 .../codemirror/addon/fold/comment-fold.js | 0 .../codemirror/addon/fold/indent-fold.js | 0 .../codemirror/addon/fold/markdown-fold.js | 0 .../codemirror/addon/hint/show-hint.js | 0 .../addon/search/match-highlighter.js | 43 +++++++--- .../codemirror/addon/selection/active-line.js | 3 + .../addon/selection/mark-selection.js | 0 .../sourceeditor/codemirror/keymap/sublime.js | 2 +- .../sourceeditor/codemirror/keymap/vim.js | 4 + .../codemirror/lib/codemirror.css | 1 + .../sourceeditor/codemirror/lib/codemirror.js | 22 ++--- .../sourceeditor/codemirror/mode/clike.js | 83 ++++++++++--------- .../sourceeditor/codemirror/mode/htmlmixed.js | 42 +++++----- .../sourceeditor/codemirror/mode/xml.js | 2 +- .../sourceeditor/test/codemirror/doc_test.js | 0 .../test/codemirror/mode/javascript/test.js | 4 + .../test/codemirror/mode_test.css | 0 .../test/codemirror/multi_test.js | 0 .../test/codemirror/search_test.js | 0 .../test/codemirror/sublime_test.js | 0 .../sourceeditor/test/codemirror/vim_test.js | 8 +- 25 files changed, 135 insertions(+), 83 deletions(-) mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/edit/matchtags.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/edit/trailingspace.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/fold/brace-fold.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/fold/comment-fold.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/fold/indent-fold.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/fold/markdown-fold.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/addon/selection/mark-selection.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/keymap/sublime.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/keymap/vim.js mode change 100644 => 100755 devtools/client/sourceeditor/codemirror/lib/codemirror.css mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/doc_test.js mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/mode_test.css mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/multi_test.js mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/search_test.js mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/sublime_test.js mode change 100644 => 100755 devtools/client/sourceeditor/test/codemirror/vim_test.js diff --git a/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js b/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js index 323b20078e8..f10bb5bf190 100755 --- a/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js +++ b/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js @@ -56,6 +56,8 @@ var inp = dialog.getElementsByTagName("input")[0], button; if (inp) { + inp.focus(); + if (options.value) { inp.value = options.value; if (options.selectValueOnOpen !== false) { @@ -79,8 +81,6 @@ }); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); - - inp.focus(); } else if (button = dialog.getElementsByTagName("button")[0]) { CodeMirror.on(button, "click", function() { close(); diff --git a/devtools/client/sourceeditor/codemirror/addon/edit/matchtags.js b/devtools/client/sourceeditor/codemirror/addon/edit/matchtags.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/edit/trailingspace.js b/devtools/client/sourceeditor/codemirror/addon/edit/trailingspace.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/fold/brace-fold.js b/devtools/client/sourceeditor/codemirror/addon/fold/brace-fold.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/fold/comment-fold.js b/devtools/client/sourceeditor/codemirror/addon/fold/comment-fold.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/fold/indent-fold.js b/devtools/client/sourceeditor/codemirror/addon/fold/indent-fold.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/fold/markdown-fold.js b/devtools/client/sourceeditor/codemirror/addon/fold/markdown-fold.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js b/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js index e9a22721f78..8f02f01c873 100755 --- a/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js +++ b/devtools/client/sourceeditor/codemirror/addon/search/match-highlighter.js @@ -16,13 +16,14 @@ // highlighted only if the selected text is a word. showToken, when enabled, // will cause the current token to be highlighted when nothing is selected. // delay is used to specify how much time to wait, in milliseconds, before -// highlighting the matches. +// highlighting the matches. If annotateScrollbar is enabled, the occurances +// will be highlighted on the scrollbar via the matchesonscrollbar addon. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror"), require("./matchesonscrollbar")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "./matchesonscrollbar"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { @@ -40,18 +41,19 @@ this.showToken = options.showToken; this.delay = options.delay; this.wordsOnly = options.wordsOnly; + this.annotateScrollbar = options.annotateScrollbar; } if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; if (this.delay == null) this.delay = DEFAULT_DELAY; if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; this.overlay = this.timeout = null; + this.matchesonscroll = null; } CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { - var over = cm.state.matchHighlighter.overlay; - if (over) cm.removeOverlay(over); + removeOverlay(cm); clearTimeout(cm.state.matchHighlighter.timeout); cm.state.matchHighlighter = null; cm.off("cursorActivity", cursorActivity); @@ -69,20 +71,39 @@ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); } + function addOverlay(cm, query, hasBoundary, style) { + var state = cm.state.matchHighlighter; + cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); + if (state.annotateScrollbar) { + var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query; + state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true, + {className: "CodeMirror-selection-highlight-scrollbar"}); + } + } + + function removeOverlay(cm) { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + if (state.annotateScrollbar) { + state.matchesonscroll.clear(); + state.matchesonscroll = null; + } + } + } + function highlightMatches(cm) { cm.operation(function() { var state = cm.state.matchHighlighter; - if (state.overlay) { - cm.removeOverlay(state.overlay); - state.overlay = null; - } + removeOverlay(cm); if (!cm.somethingSelected() && state.showToken) { var re = state.showToken === true ? /[\w$]/ : state.showToken; var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; while (start && re.test(line.charAt(start - 1))) --start; while (end < line.length && re.test(line.charAt(end))) ++end; if (start < end) - cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); + addOverlay(cm, line.slice(start, end), re, state.style); return; } var from = cm.getCursor("from"), to = cm.getCursor("to"); @@ -90,7 +111,7 @@ if (state.wordsOnly && !isWord(cm, from, to)) return; var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); if (selection.length >= state.minChars) - cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); + addOverlay(cm, selection, false, state.style); }); } diff --git a/devtools/client/sourceeditor/codemirror/addon/selection/active-line.js b/devtools/client/sourceeditor/codemirror/addon/selection/active-line.js index 22da2e0aace..b0b3f61af20 100755 --- a/devtools/client/sourceeditor/codemirror/addon/selection/active-line.js +++ b/devtools/client/sourceeditor/codemirror/addon/selection/active-line.js @@ -18,6 +18,7 @@ "use strict"; var WRAP_CLASS = "CodeMirror-activeline"; var BACK_CLASS = "CodeMirror-activeline-background"; + var GUTT_CLASS = "CodeMirror-activeline-gutter"; CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; @@ -36,6 +37,7 @@ for (var i = 0; i < cm.state.activeLines.length; i++) { cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); } } @@ -60,6 +62,7 @@ for (var i = 0; i < active.length; i++) { cm.addLineClass(active[i], "wrap", WRAP_CLASS); cm.addLineClass(active[i], "background", BACK_CLASS); + cm.addLineClass(active[i], "gutter", GUTT_CLASS); } cm.state.activeLines = active; }); diff --git a/devtools/client/sourceeditor/codemirror/addon/selection/mark-selection.js b/devtools/client/sourceeditor/codemirror/addon/selection/mark-selection.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/codemirror/keymap/sublime.js b/devtools/client/sourceeditor/codemirror/keymap/sublime.js old mode 100644 new mode 100755 index e0d0e92b91c..49db3b871c9 --- a/devtools/client/sourceeditor/codemirror/keymap/sublime.js +++ b/devtools/client/sourceeditor/codemirror/keymap/sublime.js @@ -105,7 +105,7 @@ cm.setSelections(extended); }; - map["Shift-" + ctrl + "K"] = "deleteLine"; + map["Shift-Ctrl-K"] = "deleteLine"; function insertLine(cm, above) { if (cm.isReadOnly()) return CodeMirror.Pass diff --git a/devtools/client/sourceeditor/codemirror/keymap/vim.js b/devtools/client/sourceeditor/codemirror/keymap/vim.js old mode 100644 new mode 100755 index 0548b75be7b..87b94e352b1 --- a/devtools/client/sourceeditor/codemirror/keymap/vim.js +++ b/devtools/client/sourceeditor/codemirror/keymap/vim.js @@ -164,6 +164,7 @@ { keys: 'v', type: 'action', action: 'toggleVisualMode' }, { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }}, { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, + { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }}, @@ -681,6 +682,9 @@ // Add user defined key bindings. exCommandDispatcher.map(lhs, rhs, ctx); }, + unmap: function(lhs, ctx) { + exCommandDispatcher.unmap(lhs, ctx); + }, // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace // them, or somehow make them work with the existing CodeMirror setOption/getOption API. setOption: setOption, diff --git a/devtools/client/sourceeditor/codemirror/lib/codemirror.css b/devtools/client/sourceeditor/codemirror/lib/codemirror.css old mode 100644 new mode 100755 index 1067b3ee6b4..ebfe4f697fe --- a/devtools/client/sourceeditor/codemirror/lib/codemirror.css +++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.css @@ -197,6 +197,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} white-space: normal; height: 100%; display: inline-block; + vertical-align: top; margin-bottom: -30px; /* Hack to make IE7 behave */ *zoom:1; diff --git a/devtools/client/sourceeditor/codemirror/lib/codemirror.js b/devtools/client/sourceeditor/codemirror/lib/codemirror.js index 090e4216175..e803211bc21 100755 --- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js +++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js @@ -543,6 +543,7 @@ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" if (sizes.right && sizes.bottom) { d.scrollbarFiller.style.display = "block"; @@ -787,9 +788,9 @@ function setDocumentHeight(cm, measure) { cm.display.sizer.style.minHeight = measure.docHeight + "px"; - var total = measure.docHeight + cm.display.barHeight; - cm.display.heightForcer.style.top = total + "px"; - cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; + cm.display.heightForcer.style.top = measure.docHeight + "px"; + cm.display.gutters.style.height = Math.max(measure.docHeight + cm.display.barHeight + scrollGap(cm), + measure.clientHeight) + "px"; } // Read the actual heights of the rendered lines, and update their @@ -1482,10 +1483,11 @@ if (reset && cm.doc.sel.contains(pos) == -1) operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); - var oldCSS = te.style.cssText; - input.wrapper.style.position = "absolute"; - te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + - "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; + input.wrapper.style.cssText = "position: absolute" + var wrapperBox = input.wrapper.getBoundingClientRect() + te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) @@ -1516,7 +1518,7 @@ } function rehide() { input.contextMenuPending = false; - input.wrapper.style.position = "relative"; + input.wrapper.style.cssText = oldWrapperCSS te.style.cssText = oldCSS; if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); @@ -3139,7 +3141,7 @@ display.scroller.scrollTop = doc.scrollTop; } if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { - doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); display.scrollbars.setScrollLeft(doc.scrollLeft); display.scroller.scrollLeft = doc.scrollLeft; alignHorizontally(cm); @@ -8884,7 +8886,7 @@ // THE END - CodeMirror.version = "5.11.0"; + CodeMirror.version = "5.12.0"; return CodeMirror; }); diff --git a/devtools/client/sourceeditor/codemirror/mode/clike.js b/devtools/client/sourceeditor/codemirror/mode/clike.js index 4f5c0cf3700..db7f89373d8 100755 --- a/devtools/client/sourceeditor/codemirror/mode/clike.js +++ b/devtools/client/sourceeditor/codemirror/mode/clike.js @@ -11,6 +11,42 @@ })(function(CodeMirror) { "use strict"; +function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; +} +function isStatement(type) { + return type == "statement" || type == "switchstatement" || type == "namespace"; +} +function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && isStatement(state.context.type) && !isStatement(type)) + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); +} +function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; +} + +function typeBefore(stream, state) { + if (state.prevToken == "variable" || state.prevToken == "variable-3") return true; + if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true; +} + +function isTopScope(context) { + for (;;) { + if (!context || context.type == "top") return true; + if (context.type == "}" && context.prev.type != "namespace") return false; + context = context.prev; + } +} + CodeMirror.defineMode("clike", function(config, parserConfig) { var indentUnit = config.indentUnit, statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, @@ -111,42 +147,6 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { return "comment"; } - function Context(indented, column, type, align, prev) { - this.indented = indented; - this.column = column; - this.type = type; - this.align = align; - this.prev = prev; - } - function isStatement(type) { - return type == "statement" || type == "switchstatement" || type == "namespace"; - } - function pushContext(state, col, type) { - var indent = state.indented; - if (state.context && isStatement(state.context.type) && !isStatement(type)) - indent = state.context.indented; - return state.context = new Context(indent, col, type, null, state.context); - } - function popContext(state) { - var t = state.context.type; - if (t == ")" || t == "]" || t == "}") - state.indented = state.context.indented; - return state.context = state.context.prev; - } - - function typeBefore(stream, state) { - if (state.prevToken == "variable" || state.prevToken == "variable-3") return true; - if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true; - } - - function isTopScope(context) { - for (;;) { - if (!context || context.type == "top") return true; - if (context.type == "}" && context.prev.type != "namespace") return false; - context = context.prev; - } - } - // Interface return { @@ -497,7 +497,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { ), types: words( "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + - "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " + + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + @@ -527,6 +527,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { "'": function(stream) { stream.eatWhile(/[\w\$_\xa1-\uffff]/); return "atom"; + }, + "=": function(stream, state) { + var cx = state.context + if (cx.type == "}" && cx.align && stream.eat(">")) { + state.context = new Context(cx.indented, cx.column, cx.type, null, cx.prev) + return "operator" + } else { + return false + } } }, modeProps: {closeBrackets: {triples: '"'}} diff --git a/devtools/client/sourceeditor/codemirror/mode/htmlmixed.js b/devtools/client/sourceeditor/codemirror/mode/htmlmixed.js index 21e74f163dd..6574fbd5697 100755 --- a/devtools/client/sourceeditor/codemirror/mode/htmlmixed.js +++ b/devtools/client/sourceeditor/codemirror/mode/htmlmixed.js @@ -44,13 +44,9 @@ return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); } - function getAttrValue(stream, attr) { - var pos = stream.pos, match; - while (pos >= 0 && stream.string.charAt(pos) !== "<") pos--; - if (pos < 0) return pos; - if (match = stream.string.slice(pos, stream.pos).match(getAttrRegexp(attr))) - return match[2]; - return ""; + function getAttrValue(text, attr) { + var match = text.match(getAttrRegexp(attr)) + return match ? match[2] : "" } function getTagRegexp(tagName, anchored) { @@ -66,10 +62,10 @@ } } - function findMatchingMode(tagInfo, stream) { + function findMatchingMode(tagInfo, tagText) { for (var i = 0; i < tagInfo.length; i++) { var spec = tagInfo[i]; - if (!spec[0] || spec[1].test(getAttrValue(stream, spec[0]))) return spec[2]; + if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; } } @@ -89,15 +85,17 @@ tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) function html(stream, state) { - var tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase(); - var tagInfo = tagName && tags.hasOwnProperty(tagName) && tags[tagName]; - - var style = htmlMode.token(stream, state.htmlState), modeSpec; - - if (tagInfo && /\btag\b/.test(style) && stream.current() === ">" && - (modeSpec = findMatchingMode(tagInfo, stream))) { - var mode = CodeMirror.getMode(config, modeSpec); - var endTagA = getTagRegexp(tagName, true), endTag = getTagRegexp(tagName, false); + var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName + if (tag && !/[<>\s\/]/.test(stream.current()) && + (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && + tags.hasOwnProperty(tagName)) { + state.inTag = tagName + " " + } else if (state.inTag && tag && />$/.test(stream.current())) { + var inTag = /^([\S]+) (.*)/.exec(state.inTag) + state.inTag = null + var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) + var mode = CodeMirror.getMode(config, modeSpec) + var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); state.token = function (stream, state) { if (stream.match(endTagA, false)) { state.token = html; @@ -108,6 +106,9 @@ }; state.localMode = mode; state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); + } else if (state.inTag) { + state.inTag += stream.current() + if (stream.eol()) state.inTag += " " } return style; }; @@ -115,7 +116,7 @@ return { startState: function () { var state = htmlMode.startState(); - return {token: html, localMode: null, localState: null, htmlState: state}; + return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; }, copyState: function (state) { @@ -123,7 +124,8 @@ if (state.localState) { local = CodeMirror.copyState(state.localMode, state.localState); } - return {token: state.token, localMode: state.localMode, localState: local, + return {token: state.token, inTag: state.inTag, + localMode: state.localMode, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; }, diff --git a/devtools/client/sourceeditor/codemirror/mode/xml.js b/devtools/client/sourceeditor/codemirror/mode/xml.js index 014f7d846dc..f987a3a3ce9 100755 --- a/devtools/client/sourceeditor/codemirror/mode/xml.js +++ b/devtools/client/sourceeditor/codemirror/mode/xml.js @@ -237,7 +237,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { if (state.context && state.context.tagName != tagName && config.implicitlyClosed.hasOwnProperty(state.context.tagName)) popContext(state); - if (state.context && state.context.tagName == tagName) { + if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { setStyle = "tag"; return closeState; } else { diff --git a/devtools/client/sourceeditor/test/codemirror/doc_test.js b/devtools/client/sourceeditor/test/codemirror/doc_test.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js index 252e064dccd..cb43d0894de 100755 --- a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js +++ b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js @@ -17,6 +17,10 @@ " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", "})();"); + MT("destructure_trailing_comma", + "[keyword let] {[def a], [def b],} [operator =] [variable foo];", + "[keyword let] [def c];"); // Parser still in good state? + MT("class_body", "[keyword class] [def Foo] {", " [property constructor]() {}", diff --git a/devtools/client/sourceeditor/test/codemirror/mode_test.css b/devtools/client/sourceeditor/test/codemirror/mode_test.css old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/test/codemirror/multi_test.js b/devtools/client/sourceeditor/test/codemirror/multi_test.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/test/codemirror/search_test.js b/devtools/client/sourceeditor/test/codemirror/search_test.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/test/codemirror/sublime_test.js b/devtools/client/sourceeditor/test/codemirror/sublime_test.js old mode 100644 new mode 100755 diff --git a/devtools/client/sourceeditor/test/codemirror/vim_test.js b/devtools/client/sourceeditor/test/codemirror/vim_test.js old mode 100644 new mode 100755 index 25f7e75e907..c75e003a473 --- a/devtools/client/sourceeditor/test/codemirror/vim_test.js +++ b/devtools/client/sourceeditor/test/codemirror/vim_test.js @@ -3950,7 +3950,13 @@ testVim('ex_imap', function(cm, vim, helpers) { is(vim.insertMode); helpers.doKeys('j', 'k'); is(!vim.insertMode); -}) +}); +testVim('ex_unmap_api', function(cm, vim, helpers) { + CodeMirror.Vim.map('', 'gg', 'normal'); + is(CodeMirror.Vim.handleKey(cm, "", "normal"), "Alt-X key is mapped"); + CodeMirror.Vim.unmap("", "normal"); + is(!CodeMirror.Vim.handleKey(cm, "", "normal"), "Alt-X key is unmapped"); +}); // Testing registration of functions as ex-commands and mapping to -keys testVim('ex_api_test', function(cm, vim, helpers) { From 1e4caa0ce2b74e5aa81cb643fcd0d82dde37fab1 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Mon, 22 Feb 2016 18:17:43 +0100 Subject: [PATCH 094/252] Bug 976940 - FormHistory.update() should throw if form history is disabled and the operation is not a removal. r=markh MozReview-Commit-ID: 94FRqGofGsP --- toolkit/components/satchel/FormHistory.jsm | 11 ++++--- .../satchel/test/unit/test_history_api.js | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/toolkit/components/satchel/FormHistory.jsm b/toolkit/components/satchel/FormHistory.jsm index 82aaaf76f35..adb0b2eec72 100644 --- a/toolkit/components/satchel/FormHistory.jsm +++ b/toolkit/components/satchel/FormHistory.jsm @@ -842,10 +842,6 @@ this.FormHistory = { }, update : function formHistoryUpdate(aChanges, aCallbacks) { - if (!Prefs.enabled) { - return; - } - // Used to keep track of how many searches have been started. When that number // are finished, updateFormHistoryWrite can be called. let numSearches = 0; @@ -860,6 +856,13 @@ this.FormHistory = { if (!("length" in aChanges)) aChanges = [aChanges]; + let isRemoveOperation = aChanges.every(change => change && change.op && change.op == "remove"); + if (!Prefs.enabled && !isRemoveOperation) { + throw Components.Exception( + "Form history is disabled, only remove operations are allowed", + Cr.NS_ERROR_ILLEGAL_VALUE); + } + for (let change of aChanges) { switch (change.op) { case "remove": diff --git a/toolkit/components/satchel/test/unit/test_history_api.js b/toolkit/components/satchel/test/unit/test_history_api.js index 001c199036d..be8805dbec3 100644 --- a/toolkit/components/satchel/test/unit/test_history_api.js +++ b/toolkit/components/satchel/test/unit/test_history_api.js @@ -405,6 +405,36 @@ add_task(function* () yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); + // ===== 21 ===== + // Check update throws if form history is disabled and the operation is not a + // pure removal. + testnum++; + Services.prefs.setBoolPref("browser.formfill.enable", false); + Assert.throws(() => promiseUpdate( + { op : "bump", fieldname: "field5", value: "value5" }), + /NS_ERROR_ILLEGAL_VALUE/); + Assert.throws(() => promiseUpdate( + { op : "add", fieldname: "field5", value: "value5" }), + /NS_ERROR_ILLEGAL_VALUE/); + Assert.throws(() => promiseUpdate([ + { op : "update", fieldname: "field5", value: "value5" }, + { op : "remove", fieldname: "field5", value: "value5" } + ]), + /NS_ERROR_ILLEGAL_VALUE/); + Assert.throws(() => promiseUpdate([ + null, + undefined, + "", + 1, + {}, + { op : "remove", fieldname: "field5", value: "value5" } + ]), + /NS_ERROR_ILLEGAL_VALUE/); + // Remove should work though. + yield promiseUpdate([{ op: "remove", fieldname: "field5", value: null }, + { op: "remove", fieldname: null, value: null }]); + Services.prefs.clearUserPref("browser.formfill.enable"); + } catch (e) { throw "FAILED in test #" + testnum + " -- " + e; } From 89076f8a3d6d141a02870f1771ee3a7a00d182ed Mon Sep 17 00:00:00 2001 From: Jared Wein Date: Thu, 18 Feb 2016 15:36:22 -0500 Subject: [PATCH 095/252] Bug 1219794 - Show the bookmark popup for new bookmarks and autoclose if no interaction. r=mak MozReview-Commit-ID: FSx0bB4KqpQ --- browser/base/content/browser-places.js | 141 +++++---- browser/base/content/browser.xul | 18 +- browser/base/content/test/general/browser.ini | 1 + .../test/general/browser_bookmark_popup.js | 271 ++++++++++++++++++ .../locales/en-US/chrome/browser/browser.dtd | 1 - 5 files changed, 358 insertions(+), 74 deletions(-) create mode 100644 browser/base/content/test/general/browser_bookmark_popup.js diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index 47b8debb9f8..54013d915ac 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -9,6 +9,8 @@ var StarUI = { _itemId: -1, uri: null, _batching: false, + _isNewBookmark: false, + _autoCloseTimer: 0, _element: function(aID) { return document.getElementById(aID); @@ -21,8 +23,11 @@ var StarUI = { // initially the panel is hidden // to avoid impacting startup / new window performance element.hidden = false; - element.addEventListener("popuphidden", this, false); element.addEventListener("keypress", this, false); + element.addEventListener("mouseout", this, false); + element.addEventListener("mouseover", this, false); + element.addEventListener("popuphidden", this, false); + element.addEventListener("popupshown", this, false); return this.panel = element; }, @@ -58,7 +63,11 @@ var StarUI = { // nsIDOMEventListener handleEvent(aEvent) { switch (aEvent.type) { + case "mouseover": + clearTimeout(this._autoCloseTimer); + break; case "popuphidden": + clearTimeout(this._autoCloseTimer); if (aEvent.originalTarget == this.panel) { if (!this._element("editBookmarkPanelContent").hidden) this.quitEditMode(); @@ -72,44 +81,42 @@ var StarUI = { if (this._batching) this.endBatch(); - switch (this._actionOnHide) { - case "cancel": { - if (!PlacesUIUtils.useAsyncTransactions) { + if (this._uriForRemoval) { + if (this._isNewBookmark) { + if (!PlacesUtils.useAsyncTransactions) { PlacesUtils.transactionManager.undoTransaction(); break; } - PlacesTransactions.undo().catch(Cu.reportError); + PlacesTransactions().undo().catch(Cu.reportError); break; } - case "remove": { - // Remove all bookmarks for the bookmark's url, this also removes - // the tags for the url. - if (!PlacesUIUtils.useAsyncTransactions) { - let itemIds = PlacesUtils.getBookmarksForURI(this._uriForRemoval); - for (let itemId of itemIds) { - let txn = new PlacesRemoveItemTransaction(itemId); - PlacesUtils.transactionManager.doTransaction(txn); - } - break; + // Remove all bookmarks for the bookmark's url, this also removes + // the tags for the url. + if (!PlacesUIUtils.useAsyncTransactions) { + let itemIds = PlacesUtils.getBookmarksForURI(this._uriForRemoval); + for (let itemId of itemIds) { + let txn = new PlacesRemoveItemTransaction(itemId); + PlacesUtils.transactionManager.doTransaction(txn); } - - PlacesTransactions.RemoveBookmarksForUrls(this._uriForRemoval) - .transact().catch(Cu.reportError); break; } + + PlacesTransactions.RemoveBookmarksForUrls([this._uriForRemoval]) + .transact().catch(Cu.reportError); } - this._actionOnHide = ""; } break; case "keypress": + clearTimeout(this._autoCloseTimer); + if (aEvent.defaultPrevented) { // The event has already been consumed inside of the panel. break; } + switch (aEvent.keyCode) { case KeyEvent.DOM_VK_ESCAPE: - if (!this._element("editBookmarkPanelContent").hidden) - this.cancelButtonOnCommand(); + this.panel.hidePopup(); break; case KeyEvent.DOM_VK_RETURN: if (aEvent.target.classList.contains("expander-up") || @@ -123,12 +130,40 @@ var StarUI = { break; } break; + case "mouseout": { + // Don't handle events for descendent elements. + if (aEvent.target != aEvent.currentTarget) { + break; + } + // Explicit fall-through + } + case "popupshown": + // auto-close if new and not interacted with + if (this._isNewBookmark) { + // 3500ms matches the timeout that Pocket uses in + // browser/extensions/pocket/content/panels/js/saved.js + let delay = 3500; + if (this._closePanelQuickForTesting) { + delay /= 10; + } + this._autoCloseTimer = setTimeout(() => this.panel.hidePopup(), delay, this); + } + break; } }, _overlayLoaded: false, _overlayLoading: false, - showEditBookmarkPopup: Task.async(function* (aNode, aAnchorElement, aPosition) { + showEditBookmarkPopup: Task.async(function* (aNode, aAnchorElement, aPosition, aIsNewBookmark) { + // Slow double-clicks (not true double-clicks) shouldn't + // cause the panel to flicker. + if (this.panel.state == "showing" || + this.panel.state == "open") { + return; + } + + this._isNewBookmark = aIsNewBookmark; + this._uriForRemoval = ""; // TODO: Deprecate this once async transactions are enabled and the legacy // transactions code is gone (bug 1131491) - we don't want addons to to use // the completeNodeLikeObjectForItemId, so it's better if they keep passing @@ -177,26 +212,18 @@ var StarUI = { if (this.panel.state != "closed") return; - this._blockCommands(); // un-done in the popuphiding handler + this._blockCommands(); // un-done in the popuphidden handler - // Set panel title: - // if we are batching, i.e. the bookmark has been added now, - // then show Page Bookmarked, else if the bookmark did already exist, - // we are about editing it, then use Edit This Bookmark. this._element("editBookmarkPanelTitle").value = - this._batching ? + this._isNewBookmark ? gNavigatorBundle.getString("editBookmarkPanel.pageBookmarkedTitle") : gNavigatorBundle.getString("editBookmarkPanel.editBookmarkTitle"); - // No description; show the Done, Cancel; + // No description; show the Done, Remove; this._element("editBookmarkPanelDescription").textContent = ""; this._element("editBookmarkPanelBottomButtons").hidden = false; this._element("editBookmarkPanelContent").hidden = false; - // The remove button is shown only if we're not already batching, i.e. - // if the cancel button/ESC does not remove the bookmark. - this._element("editBookmarkPanelRemoveButton").hidden = this._batching; - // The label of the remove button differs if the URI is bookmarked // multiple times. let bookmarks = PlacesUtils.getBookmarksForURI(gBrowser.currentURI); @@ -250,14 +277,8 @@ var StarUI = { gEditItemOverlay.uninitPanel(true); }, - cancelButtonOnCommand: function SU_cancelButtonOnCommand() { - this._actionOnHide = "cancel"; - this.panel.hidePopup(true); - }, - removeBookmarkButtonCommand: function SU_removeBookmarkButtonCommand() { this._uriForRemoval = PlacesUtils.bookmarks.getBookmarkURI(this._itemId); - this._actionOnHide = "remove"; this.panel.hidePopup(); }, @@ -325,7 +346,8 @@ var PlacesCommandHook = { var uri = aBrowser.currentURI; var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri); - if (itemId == -1) { + let isNewBookmark = itemId == -1; + if (isNewBookmark) { // Bug 1148838 - Make this code work for full page plugins. var title; var description; @@ -342,10 +364,10 @@ var PlacesCommandHook = { } catch (e) { } - if (aShowEditUI) { - // If we bookmark the page here (i.e. page was not "starred" already) - // but open right into the "edit" state, start batching here, so - // "Cancel" in that state removes the bookmark. + if (aShowEditUI && isNewBookmark) { + // If we bookmark the page here but open right into a cancelable + // state (i.e. new bookmark in Library), start batching here so + // all of the actions can be undone in a single undo step. StarUI.beginBatch(); } @@ -376,16 +398,16 @@ var PlacesCommandHook = { // 3. the content area if (BookmarkingUI.anchor) { StarUI.showEditBookmarkPopup(itemId, BookmarkingUI.anchor, - "bottomcenter topright"); + "bottomcenter topright", isNewBookmark); return; } let identityIcon = document.getElementById("identity-icon"); if (isElementVisible(identityIcon)) { StarUI.showEditBookmarkPopup(itemId, identityIcon, - "bottomcenter topright"); + "bottomcenter topright", isNewBookmark); } else { - StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap"); + StarUI.showEditBookmarkPopup(itemId, aBrowser, "overlap", isNewBookmark); } }), @@ -394,6 +416,7 @@ var PlacesCommandHook = { _bookmarkPagePT: Task.async(function* (aBrowser, aParentId, aShowEditUI) { let url = new URL(aBrowser.currentURI.spec); let info = yield PlacesUtils.bookmarks.fetch({ url }); + let isNewBookmark = !info; if (!info) { let parentGuid = aParentId !== undefined ? yield PlacesUtils.promiseItemGuid(aParentId) : @@ -417,10 +440,10 @@ var PlacesCommandHook = { Components.utils.reportError(e); } - if (aShowEditUI) { - // If we bookmark the page here (i.e. page was not "starred" already) - // but open right into the "edit" state, start batching here, so - // "Cancel" in that state removes the bookmark. + if (aShowEditUI && isNewBookmark) { + // If we bookmark the page here but open right into a cancelable + // state (i.e. new bookmark in Library), start batching here so + // all of the actions can be undone in a single undo step. StarUI.beginBatch(); } @@ -452,16 +475,16 @@ var PlacesCommandHook = { // 3. the content area if (BookmarkingUI.anchor) { StarUI.showEditBookmarkPopup(node, BookmarkingUI.anchor, - "bottomcenter topright"); + "bottomcenter topright", isNewBookmark); return; } let identityIcon = document.getElementById("identity-icon"); if (isElementVisible(identityIcon)) { StarUI.showEditBookmarkPopup(node, identityIcon, - "bottomcenter topright"); + "bottomcenter topright", isNewBookmark); } else { - StarUI.showEditBookmarkPopup(node, aBrowser, "overlap"); + StarUI.showEditBookmarkPopup(node, aBrowser, "overlap", isNewBookmark); } }), @@ -1703,19 +1726,15 @@ var BookmarkingUI = { let widget = CustomizableUI.getWidget(this.BOOKMARK_BUTTON_ID) .forWindow(window); if (widget.overflowed) { - // Allow to close the panel if the page is already bookmarked, cause - // we are going to open the edit bookmark panel. - if (isBookmarked) - widget.node.removeAttribute("closemenu"); - else - widget.node.setAttribute("closemenu", "none"); + // Close the overflow panel because the Edit Bookmark panel will appear. + widget.node.removeAttribute("closemenu"); } // Ignore clicks on the star if we are updating its state. if (!this._pendingStmt) { if (!isBookmarked) this._showBookmarkedNotification(); - PlacesCommandHook.bookmarkCurrentPage(isBookmarked); + PlacesCommandHook.bookmarkCurrentPage(true); } }, diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 0cb5c50d94d..beac6087d79 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -180,12 +180,6 @@