mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b-i
This commit is contained in:
commit
76de2fbfd9
2
CLOBBER
2
CLOBBER
@ -18,4 +18,4 @@
|
||||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
|
||||
Bug 915002 - Clobber needed for webidl updates for AppNotificationServiceOptions. One more time.
|
||||
Bug 872934 - Clobber needed for webidl updates for style sheet change events. Again and again.
|
@ -243,5 +243,8 @@ ifdef MOZ_PSEUDO_DERECURSE
|
||||
js/xpconnect/src/export: dom/bindings/export
|
||||
accessible/src/xpcom/export: xpcom/xpidl/export
|
||||
js/src/export: mfbt/export
|
||||
ifdef ENABLE_CLANG_PLUGIN
|
||||
js/src/export config/export: build/clang-plugin/export
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -11,8 +11,9 @@ const Cr = Components.results;
|
||||
|
||||
const INCLUDE_DESC = 0x01;
|
||||
const INCLUDE_NAME = 0x02;
|
||||
const INCLUDE_CUSTOM = 0x04;
|
||||
const NAME_FROM_SUBTREE_RULE = 0x08;
|
||||
const INCLUDE_VALUE = 0x04;
|
||||
const INCLUDE_CUSTOM = 0x08;
|
||||
const NAME_FROM_SUBTREE_RULE = 0x10;
|
||||
|
||||
const OUTPUT_DESC_FIRST = 0;
|
||||
const OUTPUT_DESC_LAST = 1;
|
||||
@ -64,8 +65,9 @@ this.OutputGenerator = {
|
||||
let nameRule = self.roleRuleMap[roleString] || 0;
|
||||
// Ignore subtree if the name is explicit and the role's name rule is the
|
||||
// NAME_FROM_SUBTREE_RULE.
|
||||
return (nameRule & NAME_FROM_SUBTREE_RULE) &&
|
||||
(Utils.getAttributes(aAccessible)['explicit-name'] === 'true');
|
||||
return (((nameRule & INCLUDE_VALUE) && aAccessible.value) ||
|
||||
((nameRule & NAME_FROM_SUBTREE_RULE) &&
|
||||
Utils.getAttributes(aAccessible)['explicit-name'] === 'true'));
|
||||
};
|
||||
|
||||
let contextStart = this._getContextStart(aContext);
|
||||
@ -256,9 +258,9 @@ this.OutputGenerator = {
|
||||
'buttondropdown': NAME_FROM_SUBTREE_RULE,
|
||||
'combobox': INCLUDE_DESC,
|
||||
'droplist': INCLUDE_DESC,
|
||||
'progressbar': INCLUDE_DESC,
|
||||
'slider': INCLUDE_DESC,
|
||||
'spinbutton': INCLUDE_DESC,
|
||||
'progressbar': INCLUDE_DESC | INCLUDE_VALUE,
|
||||
'slider': INCLUDE_DESC | INCLUDE_VALUE,
|
||||
'spinbutton': INCLUDE_DESC | INCLUDE_VALUE,
|
||||
'diagram': INCLUDE_DESC,
|
||||
'animation': INCLUDE_DESC,
|
||||
'equation': INCLUDE_DESC,
|
||||
@ -278,7 +280,7 @@ this.OutputGenerator = {
|
||||
'parent menuitem': NAME_FROM_SUBTREE_RULE,
|
||||
'header': INCLUDE_DESC,
|
||||
'footer': INCLUDE_DESC,
|
||||
'entry': INCLUDE_DESC | INCLUDE_NAME,
|
||||
'entry': INCLUDE_DESC | INCLUDE_NAME | INCLUDE_VALUE,
|
||||
'caption': INCLUDE_DESC,
|
||||
'document frame': INCLUDE_DESC,
|
||||
'heading': INCLUDE_DESC,
|
||||
@ -309,25 +311,36 @@ this.OutputGenerator = {
|
||||
output.push(desc.join(' '));
|
||||
}
|
||||
|
||||
if (aFlags & INCLUDE_VALUE) {
|
||||
let value = aAccessible.value;
|
||||
if (value) {
|
||||
output[this.outputOrder === OUTPUT_DESC_FIRST ?
|
||||
'push' : 'unshift'](value);
|
||||
}
|
||||
}
|
||||
|
||||
this._addName(output, aAccessible, aFlags);
|
||||
this._addLandmark(output, aAccessible);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
label: function label(aAccessible, aRoleStr, aStates, aFlags, aContext) {
|
||||
if (aContext.isNestedControl ||
|
||||
aContext.accessible == Utils.getEmbeddedControl(aAccessible)) {
|
||||
// If we are on a nested control, or a nesting label,
|
||||
// we don't need the context.
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.objectOutputFunctions.defaultFunc.apply(this, arguments);
|
||||
},
|
||||
|
||||
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let output = [];
|
||||
let desc = this._getLocalizedStates(aStates);
|
||||
desc.push(this._getLocalizedRole(
|
||||
(aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) ?
|
||||
'textarea' : 'entry'));
|
||||
|
||||
output.push(desc.join(' '));
|
||||
|
||||
this._addName(output, aAccessible, aFlags);
|
||||
this._addLandmark(output, aAccessible);
|
||||
|
||||
return output;
|
||||
let rolestr = (aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) ?
|
||||
'textarea' : 'entry';
|
||||
return this.objectOutputFunctions.defaultFunc.apply(
|
||||
this, [aAccessible, rolestr, aStates, aFlags]);
|
||||
},
|
||||
|
||||
pagetab: function pagetab(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
|
@ -163,20 +163,21 @@ VisualPresenter.prototype = {
|
||||
|
||||
pivotChanged: function VisualPresenter_pivotChanged(aContext, aReason) {
|
||||
this._displayedAccessibles.set(aContext.accessible.document.window,
|
||||
{ accessible: aContext.accessible,
|
||||
{ accessible: aContext.accessibleForBounds,
|
||||
startOffset: aContext.startOffset,
|
||||
endOffset: aContext.endOffset });
|
||||
|
||||
if (!aContext.accessible)
|
||||
if (!aContext.accessibleForBounds)
|
||||
return {type: this.type, details: {method: 'hideBounds'}};
|
||||
|
||||
try {
|
||||
aContext.accessible.scrollTo(
|
||||
aContext.accessibleForBounds.scrollTo(
|
||||
Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
|
||||
|
||||
let bounds = (aContext.startOffset === -1 && aContext.endOffset === -1) ?
|
||||
aContext.bounds : Utils.getTextBounds(aContext.accessible,
|
||||
aContext.startOffset, aContext.endOffset);
|
||||
aContext.bounds : Utils.getTextBounds(aContext.accessibleForBounds,
|
||||
aContext.startOffset,
|
||||
aContext.endOffset);
|
||||
|
||||
return {
|
||||
type: this.type,
|
||||
|
@ -48,6 +48,7 @@ const ROLE_TABLE = Ci.nsIAccessibleRole.ROLE_TABLE;
|
||||
const ROLE_INTERNAL_FRAME = Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
||||
const ROLE_PARAGRAPH = Ci.nsIAccessibleRole.ROLE_PARAGRAPH;
|
||||
const ROLE_SECTION = Ci.nsIAccessibleRole.ROLE_SECTION;
|
||||
const ROLE_LABEL = Ci.nsIAccessibleRole.ROLE_LABEL;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['TraversalRules'];
|
||||
|
||||
@ -57,8 +58,12 @@ Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
|
||||
|
||||
function BaseTraversalRule(aRoles, aMatchFunc) {
|
||||
this._explicitMatchRoles = new Set(aRoles);
|
||||
this._matchRoles = aRoles;
|
||||
this._matchFunc = aMatchFunc;
|
||||
if (aRoles.indexOf(ROLE_LABEL) < 0) {
|
||||
this._matchRoles.push(ROLE_LABEL);
|
||||
}
|
||||
this._matchFunc = aMatchFunc || function (acc) { return FILTER_MATCH; };
|
||||
}
|
||||
|
||||
BaseTraversalRule.prototype = {
|
||||
@ -73,15 +78,25 @@ BaseTraversalRule.prototype = {
|
||||
|
||||
match: function BaseTraversalRule_match(aAccessible)
|
||||
{
|
||||
if (aAccessible.role == ROLE_INTERNAL_FRAME) {
|
||||
let role = aAccessible.role;
|
||||
if (role == ROLE_INTERNAL_FRAME) {
|
||||
return (Utils.getMessageManager(aAccessible.DOMNode)) ?
|
||||
FILTER_MATCH | FILTER_IGNORE_SUBTREE : FILTER_IGNORE;
|
||||
}
|
||||
|
||||
if (this._matchFunc)
|
||||
return this._matchFunc(aAccessible);
|
||||
let matchResult = this._explicitMatchRoles.has(role) ?
|
||||
this._matchFunc(aAccessible) : FILTER_IGNORE;
|
||||
|
||||
return FILTER_MATCH;
|
||||
// If we are on a label that nests a checkbox/radio we should land on it.
|
||||
// It is a bigger touch target, and it reduces clutter.
|
||||
if (role == ROLE_LABEL && !(matchResult & FILTER_IGNORE_SUBTREE)) {
|
||||
let control = Utils.getEmbeddedControl(aAccessible);
|
||||
if (control && this._explicitMatchRoles.has(control.role)) {
|
||||
matchResult = this._matchFunc(control) | FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
}
|
||||
|
||||
return matchResult;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
|
||||
|
@ -14,6 +14,8 @@ const ROLE_CELL = Ci.nsIAccessibleRole.ROLE_CELL;
|
||||
const ROLE_COLUMNHEADER = Ci.nsIAccessibleRole.ROLE_COLUMNHEADER;
|
||||
const ROLE_ROWHEADER = Ci.nsIAccessibleRole.ROLE_ROWHEADER;
|
||||
|
||||
const RELATION_LABEL_FOR = Ci.nsIAccessibleRelation.RELATION_LABEL_FOR;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
|
||||
'resource://gre/modules/Services.jsm');
|
||||
@ -291,6 +293,20 @@ this.Utils = {
|
||||
|
||||
// Looking up a role that would match a landmark.
|
||||
return this.matchAttributeValue(roles, landmarks);
|
||||
},
|
||||
|
||||
getEmbeddedControl: function getEmbeddedControl(aLabel) {
|
||||
if (aLabel) {
|
||||
let relation = aLabel.getRelationByType(RELATION_LABEL_FOR);
|
||||
for (let i = 0; i < relation.targetsCount; i++) {
|
||||
let target = relation.getTarget(i);
|
||||
if (target.parent === aLabel) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -425,11 +441,18 @@ this.Logger = {
|
||||
/**
|
||||
* PivotContext: An object that generates and caches context information
|
||||
* for a given accessible and its relationship with another accessible.
|
||||
*
|
||||
* If the given accessible is a label for a nested control, then this
|
||||
* context will represent the nested control instead of the label.
|
||||
* With the exception of bounds calculation, which will use the containing
|
||||
* label. In this case the |accessible| field would be the embedded control,
|
||||
* and the |accessibleForBounds| field would be the label.
|
||||
*/
|
||||
this.PivotContext = function PivotContext(aAccessible, aOldAccessible,
|
||||
aStartOffset, aEndOffset, aIgnoreAncestry = false,
|
||||
aIncludeInvisible = false) {
|
||||
this._accessible = aAccessible;
|
||||
this._nestedControl = Utils.getEmbeddedControl(aAccessible);
|
||||
this._oldAccessible =
|
||||
this._isDefunct(aOldAccessible) ? null : aOldAccessible;
|
||||
this.startOffset = aStartOffset;
|
||||
@ -440,13 +463,23 @@ this.PivotContext = function PivotContext(aAccessible, aOldAccessible,
|
||||
|
||||
PivotContext.prototype = {
|
||||
get accessible() {
|
||||
return this._accessible;
|
||||
// If the current pivot accessible has a nested control,
|
||||
// make this context use it publicly.
|
||||
return this._nestedControl || this._accessible;
|
||||
},
|
||||
|
||||
get oldAccessible() {
|
||||
return this._oldAccessible;
|
||||
},
|
||||
|
||||
get isNestedControl() {
|
||||
return !!this._nestedControl;
|
||||
},
|
||||
|
||||
get accessibleForBounds() {
|
||||
return this._accessible;
|
||||
},
|
||||
|
||||
get textAndAdjustedOffsets() {
|
||||
if (this.startOffset === -1 && this.endOffset === -1) {
|
||||
return null;
|
||||
@ -521,7 +554,7 @@ PivotContext.prototype = {
|
||||
get currentAncestry() {
|
||||
if (!this._currentAncestry) {
|
||||
this._currentAncestry = this._ignoreAncestry ? [] :
|
||||
this._getAncestry(this._accessible);
|
||||
this._getAncestry(this.accessible);
|
||||
}
|
||||
return this._currentAncestry;
|
||||
},
|
||||
@ -582,7 +615,7 @@ PivotContext.prototype = {
|
||||
* traversal should stop.
|
||||
*/
|
||||
subtreeGenerator: function subtreeGenerator(aPreorder, aStop) {
|
||||
return this._traverse(this._accessible, aPreorder, aStop);
|
||||
return this._traverse(this.accessible, aPreorder, aStop);
|
||||
},
|
||||
|
||||
getCellInfo: function getCellInfo(aAccessible) {
|
||||
@ -677,7 +710,7 @@ PivotContext.prototype = {
|
||||
|
||||
get bounds() {
|
||||
if (!this._bounds) {
|
||||
this._bounds = Utils.getBounds(this._accessible);
|
||||
this._bounds = Utils.getBounds(this.accessibleForBounds);
|
||||
}
|
||||
|
||||
return this._bounds.clone();
|
||||
|
@ -173,6 +173,11 @@ function activateCurrent(aMessage) {
|
||||
if (aAccessible.actionCount > 0) {
|
||||
aAccessible.doAction(0);
|
||||
} else {
|
||||
let control = Utils.getEmbeddedControl(aAccessible);
|
||||
if (control && control.actionCount > 0) {
|
||||
control.doAction(0);
|
||||
}
|
||||
|
||||
// XXX Some mobile widget sets do not expose actions properly
|
||||
// (via ARIA roles, etc.), so we need to generate a click.
|
||||
// Could possibly be made simpler in the future. Maybe core
|
||||
|
@ -25,7 +25,9 @@ function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator
|
||||
var output = aGenerator.genForContext(context).output;
|
||||
|
||||
isDeeply(output, expected,
|
||||
"Context output is correct for " + aAccOrElmOrID);
|
||||
"Context output is correct for " + aAccOrElmOrID +
|
||||
" (output: " + output.join(", ") + ") ==" +
|
||||
" (expected: " + expected.join(", ") + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,6 +56,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=876475
|
||||
},{
|
||||
accOrElmOrID: "textarea",
|
||||
expected: [["txtarea", "Here lies treasure."], ["Here lies treasure.", "txtarea"]]
|
||||
},{
|
||||
accOrElmOrID: "textentry",
|
||||
expected: [["entry", "Mario", "First name:"], ["First name:", "Mario", "entry"]]
|
||||
},{
|
||||
accOrElmOrID: "range",
|
||||
expected: [["slider", "3", "Points:"], ["Points:", "3", "slider"]]
|
||||
}];
|
||||
|
||||
// Test all possible braille order preference values.
|
||||
@ -109,6 +115,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=876475
|
||||
<textarea id="textarea" cols="80" rows="5">
|
||||
Here lies treasure.
|
||||
</textarea>
|
||||
<label>First name: <input id="textentry" value="Mario"></label>
|
||||
<label>Points: <input id="range" type="range" name="points" min="1" max="10" value="3"></label>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -28,7 +28,7 @@
|
||||
expected: ["button", "Press me"]
|
||||
}, {
|
||||
accOrElmOrID: "textarea1",
|
||||
expected: ["text area", "Test Text Area", "This is the text area text."]
|
||||
expected: ["text area", "This is the text area text.", "Test Text Area"]
|
||||
}, {
|
||||
accOrElmOrID: "textarea2",
|
||||
expected: ["text area", "This is the text area text."]
|
||||
|
@ -139,6 +139,56 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
||||
accOrElmOrID: 'tab2',
|
||||
expected: [['tab list', 'tab 2 of 2', 'Advanced'],
|
||||
['Advanced', 'tab 2 of 2', 'tab list']]
|
||||
},
|
||||
|
||||
{
|
||||
// Landing on this label should mimic landing on the checkbox.
|
||||
accOrElmOrID: "label1",
|
||||
expected: [['not checked check button', 'Orange'],
|
||||
['Orange', 'not checked check button']]
|
||||
},
|
||||
{
|
||||
// Here we get a top-level view of the form.
|
||||
accOrElmOrID: "form1",
|
||||
expected: [['label', 'not checked check button', 'Orange', 'Orange',
|
||||
'not checked check button', 'Blue', 'label', 'Blue'],
|
||||
['Orange', 'not checked check button', 'Orange', 'label',
|
||||
'Blue', 'not checked check button', 'Blue', 'label']]
|
||||
},
|
||||
{
|
||||
// This is a non-nesting label.
|
||||
accOrElmOrID: "label2",
|
||||
expected: [['label', 'Blue'], ['Blue', 'label']]
|
||||
},
|
||||
{
|
||||
// This is a distinct control.
|
||||
accOrElmOrID: "input2",
|
||||
expected: [['not checked check button', 'Blue'],
|
||||
['Blue', 'not checked check button']]
|
||||
},
|
||||
{
|
||||
// This is a nested control.
|
||||
accOrElmOrID: "input1",
|
||||
expected: [['not checked check button', 'Orange'],
|
||||
['Orange', 'not checked check button']]
|
||||
},
|
||||
{
|
||||
// Landing on this label should mimic landing on the entry.
|
||||
accOrElmOrID: "label3",
|
||||
expected: [['entry', 'Joe', 'First name:'],
|
||||
['First name:', 'Joe', 'entry']]
|
||||
},
|
||||
{
|
||||
// This is a nested control with a value.
|
||||
accOrElmOrID: "input3",
|
||||
expected: [['entry', 'Joe', 'First name:'],
|
||||
['First name:', 'Joe', 'entry']]
|
||||
},
|
||||
{
|
||||
// This is a nested control with a value.
|
||||
accOrElmOrID: "input4",
|
||||
expected: [['slider', '3', 'Points:'],
|
||||
['Points:', '3', 'slider']]
|
||||
}];
|
||||
|
||||
// Test all possible utterance order preference values.
|
||||
@ -218,6 +268,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
||||
<a id="tab1" href="#" role="tab" aria-selected="true">Account</a>
|
||||
<a id="tab2" href="#" role="tab" aria-selected="false">Advanced</a>
|
||||
</div>
|
||||
<form id="form1">
|
||||
<label id="label1"><input id="input1" type="checkbox">Orange</label>
|
||||
<input id="input2" type="checkbox"><label id="label2" for="input2">Blue</label>
|
||||
</form>
|
||||
<label id="label3">First name: <input id="input3" value="Joe"></label>
|
||||
<label id="label4">Points:
|
||||
<input id="input4" type="range" name="points" min="1" max="10" value="3">
|
||||
</label>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
export PYMAKE = $(.PYMAKE)
|
||||
|
||||
libs::
|
||||
$(PYTHON) $(srcdir)/copy_source.py $(topsrcdir) $(srcdir)/source/lib $(FINAL_TARGET)/modules/commonjs >copy_source.mk
|
||||
$(MAKE) -f copy_source.mk libs
|
||||
|
@ -3,31 +3,14 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
|
||||
|
||||
def normpath(path):
|
||||
"""Ensure UNIX style paths are used with GNU make on Windows.
|
||||
|
||||
This can be removed once we no longer support GNU make on Windows (bug
|
||||
828317).
|
||||
"""
|
||||
if os.environ.get('PYMAKE') or os.name not in ('nt', 'ce'):
|
||||
return path
|
||||
|
||||
if len(path) > 2 and path[1] == ':':
|
||||
path = '/' + path[0] + path[2:]
|
||||
|
||||
return posixpath.normpath(path)
|
||||
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print >> sys.stderr, "Usage: copy_source.py " \
|
||||
"<topsrcdir> <source directory> <target directory>"
|
||||
sys.exit(1)
|
||||
|
||||
topsrcdir = normpath(sys.argv[1])
|
||||
topsrcdir = sys.argv[1]
|
||||
source_dir = sys.argv[2]
|
||||
target_dir = sys.argv[3]
|
||||
|
||||
|
@ -4137,7 +4137,7 @@
|
||||
* close many tabs at once.
|
||||
*/
|
||||
let target = event.originalTarget;
|
||||
if (target.className == 'tab-close-button') {
|
||||
if (target.classList.contains('tab-close-button')) {
|
||||
// We preemptively set this to allow the closing-multiple-tabs-
|
||||
// in-a-row case.
|
||||
if (this._blockDblClick) {
|
||||
|
@ -1143,7 +1143,7 @@ SourceScripts.prototype = {
|
||||
if (item) {
|
||||
DebuggerView.Sources.callMethod("checkItem", item.target, !isBlackBoxed);
|
||||
}
|
||||
DebuggerView.Sources.maybeShowBlackBoxMessage();
|
||||
DebuggerView.maybeShowBlackBoxMessage();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1153,17 +1153,27 @@ SourceScripts.prototype = {
|
||||
* The source form.
|
||||
* @param bool aBlackBoxFlag
|
||||
* True to black box the source, false to un-black box it.
|
||||
* @returns Promise
|
||||
* A promize that resolves to [aSource, isBlackBoxed] or rejects to
|
||||
* [aSource, error].
|
||||
*/
|
||||
blackBox: function(aSource, aBlackBoxFlag) {
|
||||
const sourceClient = this.activeThread.source(aSource);
|
||||
sourceClient[aBlackBoxFlag ? "blackBox" : "unblackBox"](({ error, message }) => {
|
||||
const deferred = promise.defer();
|
||||
|
||||
sourceClient[aBlackBoxFlag ? "blackBox" : "unblackBox"](aPacket => {
|
||||
const { error, message } = aPacket;
|
||||
if (error) {
|
||||
let msg = "Couldn't toggle black boxing for " + aSource.url + ": " + message;
|
||||
dumpn(msg);
|
||||
Cu.reportError(msg);
|
||||
return;
|
||||
deferred.reject([aSource, msg]);
|
||||
} else {
|
||||
deferred.resolve([aSource, sourceClient.isBlackBoxed]);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -50,7 +50,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
this._cmPopup = document.getElementById("sourceEditorContextMenu");
|
||||
this._cbPanel = document.getElementById("conditional-breakpoint-panel");
|
||||
this._cbTextbox = document.getElementById("conditional-breakpoint-panel-textbox");
|
||||
this._editorDeck = document.getElementById("editor-deck");
|
||||
this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
|
||||
this._prettyPrintButton = document.getElementById("pretty-print");
|
||||
|
||||
@ -383,6 +382,10 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
* Pretty print the selected source.
|
||||
*/
|
||||
prettyPrint: function() {
|
||||
if (this._prettyPrintButton.hasAttribute("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resetEditor = ([{ url }]) => {
|
||||
// Only set the text when the source is still selected.
|
||||
if (url == this.selectedValue) {
|
||||
@ -397,9 +400,11 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
return;
|
||||
}
|
||||
|
||||
let { source } = this.selectedItem.attachment;
|
||||
let prettyPrinted = DebuggerController.SourceScripts.prettyPrint(source);
|
||||
prettyPrinted.then(resetEditor, printError);
|
||||
DebuggerView.showProgressBar();
|
||||
const { source } = this.selectedItem.attachment;
|
||||
DebuggerController.SourceScripts.prettyPrint(source)
|
||||
.then(resetEditor, printError)
|
||||
.then(DebuggerView.showEditor);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -690,17 +695,21 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
let script = sourceItem.value.split(" -> ").pop();
|
||||
document.title = L10N.getFormatStr("DebuggerWindowScriptTitle", script);
|
||||
|
||||
this.maybeShowBlackBoxMessage();
|
||||
DebuggerView.maybeShowBlackBoxMessage();
|
||||
this._updatePrettyPrintButtonState();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide the black box message vs. source editor depending on if the
|
||||
* selected source is black boxed or not.
|
||||
* Enable or disable the pretty print button depending on whether the selected
|
||||
* source is black boxed or not.
|
||||
*/
|
||||
maybeShowBlackBoxMessage: function() {
|
||||
let sourceForm = this.selectedItem.attachment.source;
|
||||
let sourceClient = DebuggerController.activeThread.source(sourceForm);
|
||||
this._editorDeck.selectedIndex = sourceClient.isBlackBoxed ? 1 : 0;
|
||||
_updatePrettyPrintButtonState: function() {
|
||||
const { source } = this.selectedItem.attachment;
|
||||
if (gThreadClient.source(source).isBlackBoxed) {
|
||||
this._prettyPrintButton.setAttribute("disabled", true);
|
||||
} else {
|
||||
this._prettyPrintButton.removeAttribute("disabled");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -715,8 +724,23 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
* The check listener for the sources container.
|
||||
*/
|
||||
_onSourceCheck: function({ detail: { checked }, target }) {
|
||||
let item = this.getItemForElement(target);
|
||||
DebuggerController.SourceScripts.blackBox(item.attachment.source, !checked);
|
||||
const shouldBlackBox = !checked;
|
||||
|
||||
// Be optimistic that the (un-)black boxing will succeed and enable/disable
|
||||
// the pretty print button immediately. Then, once we actually get the
|
||||
// results from the server, make sure that it is in the correct state again
|
||||
// by calling `_updatePrettyPrintButtonState`.
|
||||
|
||||
if (shouldBlackBox) {
|
||||
this._prettyPrintButton.setAttribute("disabled", true);
|
||||
} else {
|
||||
this._prettyPrintButton.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
const { source } = this.getItemForElement(target).attachment;
|
||||
DebuggerController.SourceScripts.blackBox(source, shouldBlackBox)
|
||||
.then(this._updatePrettyPrintButtonState,
|
||||
this._updatePrettyPrintButtonState);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -114,6 +114,12 @@ let DebuggerView = {
|
||||
this._instrumentsPane = document.getElementById("instruments-pane");
|
||||
this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
|
||||
|
||||
this.showEditor = this.showEditor.bind(this);
|
||||
this.showBlackBoxMessage = this.showBlackBoxMessage.bind(this);
|
||||
this.showProgressBar = this.showProgressBar.bind(this);
|
||||
this.maybeShowBlackBoxMessage = this.maybeShowBlackBoxMessage.bind(this);
|
||||
this._editorDeck = document.getElementById("editor-deck");
|
||||
|
||||
this._onTabSelect = this._onInstrumentsPaneTabSelect.bind(this);
|
||||
this._instrumentsPane.tabpanels.addEventListener("select", this._onTabSelect);
|
||||
|
||||
@ -221,6 +227,40 @@ let DebuggerView = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the source editor.
|
||||
*/
|
||||
showEditor: function() {
|
||||
this._editorDeck.selectedIndex = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the black box message.
|
||||
*/
|
||||
showBlackBoxMessage: function() {
|
||||
this._editorDeck.selectedIndex = 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the progress bar.
|
||||
*/
|
||||
showProgressBar: function() {
|
||||
this._editorDeck.selectedIndex = 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show or hide the black box message vs. source editor depending on if the
|
||||
* selected source is black boxed or not.
|
||||
*/
|
||||
maybeShowBlackBoxMessage: function() {
|
||||
let { source } = DebuggerView.Sources.selectedItem.attachment;
|
||||
if (gThreadClient.source(source).isBlackBoxed) {
|
||||
this.showBlackBoxMessage();
|
||||
} else {
|
||||
this.showEditor();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the currently displayed text contents in the source editor.
|
||||
* This resets the mode and undo stack.
|
||||
@ -522,6 +562,7 @@ let DebuggerView = {
|
||||
_instrumentsPaneToggleButton: null,
|
||||
_collapsePaneString: "",
|
||||
_expandPaneString: "",
|
||||
_editorDeck: null,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -345,6 +345,10 @@
|
||||
image="chrome://browser/skin/devtools/blackBoxMessageEye.png"
|
||||
command="unBlackBoxCommand"/>
|
||||
</vbox>
|
||||
<vbox id="source-progress-container" align="center" pack="center">
|
||||
<progressmeter id="source-progress"
|
||||
mode="undetermined"/>
|
||||
</vbox>
|
||||
</deck>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<tabbox id="instruments-pane"
|
||||
|
@ -122,6 +122,7 @@ support-files =
|
||||
[browser_dbg_pretty-print-07.js]
|
||||
[browser_dbg_pretty-print-08.js]
|
||||
[browser_dbg_pretty-print-09.js]
|
||||
[browser_dbg_pretty-print-10.js]
|
||||
[browser_dbg_progress-listener-bug.js]
|
||||
[browser_dbg_reload-preferred-script-01.js]
|
||||
[browser_dbg_reload-preferred-script-02.js]
|
||||
|
@ -24,9 +24,11 @@ function test() {
|
||||
.then(() => {
|
||||
const finished = waitForSourceShown(gPanel, "code_ugly.js");
|
||||
clickPrettyPrintButton();
|
||||
testProgressBarShown();
|
||||
return finished;
|
||||
})
|
||||
.then(testSourceIsPretty)
|
||||
.then(testEditorShown)
|
||||
.then(testSourceIsStillPretty)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
@ -46,11 +48,21 @@ function clickPrettyPrintButton() {
|
||||
gDebugger);
|
||||
}
|
||||
|
||||
function testProgressBarShown() {
|
||||
const deck = gDebugger.document.getElementById("editor-deck");
|
||||
is(deck.selectedIndex, 2, "The progress bar should be shown");
|
||||
}
|
||||
|
||||
function testSourceIsPretty() {
|
||||
ok(gEditor.getText().contains("\n "),
|
||||
"The source should be pretty printed.")
|
||||
}
|
||||
|
||||
function testEditorShown() {
|
||||
const deck = gDebugger.document.getElementById("editor-deck");
|
||||
is(deck.selectedIndex, 0, "The editor should be shown");
|
||||
}
|
||||
|
||||
function testSourceIsStillPretty() {
|
||||
const deferred = promise.defer();
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that we disable the pretty print button for black boxed sources,
|
||||
* and that clicking it doesn't do anything.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gEditor, gSources;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gEditor = gDebugger.DebuggerView.editor;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
|
||||
waitForSourceShown(gPanel, "code_ugly.js")
|
||||
.then(testSourceIsUgly)
|
||||
.then(blackBoxSource)
|
||||
.then(waitForThreadEvents.bind(null, gPanel, "blackboxchange"))
|
||||
.then(clickPrettyPrintButton)
|
||||
.then(testSourceIsStillUgly)
|
||||
.then(() => closeDebuggerAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSourceIsUgly() {
|
||||
ok(!gEditor.getText().contains("\n "),
|
||||
"The source shouldn't be pretty printed yet.");
|
||||
}
|
||||
|
||||
function blackBoxSource() {
|
||||
const checkbox = gDebugger.document.querySelector(
|
||||
".selected .side-menu-widget-item-checkbox");
|
||||
checkbox.click();
|
||||
}
|
||||
|
||||
function clickPrettyPrintButton() {
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
gDebugger.document.getElementById("pretty-print"),
|
||||
gDebugger);
|
||||
}
|
||||
|
||||
function testSourceIsStillUgly() {
|
||||
const { source } = gSources.selectedItem.attachment;
|
||||
return gDebugger.DebuggerController.SourceScripts.getText(source).then(([, text]) => {
|
||||
ok(!text.contains("\n "));
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gSources = null;
|
||||
});
|
@ -30,4 +30,5 @@ support-files =
|
||||
[browser_bug731721_debugger_stepping.js]
|
||||
[browser_bug744021_next_prev_bracket_jump.js]
|
||||
[browser_codemirror.js]
|
||||
skip-if = os == "linux"
|
||||
[browser_sourceeditor_initialization.js]
|
||||
|
@ -26,6 +26,10 @@
|
||||
|
||||
<field name="controller">null</field>
|
||||
|
||||
<!-- collection of child items excluding empty tiles -->
|
||||
<property name="items" readonly="true" onget="return this.querySelectorAll('richgriditem');"/>
|
||||
<property name="itemCount" readonly="true" onget="return this.items.length;"/>
|
||||
|
||||
<!-- nsIDOMXULMultiSelectControlElement (not fully implemented) -->
|
||||
|
||||
<method name="clearSelection">
|
||||
@ -158,8 +162,6 @@
|
||||
|
||||
<!-- nsIDOMXULSelectControlElement -->
|
||||
|
||||
<property name="itemCount" readonly="true" onget="return this.children.length;"/>
|
||||
|
||||
<field name="_selectedItem">null</field>
|
||||
<property name="selectedItem" onget="return this._selectedItem;">
|
||||
<setter>
|
||||
@ -202,7 +204,7 @@
|
||||
<parameter name="aSkipArrange"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let addition = this.createItemElement(aLabel, aValue);
|
||||
let addition = this._createItemElement(aLabel, aValue);
|
||||
this.appendChild(addition);
|
||||
if (!aSkipArrange)
|
||||
this.arrangeItems();
|
||||
@ -232,7 +234,7 @@
|
||||
<body>
|
||||
<![CDATA[
|
||||
let existing = this.getItemAtIndex(anIndex);
|
||||
let addition = this.createItemElement(aLabel, aValue);
|
||||
let addition = this._createItemElement(aLabel, aValue);
|
||||
if (existing) {
|
||||
this.insertBefore(addition, existing);
|
||||
} else {
|
||||
@ -250,7 +252,9 @@
|
||||
<body>
|
||||
<![CDATA[
|
||||
let item = this.getItemAtIndex(anIndex);
|
||||
return item ? this.removeItem(item, aSkipArrange) : null;
|
||||
if (!item)
|
||||
return null;
|
||||
return this.removeItem(item, aSkipArrange);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@ -260,7 +264,9 @@
|
||||
<parameter name="aSkipArrange"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let removal = aItem.parentNode == this && this.removeChild(aItem);
|
||||
if (!aItem || Array.indexOf(this.items, aItem) < 0)
|
||||
return null;
|
||||
let removal = this.removeChild(aItem);
|
||||
if (removal && !aSkipArrange)
|
||||
this.arrangeItems();
|
||||
|
||||
@ -271,7 +277,6 @@
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="getIndexOfItem">
|
||||
<parameter name="anItem"/>
|
||||
<body>
|
||||
@ -279,7 +284,7 @@
|
||||
if (!anItem)
|
||||
return -1;
|
||||
|
||||
return Array.indexOf(this.children, anItem);
|
||||
return Array.indexOf(this.items, anItem);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@ -290,7 +295,7 @@
|
||||
<![CDATA[
|
||||
if (!this._isIndexInBounds(anIndex))
|
||||
return null;
|
||||
return this.children.item(anIndex);
|
||||
return this.items.item(anIndex);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@ -609,16 +614,18 @@
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="createItemElement">
|
||||
<method name="_createItemElement">
|
||||
<parameter name="aLabel"/>
|
||||
<parameter name="aValue"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let item = this.ownerDocument.createElement("richgriditem");
|
||||
item.setAttribute("label", aLabel);
|
||||
if (aValue) {
|
||||
item.setAttribute("value", aValue);
|
||||
}
|
||||
if (aLabel) {
|
||||
item.setAttribute("label", aLabel);
|
||||
}
|
||||
if(this.hasAttribute("tiletype")) {
|
||||
item.setAttribute("tiletype", this.getAttribute("tiletype"));
|
||||
}
|
||||
@ -860,7 +867,7 @@
|
||||
<property name="control">
|
||||
<getter><![CDATA[
|
||||
let parent = this.parentNode;
|
||||
while (parent) {
|
||||
while (parent && parent != this.ownerDocument.documentElement) {
|
||||
if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement)
|
||||
return parent;
|
||||
parent = parent.parentNode;
|
||||
|
@ -100,7 +100,7 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
case "pin":
|
||||
let pinIndices = [];
|
||||
Array.forEach(selectedTiles, function(aNode) {
|
||||
pinIndices.push( Array.indexOf(aNode.control.children, aNode) );
|
||||
pinIndices.push( Array.indexOf(aNode.control.items, aNode) );
|
||||
aNode.contextActions.delete('pin');
|
||||
aNode.contextActions.add('unpin');
|
||||
});
|
||||
@ -153,7 +153,6 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
// flush, recreate all
|
||||
this.isUpdating = true;
|
||||
// destroy and recreate all item nodes, skip calling arrangeItems
|
||||
grid.clearAll(true);
|
||||
this.populateGrid();
|
||||
}
|
||||
},
|
||||
@ -165,14 +164,18 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
let filepath = PageThumbsStorage.getFilePathForURL(aSite.url);
|
||||
if (yield OS.File.exists(filepath)) {
|
||||
aSite.backgroundImage = 'url("'+PageThumbs.getThumbnailURL(aSite.url)+'")';
|
||||
aTileNode.setAttribute("customImage", aSite.backgroundImage);
|
||||
if (aTileNode.refresh) {
|
||||
aTileNode.refresh()
|
||||
if ('backgroundImage' in aTileNode) {
|
||||
aTileNode.backgroundImage = aSite.backgroundImage;
|
||||
} else {
|
||||
aTileNode.setAttribute("customImage", aSite.backgroundImage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
aSite.applyToTileNode(aTileNode);
|
||||
if (aTileNode.refresh) {
|
||||
aTileNode.refresh();
|
||||
}
|
||||
if (aArrangeGrid) {
|
||||
this._set.arrangeItems();
|
||||
}
|
||||
@ -182,24 +185,19 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
this.isUpdating = true;
|
||||
|
||||
let sites = TopSites.getSites();
|
||||
let length = Math.min(sites.length, this._topSitesMax || Infinity);
|
||||
let tileset = this._set;
|
||||
|
||||
// if we're updating with a collection that is smaller than previous
|
||||
// remove any extra tiles
|
||||
while (tileset.children.length > length) {
|
||||
tileset.removeChild(tileset.children[tileset.children.length -1]);
|
||||
if (this._topSitesMax) {
|
||||
sites = sites.slice(0, this._topSitesMax);
|
||||
}
|
||||
let tileset = this._set;
|
||||
tileset.clearAll(true);
|
||||
|
||||
for (let idx=0; idx < length; idx++) {
|
||||
let isNew = !tileset.children[idx],
|
||||
site = sites[idx];
|
||||
let item = isNew ? tileset.createItemElement(site.title, site.url) : tileset.children[idx];
|
||||
for (let site of sites) {
|
||||
// call to private _createItemElement is a temp measure
|
||||
// we'll eventually just request the next slot
|
||||
let item = tileset._createItemElement(site.title, site.url);
|
||||
|
||||
this.updateTile(item, site);
|
||||
if (isNew) {
|
||||
tileset.appendChild(item);
|
||||
}
|
||||
tileset.appendChild(item);
|
||||
}
|
||||
tileset.arrangeItems();
|
||||
this.isUpdating = false;
|
||||
|
@ -18,8 +18,8 @@ gTests.push({
|
||||
ok(grid, "#grid1 is found");
|
||||
is(typeof grid.clearSelection, "function", "#grid1 has the binding applied");
|
||||
|
||||
is(grid.children.length, 2, "#grid1 has a 2 items");
|
||||
is(grid.children[0].control, grid, "#grid1 item's control points back at #grid1'");
|
||||
is(grid.items.length, 2, "#grid1 has a 2 items");
|
||||
is(grid.items[0].control, grid, "#grid1 item's control points back at #grid1'");
|
||||
}
|
||||
});
|
||||
|
||||
@ -29,7 +29,7 @@ gTests.push({
|
||||
let grid = doc.querySelector("#grid1");
|
||||
is(typeof grid.handleItemClick, "function", "grid.handleItemClick is a function");
|
||||
let handleStub = stubMethod(grid, 'handleItemClick');
|
||||
let itemId = "grid1_item1"; // grid.children[0].getAttribute("id");
|
||||
let itemId = "grid1_item1"; // grid.items[0].getAttribute("id");
|
||||
|
||||
// send click to item and wait for next tick;
|
||||
EventUtils.sendMouseEvent({type: 'click'}, itemId, doc.defaultView);
|
||||
@ -114,9 +114,8 @@ gTests.push({
|
||||
grid.clearAll();
|
||||
|
||||
is(grid.itemCount, 0, "grid has 0 itemCount after clearAll");
|
||||
is(grid.children.length, 0, "grid has 0 children after clearAll");
|
||||
is(grid.rowCount, 0, "grid has 0 rows when empty");
|
||||
is(grid.columnCount, 0, "grid has 0 cols when empty");
|
||||
is(grid.items.length, 0, "grid has 0 items after clearAll");
|
||||
// now that we use slots, an empty grid may still have non-zero rows & columns
|
||||
|
||||
is(arrangeSpy.callCount, 1, "arrangeItems is called once when we clearAll");
|
||||
arrangeSpy.restore();
|
||||
@ -150,13 +149,13 @@ gTests.push({
|
||||
let grid = doc.querySelector("#emptygrid");
|
||||
|
||||
is(grid.itemCount, 0, "0 itemCount when empty");
|
||||
is(grid.children.length, 0, "0 children when empty");
|
||||
is(grid.items.length, 0, "0 items when empty");
|
||||
is(typeof grid.appendItem, "function", "appendItem is a function on the grid");
|
||||
|
||||
let arrangeStub = stubMethod(grid, "arrangeItems");
|
||||
let newItem = grid.appendItem("test title", "about:blank");
|
||||
|
||||
ok(newItem && grid.children[0]==newItem, "appendItem gives back the item");
|
||||
ok(newItem && grid.items[0]==newItem, "appendItem gives back the item");
|
||||
is(grid.itemCount, 1, "itemCount is incremented when we appendItem");
|
||||
is(newItem.getAttribute("label"), "test title", "title ends up on label attribute");
|
||||
is(newItem.getAttribute("value"), "about:blank", "url ends up on value attribute");
|
||||
@ -193,7 +192,7 @@ gTests.push({
|
||||
|
||||
ok(removedItem, "removeItemAt gives back an item");
|
||||
is(removedItem.getAttribute("id"), "grid2_item1", "removeItemAt gives back the correct item");
|
||||
is(grid.children[0].getAttribute("id"), "grid2_item2", "2nd item becomes the first item");
|
||||
is(grid.items[0].getAttribute("id"), "grid2_item2", "2nd item becomes the first item");
|
||||
is(grid.itemCount, 1, "itemCount is decremented when we removeItemAt");
|
||||
|
||||
is(arrangeStub.callCount, 1, "arrangeItems is called when we removeItemAt");
|
||||
@ -215,10 +214,10 @@ gTests.push({
|
||||
let insertedItem = grid.insertItemAt(1, "inserted item", "http://example.com/inserted");
|
||||
|
||||
ok(insertedItem, "insertItemAt gives back an item");
|
||||
is(grid.children[1], insertedItem, "item is inserted at the correct index");
|
||||
is(grid.items[1], insertedItem, "item is inserted at the correct index");
|
||||
is(insertedItem.getAttribute("label"), "inserted item", "insertItemAt creates item with the correct label");
|
||||
is(insertedItem.getAttribute("value"), "http://example.com/inserted", "insertItemAt creates item with the correct url value");
|
||||
is(grid.children[2].getAttribute("id"), "grid3_item2", "following item ends up at the correct index");
|
||||
is(grid.items[2].getAttribute("id"), "grid3_item2", "following item ends up at the correct index");
|
||||
is(grid.itemCount, 3, "itemCount is incremented when we insertItemAt");
|
||||
|
||||
is(arrangeStub.callCount, 1, "arrangeItems is called when we insertItemAt");
|
||||
@ -275,11 +274,11 @@ gTests.push({
|
||||
is(typeof grid.removeItem, "function", "removeItem is a function on the grid");
|
||||
|
||||
let arrangeStub = stubMethod(grid, "arrangeItems");
|
||||
let removedFirst = grid.removeItem( grid.children[0] );
|
||||
let removedFirst = grid.removeItem( grid.items[0] );
|
||||
|
||||
is(arrangeStub.callCount, 1, "arrangeItems is called when we removeItem");
|
||||
|
||||
let removed2nd = grid.removeItem( grid.children[0], true);
|
||||
let removed2nd = grid.removeItem( grid.items[0], true);
|
||||
is(removed2nd.getAttribute("label"), "2nd item", "the next item was returned");
|
||||
is(grid.itemCount, 2, "2 items remain");
|
||||
|
||||
@ -316,23 +315,23 @@ gTests.push({
|
||||
is(grid.itemCount, 2, "2 items initially");
|
||||
is(grid.selectedItems.length, 0, "nothing selected initially");
|
||||
|
||||
grid.toggleItemSelection(grid.children[1]);
|
||||
ok(grid.children[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
|
||||
grid.toggleItemSelection(grid.items[1]);
|
||||
ok(grid.items[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
|
||||
is(grid.selectedIndex, 1, "selectedIndex is correct");
|
||||
|
||||
grid.toggleItemSelection(grid.children[1]);
|
||||
ok(!grid.children[1].selected, "toggleItemSelection sets falsy selected prop on previously-selected item");
|
||||
grid.toggleItemSelection(grid.items[1]);
|
||||
ok(!grid.items[1].selected, "toggleItemSelection sets falsy selected prop on previously-selected item");
|
||||
is(grid.selectedIndex, -1, "selectedIndex reports correctly with nothing selected");
|
||||
|
||||
// item selection
|
||||
grid.selectItem(grid.children[1]);
|
||||
ok(grid.children[1].selected, "Item selected property is truthy after grid.selectItem");
|
||||
ok(grid.children[1].getAttribute("selected"), "Item selected attribute is truthy after grid.selectItem");
|
||||
grid.selectItem(grid.items[1]);
|
||||
ok(grid.items[1].selected, "Item selected property is truthy after grid.selectItem");
|
||||
ok(grid.items[1].getAttribute("selected"), "Item selected attribute is truthy after grid.selectItem");
|
||||
ok(grid.selectedItems.length, "There are selectedItems after grid.selectItem");
|
||||
|
||||
// clearSelection
|
||||
grid.selectItem(grid.children[0]);
|
||||
grid.selectItem(grid.children[1]);
|
||||
grid.selectItem(grid.items[0]);
|
||||
grid.selectItem(grid.items[1]);
|
||||
grid.clearSelection();
|
||||
is(grid.selectedItems.length, 0, "Nothing selected when we clearSelection");
|
||||
is(grid.selectedIndex, -1, "selectedIndex resets after clearSelection");
|
||||
@ -347,10 +346,10 @@ gTests.push({
|
||||
doc.defaultView.addEventListener("select", handler, false);
|
||||
info("select listener added");
|
||||
|
||||
info("calling selectItem, currently it is:" + grid.children[0].selected);
|
||||
info("calling selectItem, currently it is:" + grid.items[0].selected);
|
||||
// Note: A richgrid in seltype=single mode fires "select" events from selectItem
|
||||
grid.selectItem(grid.children[0]);
|
||||
info("calling selectItem, now it is:" + grid.children[0].selected);
|
||||
grid.selectItem(grid.items[0]);
|
||||
info("calling selectItem, now it is:" + grid.items[0].selected);
|
||||
yield waitForMs(0);
|
||||
|
||||
is(handlerStub.callCount, 1, "select event handler was called when we selected an item");
|
||||
@ -378,22 +377,22 @@ gTests.push({
|
||||
is(grid.itemCount, 2, "2 items initially");
|
||||
is(grid.selectedItems.length, 0, "nothing selected initially");
|
||||
|
||||
grid.toggleItemSelection(grid.children[1]);
|
||||
ok(grid.children[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
|
||||
grid.toggleItemSelection(grid.items[1]);
|
||||
ok(grid.items[1].selected, "toggleItemSelection sets truthy selected prop on previously-unselected item");
|
||||
is(grid.selectedItems.length, 1, "1 item selected when we first toggleItemSelection");
|
||||
is(grid.selectedItems[0], grid.children[1], "the right item is selected");
|
||||
is(grid.selectedItems[0], grid.items[1], "the right item is selected");
|
||||
is(grid.selectedIndex, 1, "selectedIndex is correct");
|
||||
|
||||
grid.toggleItemSelection(grid.children[1]);
|
||||
grid.toggleItemSelection(grid.items[1]);
|
||||
is(grid.selectedItems.length, 0, "Nothing selected when we toggleItemSelection again");
|
||||
|
||||
// clearSelection
|
||||
grid.children[0].selected=true;
|
||||
grid.children[1].selected=true;
|
||||
grid.items[0].selected=true;
|
||||
grid.items[1].selected=true;
|
||||
is(grid.selectedItems.length, 2, "Both items are selected before calling clearSelection");
|
||||
grid.clearSelection();
|
||||
is(grid.selectedItems.length, 0, "Nothing selected when we clearSelection");
|
||||
ok(!(grid.children[0].selected || grid.children[1].selected), "selected properties all falsy when we clearSelection");
|
||||
ok(!(grid.items[0].selected || grid.items[1].selected), "selected properties all falsy when we clearSelection");
|
||||
|
||||
// selectionchange events
|
||||
// in seltype=multiple mode, we track selected state on all items
|
||||
@ -405,10 +404,10 @@ gTests.push({
|
||||
doc.defaultView.addEventListener("selectionchange", handler, false);
|
||||
info("selectionchange listener added");
|
||||
|
||||
info("calling toggleItemSelection, currently it is:" + grid.children[0].selected);
|
||||
info("calling toggleItemSelection, currently it is:" + grid.items[0].selected);
|
||||
// Note: A richgrid in seltype=single mode fires "select" events from selectItem
|
||||
grid.toggleItemSelection(grid.children[0]);
|
||||
info("/calling toggleItemSelection, now it is:" + grid.children[0].selected);
|
||||
grid.toggleItemSelection(grid.items[0]);
|
||||
info("/calling toggleItemSelection, now it is:" + grid.items[0].selected);
|
||||
yield waitForMs(0);
|
||||
|
||||
is(handlerStub.callCount, 1, "selectionchange event handler was called when we selected an item");
|
||||
@ -418,6 +417,3 @@ gTests.push({
|
||||
doc.defaultView.removeEventListener("selectionchange", handler, false);
|
||||
}
|
||||
});
|
||||
|
||||
// implements a getItemAtIndex method (or grid.children[idx] ?)
|
||||
|
||||
|
@ -194,7 +194,7 @@ gTests.push({
|
||||
},
|
||||
run: function() {
|
||||
let grid = TopSitesTestHelper.grid;
|
||||
let items = grid.children;
|
||||
let items = grid.items;
|
||||
is(items.length, 8, "should be 8 topsites"); // i.e. not 10
|
||||
if(items.length) {
|
||||
let firstitem = items[0];
|
||||
@ -230,7 +230,7 @@ gTests.push({
|
||||
run: function() {
|
||||
// test that pinned state of each site as rendered matches our expectations
|
||||
let pins = this.pins.split(",");
|
||||
let items = TopSitesTestHelper.grid.children;
|
||||
let items = TopSitesTestHelper.grid.items;
|
||||
is(items.length, 8, "should be 8 topsites in the grid");
|
||||
|
||||
is(TopSitesTestHelper.document.querySelectorAll("#start-topsites-grid > [pinned]").length, 3, "should be 3 children with 'pinned' attribute");
|
||||
@ -273,10 +273,10 @@ gTests.push({
|
||||
// test that site is pinned as expected
|
||||
// and that sites fill positions around it
|
||||
let grid = TopSitesTestHelper.grid,
|
||||
items = grid.children;
|
||||
items = grid.items;
|
||||
is(items.length, 4, this.desc + ": should be 4 topsites");
|
||||
|
||||
let tile = grid.children[2],
|
||||
let tile = grid.items[2],
|
||||
url = tile.getAttribute("value"),
|
||||
title = tile.getAttribute("label");
|
||||
|
||||
@ -291,7 +291,7 @@ gTests.push({
|
||||
return !grid.controller.isUpdating;
|
||||
});
|
||||
|
||||
let thirdTile = grid.children[2];
|
||||
let thirdTile = grid.items[2];
|
||||
ok( thirdTile.hasAttribute("pinned"), thirdTile.getAttribute("value")+ " should look pinned" );
|
||||
|
||||
// visit some more sites
|
||||
@ -329,7 +329,7 @@ gTests.push({
|
||||
// unpin a pinned site
|
||||
// test that sites are unpinned as expected
|
||||
let grid = TopSitesTestHelper.grid,
|
||||
items = grid.children;
|
||||
items = grid.items;
|
||||
is(items.length, 8, this.desc + ": should be 8 topsites");
|
||||
let site = {
|
||||
url: items[1].getAttribute("value"),
|
||||
@ -346,7 +346,7 @@ gTests.push({
|
||||
return !grid.controller.isUpdating;
|
||||
});
|
||||
|
||||
let secondTile = grid.children[1];
|
||||
let secondTile = grid.items[1];
|
||||
ok( !secondTile.hasAttribute("pinned"), "2nd item should no longer be marked as pinned" );
|
||||
ok( !NewTabUtils.pinnedLinks.isPinned(site), "2nd item should no longer be pinned" );
|
||||
}
|
||||
@ -371,7 +371,7 @@ gTests.push({
|
||||
// block a site
|
||||
// test that sites are removed from the grid as expected
|
||||
let grid = TopSitesTestHelper.grid,
|
||||
items = grid.children;
|
||||
items = grid.items;
|
||||
is(items.length, 8, this.desc + ": should be 8 topsites");
|
||||
|
||||
let brianSite = TopSitesTestHelper.siteFromNode(items[0]);
|
||||
@ -426,7 +426,7 @@ gTests.push({
|
||||
is( grid.querySelectorAll("[value='"+dougalSite.url+"']").length, 1, "Unblocked site is back in the grid");
|
||||
// ..and that a previously pinned site is re-pinned after being blocked, then restored
|
||||
ok( NewTabUtils.pinnedLinks.isPinned(dougalSite), "Restoring previously pinned site makes it pinned again" );
|
||||
is( grid.children[1].getAttribute("value"), dougalSite.url, "Blocked Site restored to pinned index" );
|
||||
is( grid.items[1].getAttribute("value"), dougalSite.url, "Blocked Site restored to pinned index" );
|
||||
|
||||
ok( !NewTabUtils.blockedLinks.isBlocked(dylanSite), "site was unblocked" );
|
||||
is( grid.querySelectorAll("[value='"+dylanSite.url+"']").length, 1, "Unblocked site is back in the grid");
|
||||
@ -458,7 +458,7 @@ gTests.push({
|
||||
// delete a both pinned and unpinned sites
|
||||
// test that sites are removed from the grid
|
||||
let grid = TopSitesTestHelper.grid,
|
||||
items = grid.children;
|
||||
items = grid.items;
|
||||
is(items.length, 4, this.desc + ": should be 4 topsites");
|
||||
|
||||
let brianTile = grid.querySelector('richgriditem[value$="brian"]');
|
||||
|
@ -66,9 +66,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Black box message */
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message {
|
||||
#black-boxed-message,
|
||||
#source-progress-container {
|
||||
background: url(background-noise-toolbar.png) rgb(61,69,76);
|
||||
/* Prevent the container deck from aquiring the height from this message. */
|
||||
min-height: 1px;
|
||||
@ -76,6 +77,11 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
#source-progress {
|
||||
min-height: 2em;
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
#black-boxed-message-label,
|
||||
#black-boxed-message-button {
|
||||
text-align: center;
|
||||
|
@ -64,9 +64,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Black box message */
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message {
|
||||
#black-boxed-message,
|
||||
#source-progress-container {
|
||||
background: url(background-noise-toolbar.png) rgb(61,69,76);
|
||||
/* Prevent the container deck from aquiring the height from this message. */
|
||||
min-height: 1px;
|
||||
@ -74,6 +75,11 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
#source-progress {
|
||||
min-height: 2em;
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
#black-boxed-message-label,
|
||||
#black-boxed-message-button {
|
||||
text-align: center;
|
||||
|
@ -64,9 +64,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Black box message */
|
||||
/* Black box message and source progress meter */
|
||||
|
||||
#black-boxed-message {
|
||||
#black-boxed-message,
|
||||
#source-progress-container {
|
||||
background: url(background-noise-toolbar.png) rgb(61,69,76);
|
||||
/* Prevent the container deck from aquiring the height from this message. */
|
||||
min-height: 1px;
|
||||
@ -74,6 +75,11 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
#source-progress {
|
||||
min-height: 2em;
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
#black-boxed-message-label,
|
||||
#black-boxed-message-button {
|
||||
text-align: center;
|
||||
|
@ -171,10 +171,10 @@ AC_DEFUN([MOZ_COMPILER_OPTS],
|
||||
|
||||
AC_SUBST(DEVELOPER_OPTIONS)
|
||||
|
||||
if test -n "$DEVELOPER_OPTIONS" -a "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
|
||||
if test "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
|
||||
dnl Don't enable on pymake, because of bug 918652. Bug 912979 is an annoyance
|
||||
dnl with pymake, too.
|
||||
MOZ_PSEUDO_DERECURSE=no-parallel-export,no-pymake,no-skip
|
||||
MOZ_PSEUDO_DERECURSE=no-pymake,no-skip
|
||||
fi
|
||||
|
||||
MOZ_DEBUGGING_OPTS
|
||||
|
@ -41,11 +41,16 @@ TESTFLAGS := -fsyntax-only -Xclang -verify \
|
||||
$(TESTS): test-%: tests/%.cpp $(PLUGIN)
|
||||
$(CXX) $(TESTFLAGS) $<
|
||||
|
||||
compile binaries libs export tools: all
|
||||
compile libs export tools: all
|
||||
|
||||
distclean clean:
|
||||
rm -f $(OBJS) $(TESTS) $(PLUGIN)
|
||||
|
||||
check:
|
||||
|
||||
.PHONY: compile binaries libs export tools distclean clean check
|
||||
libs: binaries
|
||||
|
||||
binaries: all
|
||||
@touch $@
|
||||
|
||||
.PHONY: compile libs export tools distclean clean check
|
||||
|
@ -353,14 +353,17 @@ const kEventConstructors = {
|
||||
StyleRuleChangeEvent: { create: function (aName, aProps) {
|
||||
return new StyleRuleChangeEvent(aName, aProps);
|
||||
},
|
||||
chromeOnly: true,
|
||||
},
|
||||
StyleSheetApplicableStateChangeEvent: { create: function (aName, aProps) {
|
||||
return new StyleSheetApplicableStateChangeEvent(aName, aProps);
|
||||
},
|
||||
chromeOnly: true,
|
||||
},
|
||||
StyleSheetChangeEvent: { create: function (aName, aProps) {
|
||||
return new StyleSheetChangeEvent(aName, aProps);
|
||||
},
|
||||
chromeOnly: true,
|
||||
},
|
||||
SVGZoomEvent: { create: function (aName, aProps) {
|
||||
var e = document.createEvent("svgzoomevent");
|
||||
@ -410,6 +413,16 @@ const kEventConstructors = {
|
||||
},
|
||||
};
|
||||
|
||||
for (var name of Object.keys(kEventConstructors)) {
|
||||
if (!kEventConstructors[name].chromeOnly) {
|
||||
continue;
|
||||
}
|
||||
if (window[name]) {
|
||||
ok(false, name + " should be chrome only.");
|
||||
}
|
||||
window[name] = SpecialPowers.unwrap(SpecialPowers.wrap(window)[name]);
|
||||
}
|
||||
|
||||
var props = Object.getOwnPropertyNames(window);
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
// Assume that event object must be named as "FooBarEvent".
|
||||
|
@ -870,6 +870,12 @@ DOMInterfaces = {
|
||||
'resultNotAddRefed': [ 'coneGain', 'distanceGain' ],
|
||||
}],
|
||||
|
||||
'PeerConnectionImpl': {
|
||||
'nativeType': 'sipcc::PeerConnectionImpl',
|
||||
'headerFile': 'PeerConnectionImpl.h',
|
||||
'wrapperCache': False
|
||||
},
|
||||
|
||||
'Performance': {
|
||||
'nativeType': 'nsPerformance',
|
||||
'resultNotAddRefed': [ 'timing', 'navigation' ]
|
||||
|
@ -76,6 +76,8 @@ LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
|
||||
-I$(topsrcdir)/content/canvas/src \
|
||||
-I$(topsrcdir)/content/html/content/src \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/common/time_profiling \
|
||||
-I$(topsrcdir)/media/mtransport \
|
||||
-I$(topsrcdir)/dom/base \
|
||||
-I$(topsrcdir)/dom/battery \
|
||||
-I$(topsrcdir)/dom/indexedDB \
|
||||
|
@ -10,11 +10,13 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
|
||||
const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
|
||||
const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
|
||||
const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
|
||||
const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
|
||||
|
||||
const PC_CID = Components.ID("{9878b414-afaa-4176-a887-1e02b3b047c2}");
|
||||
const PC_OBS_CID = Components.ID("{1d44a18e-4545-4ff3-863d-6dbd6234a583}");
|
||||
const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
|
||||
const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
|
||||
const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}");
|
||||
@ -189,8 +191,7 @@ RTCPeerConnection.prototype = {
|
||||
classID: PC_CID,
|
||||
contractID: PC_CONTRACT,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
init: function(win) { this._win = win; },
|
||||
|
||||
__init: function(rtcConfig) {
|
||||
@ -217,9 +218,8 @@ RTCPeerConnection.prototype = {
|
||||
this.makeGetterSetterEH("onclosedconnection");
|
||||
this.makeGetterSetterEH("oniceconnectionstatechange");
|
||||
|
||||
this._pc = Cc["@mozilla.org/peerconnection;1"].
|
||||
createInstance(Ci.IPeerConnection);
|
||||
this._observer = new PeerConnectionObserver(this);
|
||||
this._pc = new this._win.PeerConnectionImpl();
|
||||
this._observer = new this._win.PeerConnectionObserver(this);
|
||||
this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
|
||||
|
||||
@ -227,13 +227,18 @@ RTCPeerConnection.prototype = {
|
||||
_globalPCList.addPC(this);
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._getPC().initialize,
|
||||
args: [this._observer, this._win, rtcConfig, Services.tm.currentThread],
|
||||
func: this._initialize,
|
||||
args: [rtcConfig],
|
||||
// If not trickling, suppress start.
|
||||
wait: !this._trickleIce
|
||||
});
|
||||
},
|
||||
|
||||
_initialize: function(rtcConfig) {
|
||||
this._getPC().initialize(this._observer, this._win, rtcConfig,
|
||||
Services.tm.currentThread);
|
||||
},
|
||||
|
||||
_getPC: function() {
|
||||
if (!this._pc) {
|
||||
throw new this._win.DOMError("",
|
||||
@ -301,6 +306,9 @@ RTCPeerConnection.prototype = {
|
||||
}
|
||||
}
|
||||
function mustValidateServer(server) {
|
||||
if (!server.url) {
|
||||
throw new errorCtor("", errorMsg + " - missing url");
|
||||
}
|
||||
let url = nicerNewURI(server.url, errorMsg);
|
||||
if (url.scheme in { turn:1, turns:1 }) {
|
||||
if (!server.username) {
|
||||
@ -324,75 +332,44 @@ RTCPeerConnection.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Constraints look like this:
|
||||
* MediaConstraints look like this:
|
||||
*
|
||||
* {
|
||||
* mandatory: {"OfferToReceiveAudio": true, "OfferToReceiveVideo": true },
|
||||
* optional: [{"VoiceActivityDetection": true}, {"FooBar": 10}]
|
||||
* }
|
||||
*
|
||||
* We check for basic structure of constraints and the validity of
|
||||
* mandatory constraints against those we support (fail if we don't).
|
||||
* Unknown optional constraints may be of any type.
|
||||
* WebIDL normalizes the top structure for us, but the mandatory constraints
|
||||
* member comes in as a raw object so we can detect unknown constraints.
|
||||
* We compare its members against ones we support, and fail if not found.
|
||||
*/
|
||||
_mustValidateConstraints: function(constraints, errorMsg) {
|
||||
function isObject(obj) {
|
||||
return obj && (typeof obj === "object");
|
||||
}
|
||||
function isArraylike(obj) {
|
||||
return isObject(obj) && ("length" in obj);
|
||||
}
|
||||
const SUPPORTED_CONSTRAINTS = {
|
||||
OfferToReceiveAudio:1,
|
||||
OfferToReceiveVideo:1,
|
||||
MozDontOfferDataChannel:1
|
||||
};
|
||||
const OTHER_KNOWN_CONSTRAINTS = {
|
||||
VoiceActivityDetection:1,
|
||||
IceTransports:1,
|
||||
RequestIdentity:1
|
||||
};
|
||||
// Parse-aid: Testing for pilot error of missing outer block avoids
|
||||
// otherwise silent no-op since both mandatory and optional are optional
|
||||
if (!isObject(constraints) || Array.isArray(constraints)) {
|
||||
throw new this._win.DOMError("", errorMsg);
|
||||
}
|
||||
if (constraints.mandatory) {
|
||||
// Testing for pilot error of using [] on mandatory here throws nicer msg
|
||||
// (arrays would throw in loop below regardless but with more cryptic msg)
|
||||
if (!isObject(constraints.mandatory) || Array.isArray(constraints.mandatory)) {
|
||||
throw new this._win.DOMError("",
|
||||
errorMsg + " - malformed mandatory constraints");
|
||||
let supported;
|
||||
try {
|
||||
// Passing the raw constraints.mandatory here validates its structure
|
||||
supported = this._observer.getSupportedConstraints(constraints.mandatory);
|
||||
} catch (e) {
|
||||
throw new this._win.DOMError("", errorMsg + " - " + e.message);
|
||||
}
|
||||
for (let constraint in constraints.mandatory) {
|
||||
if (!(constraint in SUPPORTED_CONSTRAINTS) &&
|
||||
constraints.mandatory.hasOwnProperty(constraint)) {
|
||||
throw new this._win.DOMError("", errorMsg + " - " +
|
||||
((constraint in OTHER_KNOWN_CONSTRAINTS)? "unsupported" : "unknown") +
|
||||
" mandatory constraint: " + constraint);
|
||||
|
||||
for (let constraint of Object.keys(constraints.mandatory)) {
|
||||
if (!(constraint in supported)) {
|
||||
throw new this._win.DOMError("",
|
||||
errorMsg + " - unknown mandatory constraint: " + constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (constraints.optional) {
|
||||
if (!isArraylike(constraints.optional)) {
|
||||
throw new this._win.DOMError("",
|
||||
errorMsg + " - malformed optional constraint array");
|
||||
}
|
||||
let len = constraints.optional.length;
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
if (!isObject(constraints.optional[i])) {
|
||||
throw new this._win.DOMError("", errorMsg +
|
||||
" - malformed optional constraint: " + constraints.optional[i]);
|
||||
}
|
||||
for (let i = 0; i < len; i++) {
|
||||
let constraints_per_entry = 0;
|
||||
for (let constraint in constraints.optional[i]) {
|
||||
if (constraints.optional[i].hasOwnProperty(constraint)) {
|
||||
if (constraints_per_entry) {
|
||||
throw new this._win.DOMError("", errorMsg +
|
||||
" - optional constraint must be single key/value pair");
|
||||
}
|
||||
constraints_per_entry += 1;
|
||||
for (let constraint in Object.keys(constraints.optional[i])) {
|
||||
if (constraints_per_entry) {
|
||||
throw new this._win.DOMError("", errorMsg +
|
||||
" - optional constraint must be single key/value pair");
|
||||
}
|
||||
constraints_per_entry += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,11 +470,11 @@ RTCPeerConnection.prototype = {
|
||||
this._onCreateOfferSuccess = onSuccess;
|
||||
this._onCreateOfferFailure = onError;
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._getPC().createOffer,
|
||||
args: [constraints],
|
||||
wait: true
|
||||
});
|
||||
this._queueOrRun({ func: this._createOffer, args: [constraints], wait: true });
|
||||
},
|
||||
|
||||
_createOffer: function(constraints) {
|
||||
this._getPC().createOffer(constraints);
|
||||
},
|
||||
|
||||
_createAnswer: function(onSuccess, onError, constraints, provisional) {
|
||||
@ -567,13 +544,17 @@ RTCPeerConnection.prototype = {
|
||||
}
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._getPC().setLocalDescription,
|
||||
func: this._setLocalDescription,
|
||||
args: [type, desc.sdp],
|
||||
wait: true,
|
||||
type: desc.type
|
||||
});
|
||||
},
|
||||
|
||||
_setLocalDescription: function(type, sdp) {
|
||||
this._getPC().setLocalDescription(type, sdp);
|
||||
},
|
||||
|
||||
setRemoteDescription: function(desc, onSuccess, onError) {
|
||||
// TODO -- if we have two setRemoteDescriptions in the
|
||||
// queue, this code overwrites the callbacks for the first
|
||||
@ -597,13 +578,17 @@ RTCPeerConnection.prototype = {
|
||||
}
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._getPC().setRemoteDescription,
|
||||
func: this._setRemoteDescription,
|
||||
args: [type, desc.sdp],
|
||||
wait: true,
|
||||
type: desc.type
|
||||
});
|
||||
},
|
||||
|
||||
_setRemoteDescription: function(type, sdp) {
|
||||
this._getPC().setRemoteDescription(type, sdp);
|
||||
},
|
||||
|
||||
updateIce: function(config, constraints) {
|
||||
throw new this._win.DOMError("", "updateIce not yet implemented");
|
||||
},
|
||||
@ -616,12 +601,13 @@ RTCPeerConnection.prototype = {
|
||||
this._onAddIceCandidateSuccess = onSuccess || null;
|
||||
this._onAddIceCandidateError = onError || null;
|
||||
|
||||
this._queueOrRun({
|
||||
func: this._getPC().addIceCandidate,
|
||||
args: [cand.candidate, cand.sdpMid || "",
|
||||
(cand.sdpMLineIndex === null)? 0 : cand.sdpMLineIndex + 1],
|
||||
wait: true
|
||||
});
|
||||
this._queueOrRun({ func: this._addIceCandidate, args: [cand], wait: true });
|
||||
},
|
||||
|
||||
_addIceCandidate: function(cand) {
|
||||
this._getPC().addIceCandidate(cand.candidate, cand.sdpMid || "",
|
||||
(cand.sdpMLineIndex === null)? 0 :
|
||||
cand.sdpMLineIndex + 1);
|
||||
},
|
||||
|
||||
addStream: function(stream, constraints) {
|
||||
@ -629,11 +615,11 @@ RTCPeerConnection.prototype = {
|
||||
throw new this._win.DOMError("", "Invalid stream passed to addStream!");
|
||||
}
|
||||
// TODO: Implement constraints.
|
||||
this._queueOrRun({
|
||||
func: this._getPC().addStream,
|
||||
args: [stream],
|
||||
wait: false
|
||||
});
|
||||
this._queueOrRun({ func: this._addStream, args: [stream], wait: false });
|
||||
},
|
||||
|
||||
_addStream: function(stream) {
|
||||
this._getPC().addStream(stream);
|
||||
},
|
||||
|
||||
removeStream: function(stream) {
|
||||
@ -646,23 +632,23 @@ RTCPeerConnection.prototype = {
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this._queueOrRun({
|
||||
func: this._getPC().close,
|
||||
args: [false],
|
||||
wait: false
|
||||
});
|
||||
this._queueOrRun({ func: this._close, args: [false], wait: false });
|
||||
this._closed = true;
|
||||
this.changeIceConnectionState("closed");
|
||||
},
|
||||
|
||||
_close: function() {
|
||||
this._getPC().close();
|
||||
},
|
||||
|
||||
getLocalStreams: function() {
|
||||
this._checkClosed();
|
||||
return this._getPC().localStreams;
|
||||
return this._getPC().getLocalStreams();
|
||||
},
|
||||
|
||||
getRemoteStreams: function() {
|
||||
this._checkClosed();
|
||||
return this._getPC().remoteStreams;
|
||||
return this._getPC().getRemoteStreams();
|
||||
},
|
||||
|
||||
// Backwards-compatible attributes
|
||||
@ -698,24 +684,21 @@ RTCPeerConnection.prototype = {
|
||||
get iceGatheringState() { return this._iceGatheringState; },
|
||||
get iceConnectionState() { return this._iceConnectionState; },
|
||||
|
||||
// Corresponds to constants in IPeerConnection.idl
|
||||
_signalingStateMap: [
|
||||
'invalid',
|
||||
'stable',
|
||||
'have-local-offer',
|
||||
'have-remote-offer',
|
||||
'have-local-pranswer',
|
||||
'have-remote-pranswer',
|
||||
'closed'
|
||||
],
|
||||
|
||||
get signalingState() {
|
||||
// checking for our local pc closed indication
|
||||
// before invoking the pc methods.
|
||||
if(this._closed) {
|
||||
return "closed";
|
||||
}
|
||||
return this._signalingStateMap[this._getPC().signalingState];
|
||||
return {
|
||||
"SignalingInvalid": "",
|
||||
"SignalingStable": "stable",
|
||||
"SignalingHaveLocalOffer": "have-local-offer",
|
||||
"SignalingHaveRemoteOffer": "have-remote-offer",
|
||||
"SignalingHaveLocalPranswer": "have-local-pranswer",
|
||||
"SignalingHaveRemotePranswer": "have-remote-pranswer",
|
||||
"SignalingClosed": "closed"
|
||||
}[this._getPC().signalingState];
|
||||
},
|
||||
|
||||
changeIceGatheringState: function(state) {
|
||||
@ -814,10 +797,14 @@ RTCPeerConnection.prototype = {
|
||||
numstreams = 16;
|
||||
}
|
||||
this._queueOrRun({
|
||||
func: this._getPC().connectDataConnection,
|
||||
func: this._connectDataConnection,
|
||||
args: [localport, remoteport, numstreams],
|
||||
wait: false
|
||||
});
|
||||
},
|
||||
|
||||
_connectDataConnection: function(localport, remoteport, numstreams) {
|
||||
this._getPC().connectDataConnection(localport, remoteport, numstreams);
|
||||
}
|
||||
};
|
||||
|
||||
@ -843,12 +830,20 @@ RTCError.prototype = {
|
||||
};
|
||||
|
||||
// This is a separate object because we don't want to expose it to DOM.
|
||||
function PeerConnectionObserver(dompc) {
|
||||
this._dompc = dompc;
|
||||
function PeerConnectionObserver() {
|
||||
this._dompc = null;
|
||||
}
|
||||
PeerConnectionObserver.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
classDescription: "PeerConnectionObserver",
|
||||
classID: PC_OBS_CID,
|
||||
contractID: PC_OBS_CONTRACT,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
init: function(win) { this._win = win; },
|
||||
|
||||
__init: function(dompc) {
|
||||
this._dompc = dompc;
|
||||
},
|
||||
|
||||
dispatchEvent: function(event) {
|
||||
this._dompc.dispatchEvent(event);
|
||||
@ -1000,23 +995,19 @@ PeerConnectionObserver.prototype = {
|
||||
handleIceStateChanges: function(iceState) {
|
||||
var histogram = Services.telemetry.getHistogramById("WEBRTC_ICE_SUCCESS_RATE");
|
||||
|
||||
const STATE_MAP = [
|
||||
// Ci.IPeerConnection.kIceGathering:
|
||||
const STATE_MAP = {
|
||||
IceGathering:
|
||||
{ gathering: "gathering" },
|
||||
// Ci.IPeerConnection.kIceWaiting:
|
||||
IceWaiting:
|
||||
{ connection: "new", gathering: "complete", legacy: "starting" },
|
||||
// Ci.IPeerConnection.kIceChecking:
|
||||
IceChecking:
|
||||
{ connection: "checking", legacy: "checking" },
|
||||
// Ci.IPeerConnection.kIceConnected:
|
||||
IceConnected:
|
||||
{ connection: "connected", legacy: "connected", success: true },
|
||||
// Ci.IPeerConnection.kIceFailed:
|
||||
IceFailed:
|
||||
{ connection: "failed", legacy: "failed", success: false }
|
||||
];
|
||||
|
||||
if (iceState < 0 || iceState > STATE_MAP.length) {
|
||||
this._dompc.reportWarning("Unhandled ice state: " + iceState, null, 0);
|
||||
return;
|
||||
}
|
||||
};
|
||||
// These are all the allowed inputs.
|
||||
|
||||
let transitions = STATE_MAP[iceState];
|
||||
|
||||
@ -1036,7 +1027,7 @@ PeerConnectionObserver.prototype = {
|
||||
histogram.add(transitions.success);
|
||||
}
|
||||
|
||||
if (iceState == Ci.IPeerConnection.kIceWaiting) {
|
||||
if (iceState == "IceWaiting") {
|
||||
if (!this._dompc._trickleIce) {
|
||||
// If we are not trickling, then the queue is in a pending state
|
||||
// waiting for ICE gathering and executeNext frees it
|
||||
@ -1053,24 +1044,24 @@ PeerConnectionObserver.prototype = {
|
||||
|
||||
onStateChange: function(state) {
|
||||
switch (state) {
|
||||
case Ci.IPeerConnectionObserver.kSignalingState:
|
||||
case "SignalingState":
|
||||
this.callCB(this._dompc.onsignalingstatechange,
|
||||
this._dompc.signalingState);
|
||||
break;
|
||||
|
||||
case Ci.IPeerConnectionObserver.kIceState:
|
||||
case "IceState":
|
||||
this.handleIceStateChanges(this._dompc._pc.iceState);
|
||||
break;
|
||||
|
||||
case Ci.IPeerConnectionObserver.kSdpState:
|
||||
case "SdpState":
|
||||
// No-op
|
||||
break;
|
||||
|
||||
case Ci.IPeerConnectionObserver.kReadyState:
|
||||
case "ReadyState":
|
||||
// No-op
|
||||
break;
|
||||
|
||||
case Ci.IPeerConnectionObserver.kSipccState:
|
||||
case "SipccState":
|
||||
// No-op
|
||||
break;
|
||||
|
||||
@ -1106,9 +1097,14 @@ PeerConnectionObserver.prototype = {
|
||||
|
||||
notifyClosedConnection: function() {
|
||||
this.dispatchEvent(new this._dompc._win.Event("closedconnection"));
|
||||
},
|
||||
|
||||
getSupportedConstraints: function(dict) {
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
[GlobalPCList, RTCIceCandidate, RTCSessionDescription, RTCPeerConnection]
|
||||
[GlobalPCList, RTCIceCandidate, RTCSessionDescription, RTCPeerConnection,
|
||||
PeerConnectionObserver]
|
||||
);
|
||||
|
@ -1,9 +1,11 @@
|
||||
component {9878b414-afaa-4176-a887-1e02b3b047c2} PeerConnection.js
|
||||
component {1d44a18e-4545-4ff3-863d-6dbd6234a583} PeerConnection.js
|
||||
component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
|
||||
component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
|
||||
component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
|
||||
|
||||
contract @mozilla.org/dom/peerconnection;1 {9878b414-afaa-4176-a887-1e02b3b047c2}
|
||||
contract @mozilla.org/dom/peerconnectionobserver;1 {1d44a18e-4545-4ff3-863d-6dbd6234a583}
|
||||
contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
|
||||
contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
|
||||
contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78}
|
||||
|
@ -24,45 +24,12 @@ interface IPeerConnectionManager : nsISupports
|
||||
*
|
||||
* See media/webrtc/signaling/include/PeerConnectionImpl.h
|
||||
*/
|
||||
[scriptable, uuid(896dc16a-05d6-45e4-bdbf-aba57123ed3e)]
|
||||
[scriptable, uuid(d7dfe148-0416-446b-a128-66a7c71ae8d3)]
|
||||
interface IPeerConnectionObserver : nsISupports
|
||||
{
|
||||
/* Constants */
|
||||
const long kReadyState = 0x1;
|
||||
const long kIceState = 0x2;
|
||||
const long kSdpState = 0x3;
|
||||
const long kSipccState = 0x4;
|
||||
const long kSignalingState = 0x5;
|
||||
|
||||
/* JSEP callbacks */
|
||||
void onCreateOfferSuccess(in string offer);
|
||||
void onCreateOfferError(in unsigned long name, in string message);
|
||||
void onCreateAnswerSuccess(in string answer);
|
||||
void onCreateAnswerError(in unsigned long name, in string message);
|
||||
void onSetLocalDescriptionSuccess();
|
||||
void onSetRemoteDescriptionSuccess();
|
||||
void onSetLocalDescriptionError(in unsigned long name, in string message);
|
||||
void onSetRemoteDescriptionError(in unsigned long name, in string message);
|
||||
void onAddIceCandidateSuccess();
|
||||
void onAddIceCandidateError(in unsigned long name, in string message);
|
||||
void onIceCandidate(in unsigned short level, in string mid, in string candidate);
|
||||
|
||||
/* Data channel callbacks */
|
||||
void notifyDataChannel(in nsIDOMDataChannel channel);
|
||||
void notifyConnection();
|
||||
void notifyClosedConnection();
|
||||
|
||||
/* Notification of one of several types of state changed */
|
||||
void onStateChange(in unsigned long state);
|
||||
|
||||
/* Changes to MediaStreams */
|
||||
void onAddStream(in nsIDOMMediaStream stream);
|
||||
void onRemoveStream();
|
||||
void onAddTrack();
|
||||
void onRemoveTrack();
|
||||
};
|
||||
|
||||
[scriptable, uuid(930dce8b-7c5e-4393-b8c0-cb3a928f68bd)]
|
||||
[scriptable, uuid(c9c31639-1a49-4533-8429-f6a348c4d8c3)]
|
||||
interface IPeerConnection : nsISupports
|
||||
{
|
||||
const unsigned long kHintAudio = 0x00000001;
|
||||
@ -86,15 +53,6 @@ interface IPeerConnection : nsISupports
|
||||
const long kClosing = 3;
|
||||
const long kClosed = 4;
|
||||
|
||||
/* RTCSignalingState from WebRTC spec */
|
||||
const long kSignalingInvalid = 0;
|
||||
const long kSignalingStable = 1;
|
||||
const long kSignalingHaveLocalOffer = 2;
|
||||
const long kSignalingHaveRemoteOffer = 3;
|
||||
const long kSignalingHaveLocalPranswer = 4;
|
||||
const long kSignalingHaveRemotePranswer = 5;
|
||||
const long kSignalingClosed = 6;
|
||||
|
||||
/* for 'type' in DataChannelInit dictionary */
|
||||
const unsigned short kDataChannelReliable = 0;
|
||||
const unsigned short kDataChannelPartialReliableRexmit = 1;
|
||||
@ -112,50 +70,4 @@ interface IPeerConnection : nsISupports
|
||||
const unsigned long kIncompatibleMediaStreamTrack = 8;
|
||||
const unsigned long kInternalError = 9;
|
||||
const unsigned long kMaxErrorType = 9; // Same as final error
|
||||
|
||||
/* Must be called first. Observer events will be dispatched on the thread provided */
|
||||
[implicit_jscontext] void initialize(in IPeerConnectionObserver observer, in nsIDOMWindow window,
|
||||
[optional] in jsval iceServers,
|
||||
[optional] in nsIThread thread);
|
||||
|
||||
/* JSEP calls */
|
||||
[implicit_jscontext] void createOffer(in jsval constraints);
|
||||
[implicit_jscontext] void createAnswer(in jsval constraints);
|
||||
void setLocalDescription(in long action, in string sdp);
|
||||
void setRemoteDescription(in long action, in string sdp);
|
||||
|
||||
/* Adds the stream created by GetUserMedia */
|
||||
void addStream(in nsIDOMMediaStream stream);
|
||||
void removeStream(in nsIDOMMediaStream stream);
|
||||
void closeStreams();
|
||||
|
||||
[implicit_jscontext] readonly attribute jsval localStreams; // MediaStream[]
|
||||
[implicit_jscontext] readonly attribute jsval remoteStreams; // MediaStream[]
|
||||
|
||||
/* As the ICE candidates roll in this one should be called each time
|
||||
* in order to keep the candidate list up-to-date for the next SDP-related
|
||||
* call PeerConnectionImpl does not parse ICE candidates, just sticks them
|
||||
* into the SDP.
|
||||
*/
|
||||
void addIceCandidate(in string candidate, in string mid, in unsigned short level);
|
||||
|
||||
/* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */
|
||||
void close();
|
||||
|
||||
/* Attributes */
|
||||
readonly attribute string localDescription;
|
||||
readonly attribute string remoteDescription;
|
||||
|
||||
readonly attribute unsigned long iceState;
|
||||
readonly attribute unsigned long readyState;
|
||||
readonly attribute unsigned long signalingState;
|
||||
readonly attribute unsigned long sipccState;
|
||||
|
||||
/* Data channels */
|
||||
nsIDOMDataChannel createDataChannel(in ACString label, in ACString protocol,
|
||||
in unsigned short type, in boolean outOfOrderAllowed,
|
||||
in unsigned short maxTime, in unsigned short maxNum,
|
||||
in boolean externalNegotiated, in unsigned short stream);
|
||||
void connectDataConnection(in unsigned short localport,
|
||||
in unsigned short remoteport, in unsigned short numstreams);
|
||||
};
|
||||
|
@ -27,15 +27,9 @@
|
||||
try { pconnect.createOffer(step1, failed, 1); } catch (e) { exception = e; }
|
||||
ok(exception, "createOffer(step1, failed, 1) throws");
|
||||
exception = null;
|
||||
try { pconnect.createOffer(step1, failed, []); } catch (e) { exception = e; }
|
||||
ok(exception, "createOffer(step1, failed, []) throws");
|
||||
exception = null;
|
||||
try { pconnects.createOffer(step1, failed, {}); } catch (e) { exception = e; }
|
||||
ok(!exception, "createOffer(step1, failed, {}) succeeds");
|
||||
exception = null;
|
||||
try { pconnect.createOffer(step1, failed, { mandatory: [] }); } catch (e) { exception = e; }
|
||||
ok(exception, "createOffer(step1, failed, { mandatory: [] }) throws");
|
||||
exception = null;
|
||||
try {
|
||||
pconnect.createOffer(step1, failed, { mandatory: { FooBar: true } });
|
||||
} catch (e) {
|
||||
@ -44,9 +38,6 @@
|
||||
}
|
||||
ok(exception, "createOffer(step1, failed, { mandatory: { FooBar: true } }) throws");
|
||||
exception = null;
|
||||
try { pconnect.createOffer(step1, failed, { optional: {} }); } catch (e) { exception = e; }
|
||||
ok(exception, "createOffer(step1, failed, { optional: {} }) throws");
|
||||
exception = null;
|
||||
try { pconnects.createOffer(step1, failed, { optional: [] }); } catch (e) { exception = e; }
|
||||
ok(!exception, "createOffer(step1, failed, { optional: [] }) succeeds");
|
||||
exception = null;
|
||||
|
@ -411,10 +411,7 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "SpecialPowers", xbl: false},
|
||||
"Storage",
|
||||
"StorageEvent",
|
||||
"StyleRuleChangeEvent",
|
||||
"StyleSheet",
|
||||
"StyleSheetApplicableStateChangeEvent",
|
||||
"StyleSheetChangeEvent",
|
||||
"StyleSheetList",
|
||||
"SVGAElement",
|
||||
"SVGAltGlyphElement",
|
||||
|
@ -4,7 +4,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[NoInterfaceObject]
|
||||
[ChromeOnly]
|
||||
interface MediaStreamList {
|
||||
getter MediaStream? (unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
|
77
dom/webidl/PeerConnectionImpl.webidl
Normal file
77
dom/webidl/PeerConnectionImpl.webidl
Normal file
@ -0,0 +1,77 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* PeerConnection.js' interface to the C++ PeerConnectionImpl.
|
||||
*
|
||||
* Do not confuse with mozRTCPeerConnection. This interface is purely for
|
||||
* communication between the PeerConnection JS DOM binding and the C++
|
||||
* implementation in SIPCC.
|
||||
*
|
||||
* See media/webrtc/signaling/include/PeerConnectionImpl.h
|
||||
*
|
||||
*/
|
||||
|
||||
interface Window;
|
||||
interface nsISupports;
|
||||
|
||||
/* Must be created first. Observer events will be dispatched on the thread provided */
|
||||
[ChromeOnly, Constructor]
|
||||
interface PeerConnectionImpl {
|
||||
/* Must be called first. Observer events dispatched on the thread provided */
|
||||
[Throws]
|
||||
void initialize(PeerConnectionObserver observer, Window window,
|
||||
RTCConfiguration iceServers,
|
||||
nsISupports thread);
|
||||
/* JSEP calls */
|
||||
[Throws]
|
||||
void createOffer(optional MediaConstraintsInternal constraints);
|
||||
[Throws]
|
||||
void createAnswer(optional MediaConstraintsInternal constraints);
|
||||
[Throws]
|
||||
void setLocalDescription(long action, DOMString sdp);
|
||||
[Throws]
|
||||
void setRemoteDescription(long action, DOMString sdp);
|
||||
|
||||
/* Adds the stream created by GetUserMedia */
|
||||
[Throws]
|
||||
void addStream(MediaStream stream);
|
||||
[Throws]
|
||||
void removeStream(MediaStream stream);
|
||||
[Throws]
|
||||
void closeStreams();
|
||||
|
||||
sequence<MediaStream> getLocalStreams();
|
||||
sequence<MediaStream> getRemoteStreams();
|
||||
|
||||
/* As the ICE candidates roll in this one should be called each time
|
||||
* in order to keep the candidate list up-to-date for the next SDP-related
|
||||
* call PeerConnectionImpl does not parse ICE candidates, just sticks them
|
||||
* into the SDP.
|
||||
*/
|
||||
[Throws]
|
||||
void addIceCandidate(DOMString candidate, DOMString mid, unsigned short level);
|
||||
|
||||
/* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */
|
||||
void close();
|
||||
|
||||
/* Attributes */
|
||||
readonly attribute DOMString localDescription;
|
||||
readonly attribute DOMString remoteDescription;
|
||||
|
||||
readonly attribute PCImplIceState iceState;
|
||||
readonly attribute PCImplReadyState readyState;
|
||||
readonly attribute PCImplSignalingState signalingState;
|
||||
readonly attribute PCImplSipccState sipccState;
|
||||
|
||||
/* Data channels */
|
||||
[Throws]
|
||||
DataChannel createDataChannel(DOMString label, DOMString protocol,
|
||||
unsigned short type, boolean outOfOrderAllowed,
|
||||
unsigned short maxTime, unsigned short maxNum,
|
||||
boolean externalNegotiated, unsigned short stream);
|
||||
[Throws]
|
||||
void connectDataConnection(unsigned short localport,
|
||||
unsigned short remoteport, unsigned short numstreams);
|
||||
};
|
41
dom/webidl/PeerConnectionImplEnums.webidl
Normal file
41
dom/webidl/PeerConnectionImplEnums.webidl
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* This is in a separate file so it can be shared with unittests.
|
||||
*/
|
||||
|
||||
enum PCImplReadyState {
|
||||
"New",
|
||||
"Negotiating",
|
||||
"Active",
|
||||
"Closing",
|
||||
"Closed"
|
||||
};
|
||||
|
||||
/* Must be in the same order as comparable fsmdef_states_t in fsmdef_states.h */
|
||||
enum PCImplSignalingState {
|
||||
"SignalingInvalid",
|
||||
"SignalingStable",
|
||||
"SignalingHaveLocalOffer",
|
||||
"SignalingHaveRemoteOffer",
|
||||
"SignalingHaveLocalPranswer",
|
||||
"SignalingHaveRemotePranswer",
|
||||
"SignalingClosed",
|
||||
};
|
||||
|
||||
enum PCImplSipccState {
|
||||
"Idle",
|
||||
"Starting",
|
||||
"Started"
|
||||
};
|
||||
|
||||
// TODO(ekr@rtfm.com): make this conform to the specifications
|
||||
enum PCImplIceState {
|
||||
"IceGathering",
|
||||
"IceWaiting",
|
||||
"IceChecking",
|
||||
"IceConnected",
|
||||
"IceFailed"
|
||||
};
|
46
dom/webidl/PeerConnectionObserver.webidl
Normal file
46
dom/webidl/PeerConnectionObserver.webidl
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
[ChromeOnly,
|
||||
JSImplementation="@mozilla.org/dom/peerconnectionobserver;1",
|
||||
Constructor (object domPC)]
|
||||
interface PeerConnectionObserver
|
||||
{
|
||||
/* JSEP callbacks */
|
||||
void onCreateOfferSuccess(DOMString offer);
|
||||
void onCreateOfferError(unsigned long name, DOMString message);
|
||||
void onCreateAnswerSuccess(DOMString answer);
|
||||
void onCreateAnswerError(unsigned long name, DOMString message);
|
||||
void onSetLocalDescriptionSuccess();
|
||||
void onSetRemoteDescriptionSuccess();
|
||||
void onSetLocalDescriptionError(unsigned long name, DOMString message);
|
||||
void onSetRemoteDescriptionError(unsigned long name, DOMString message);
|
||||
void onAddIceCandidateSuccess();
|
||||
void onAddIceCandidateError(unsigned long name, DOMString message);
|
||||
void onIceCandidate(unsigned short level, DOMString mid, DOMString candidate);
|
||||
|
||||
/* Data channel callbacks */
|
||||
void notifyDataChannel(DataChannel channel);
|
||||
void notifyConnection();
|
||||
void notifyClosedConnection();
|
||||
|
||||
/* Notification of one of several types of state changed */
|
||||
void onStateChange(PCObserverStateType state);
|
||||
|
||||
/* Changes to MediaStreams */
|
||||
void onAddStream(MediaStream stream);
|
||||
void onRemoveStream();
|
||||
void onAddTrack();
|
||||
void onRemoveTrack();
|
||||
|
||||
/* Helper function to access supported constraints defined in webidl. Needs to
|
||||
* be in a separate webidl object we hold, so putting it here was convenient.
|
||||
*/
|
||||
// TODO: Bug 863949
|
||||
// MediaConstraintSet getSupportedConstraints(optional
|
||||
object getSupportedConstraints(optional
|
||||
MediaConstraintSet constraints);
|
||||
};
|
16
dom/webidl/PeerConnectionObserverEnums.webidl
Normal file
16
dom/webidl/PeerConnectionObserverEnums.webidl
Normal file
@ -0,0 +1,16 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* This is in a separate file so it can be shared with unittests.
|
||||
*/
|
||||
|
||||
enum PCObserverStateType {
|
||||
"None",
|
||||
"ReadyState",
|
||||
"IceState",
|
||||
"SdpState",
|
||||
"SipccState",
|
||||
"SignalingState"
|
||||
};
|
@ -51,6 +51,32 @@ dictionary RTCDataChannelInit {
|
||||
unsigned short stream; // now id
|
||||
};
|
||||
|
||||
// Misnomer dictionaries housing PeerConnection-specific constraints.
|
||||
//
|
||||
// Important! Do not ever add members that might need tracing (e.g. object)
|
||||
// to MediaConstraintSet or any dictionary marked XxxInternal here
|
||||
|
||||
dictionary MediaConstraintSet {
|
||||
boolean OfferToReceiveAudio;
|
||||
boolean OfferToReceiveVideo;
|
||||
boolean MozDontOfferDataChannel;
|
||||
};
|
||||
|
||||
// MediaConstraint = single-property-subset of MediaConstraintSet
|
||||
// Implemented as full set. Test Object.keys(pair).length == 1
|
||||
|
||||
// typedef MediaConstraintSet MediaConstraint; // TODO: Bug 913053
|
||||
|
||||
dictionary MediaConstraints {
|
||||
object mandatory; // so we can see unknown + unsupported constraints
|
||||
sequence<MediaConstraintSet> _optional; // a.k.a. MediaConstraint
|
||||
};
|
||||
|
||||
dictionary MediaConstraintsInternal {
|
||||
MediaConstraintSet mandatory; // holds only supported constraints
|
||||
sequence<MediaConstraintSet> _optional; // a.k.a. MediaConstraint
|
||||
};
|
||||
|
||||
interface RTCDataChannel;
|
||||
|
||||
[Pref="media.peerconnection.enabled",
|
||||
@ -61,10 +87,10 @@ interface RTCDataChannel;
|
||||
interface mozRTCPeerConnection : EventTarget {
|
||||
void createOffer (RTCSessionDescriptionCallback successCallback,
|
||||
RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
|
||||
optional object? constraints);
|
||||
optional MediaConstraints constraints);
|
||||
void createAnswer (RTCSessionDescriptionCallback successCallback,
|
||||
RTCPeerConnectionErrorCallback? failureCallback, // for apprtc
|
||||
optional object? constraints);
|
||||
optional MediaConstraints constraints);
|
||||
void setLocalDescription (mozRTCSessionDescription description,
|
||||
optional VoidFunction successCallback,
|
||||
optional RTCPeerConnectionErrorCallback failureCallback);
|
||||
@ -75,7 +101,7 @@ interface mozRTCPeerConnection : EventTarget {
|
||||
readonly attribute mozRTCSessionDescription? remoteDescription;
|
||||
readonly attribute RTCSignalingState signalingState;
|
||||
void updateIce (optional RTCConfiguration configuration,
|
||||
optional object? constraints);
|
||||
optional MediaConstraints constraints);
|
||||
void addIceCandidate (mozRTCIceCandidate candidate,
|
||||
optional VoidFunction successCallback,
|
||||
optional RTCPeerConnectionErrorCallback failureCallback);
|
||||
@ -84,7 +110,7 @@ interface mozRTCPeerConnection : EventTarget {
|
||||
sequence<MediaStream> getLocalStreams ();
|
||||
sequence<MediaStream> getRemoteStreams ();
|
||||
MediaStream? getStreamById (DOMString streamId);
|
||||
void addStream (MediaStream stream, optional object? constraints);
|
||||
void addStream (MediaStream stream, optional MediaConstraints constraints);
|
||||
void removeStream (MediaStream stream);
|
||||
void close ();
|
||||
attribute EventHandler onnegotiationneeded;
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
interface CSSRule;
|
||||
|
||||
[Constructor(DOMString type, optional StyleRuleChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
[ChromeOnly, Constructor(DOMString type, optional StyleRuleChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
interface StyleRuleChangeEvent : Event
|
||||
{
|
||||
readonly attribute CSSStyleSheet? stylesheet;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type, optional StyleSheetApplicableStateChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
[ChromeOnly, Constructor(DOMString type, optional StyleSheetApplicableStateChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
interface StyleSheetApplicableStateChangeEvent : Event
|
||||
{
|
||||
readonly attribute CSSStyleSheet? stylesheet;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type, optional StyleSheetChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
[ChromeOnly, Constructor(DOMString type, optional StyleSheetChangeEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
|
||||
interface StyleSheetChangeEvent : Event
|
||||
{
|
||||
readonly attribute CSSStyleSheet? stylesheet;
|
||||
|
@ -242,6 +242,10 @@ WEBIDL_FILES = [
|
||||
'PaintRequestList.webidl',
|
||||
'PannerNode.webidl',
|
||||
'ParentNode.webidl',
|
||||
'PeerConnectionImpl.webidl',
|
||||
'PeerConnectionImplEnums.webidl',
|
||||
'PeerConnectionObserver.webidl',
|
||||
'PeerConnectionObserverEnums.webidl',
|
||||
'Performance.webidl',
|
||||
'PerformanceNavigation.webidl',
|
||||
'PerformanceTiming.webidl',
|
||||
|
@ -99,10 +99,10 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient>
|
||||
CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
|
||||
CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
|
||||
{
|
||||
return CompositableClient::CreateBufferTextureClient(aFormat,
|
||||
mTextureInfo.mTextureFlags);
|
||||
mTextureInfo.mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -83,7 +83,8 @@ public:
|
||||
}
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual void OnDetach() MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -207,12 +207,6 @@ CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient>
|
||||
CompositableClient::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
return CreateBufferTextureClient(aFormat, TEXTURE_FLAGS_DEFAULT);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::AddTextureClient(TextureClient* aClient)
|
||||
{
|
||||
|
@ -85,10 +85,8 @@ public:
|
||||
gfxContentType aContentType = GFX_CONTENT_SENTINEL);
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags);
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat);
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
|
||||
|
||||
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aDescriptor)
|
||||
|
@ -293,13 +293,6 @@ ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, Texture
|
||||
return CompositableClient::CreateBufferTextureClient(aFormat, mTextureFlags | aFlags);
|
||||
}
|
||||
|
||||
TemporaryRef<BufferTextureClient>
|
||||
ImageClientSingle::CreateBufferTextureClient(gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
return CompositableClient::CreateBufferTextureClient(aFormat,
|
||||
mTextureFlags | TEXTURE_FLAGS_DEFAULT);
|
||||
}
|
||||
|
||||
void
|
||||
ImageClientSingle::OnDetach()
|
||||
{
|
||||
|
@ -92,10 +92,8 @@ public:
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE;
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags) MOZ_OVERRIDE;
|
||||
|
||||
virtual TemporaryRef<BufferTextureClient>
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat) MOZ_OVERRIDE;
|
||||
CreateBufferTextureClient(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT) MOZ_OVERRIDE;
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -714,7 +714,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
||||
nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
|
||||
APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
|
||||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller && mAllowZoom) {
|
||||
if (controller && !mAllowZoom) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, mFrameMetrics.mZoom);
|
||||
|
38
intl/icu-patches/bug-901348
Normal file
38
intl/icu-patches/bug-901348
Normal file
@ -0,0 +1,38 @@
|
||||
# HG changeset patch
|
||||
# User Nomis101
|
||||
# Date 1380136873 -7200
|
||||
# Wed Sep 25 21:21:13 2013 +0200
|
||||
# Node ID 2921e2256ba8a8ac1ca8b5b0e48eb04511545d41
|
||||
# Parent 39f30376058cf20823534f2d510430eaa31844bf
|
||||
Bug 901348 - [10.9] Duplicate symbol errors building --with-intl-api
|
||||
|
||||
diff --git a/intl/icu/source/common/umutex.h b/intl/icu/source/common/umutex.h
|
||||
--- a/intl/icu/source/common/umutex.h
|
||||
+++ b/intl/icu/source/common/umutex.h
|
||||
@@ -43,26 +43,18 @@
|
||||
# define NOIME
|
||||
# define NOMCX
|
||||
# include <windows.h>
|
||||
#endif /* 0 */
|
||||
#define U_WINDOWS_CRIT_SEC_SIZE 64
|
||||
#endif /* win32 */
|
||||
|
||||
#if U_PLATFORM_IS_DARWIN_BASED
|
||||
-#if defined(__STRICT_ANSI__)
|
||||
-#define UPRV_REMAP_INLINE
|
||||
-#define inline
|
||||
-#endif
|
||||
#include <libkern/OSAtomic.h>
|
||||
#define USE_MAC_OS_ATOMIC_INCREMENT 1
|
||||
-#if defined(UPRV_REMAP_INLINE)
|
||||
-#undef inline
|
||||
-#undef UPRV_REMAP_INLINE
|
||||
-#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we do not compile with dynamic_annotations.h then define
|
||||
* empty annotation macros.
|
||||
* See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
|
||||
*/
|
||||
#ifndef ANNOTATE_HAPPENS_BEFORE
|
@ -48,16 +48,8 @@
|
||||
#endif /* win32 */
|
||||
|
||||
#if U_PLATFORM_IS_DARWIN_BASED
|
||||
#if defined(__STRICT_ANSI__)
|
||||
#define UPRV_REMAP_INLINE
|
||||
#define inline
|
||||
#endif
|
||||
#include <libkern/OSAtomic.h>
|
||||
#define USE_MAC_OS_ATOMIC_INCREMENT 1
|
||||
#if defined(UPRV_REMAP_INLINE)
|
||||
#undef inline
|
||||
#undef UPRV_REMAP_INLINE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -558,9 +558,9 @@ struct JSClass {
|
||||
//
|
||||
// Implementing this efficiently requires that global objects have classes
|
||||
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
// prevously allowed, but is now an ES5 violation and thus unsupported.
|
||||
// previously allowed, but is now an ES5 violation and thus unsupported.
|
||||
//
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 26)
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 26)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
@ -171,10 +171,10 @@ AC_DEFUN([MOZ_COMPILER_OPTS],
|
||||
|
||||
AC_SUBST(DEVELOPER_OPTIONS)
|
||||
|
||||
if test -n "$DEVELOPER_OPTIONS" -a "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
|
||||
if test "${MOZ_PSEUDO_DERECURSE-unset}" = unset; then
|
||||
dnl Don't enable on pymake, because of bug 918652. Bug 912979 is an annoyance
|
||||
dnl with pymake, too.
|
||||
MOZ_PSEUDO_DERECURSE=no-parallel-export,no-pymake,no-skip
|
||||
MOZ_PSEUDO_DERECURSE=no-pymake,no-skip
|
||||
fi
|
||||
|
||||
MOZ_DEBUGGING_OPTS
|
||||
|
@ -2038,7 +2038,7 @@ js_InitIntlClass(JSContext *cx, HandleObject obj)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MarkStandardClassInitializedNoProto(global, &IntlClass);
|
||||
global->markStandardClassInitializedNoProto(&IntlClass);
|
||||
|
||||
return Intl;
|
||||
}
|
||||
@ -2052,6 +2052,6 @@ GlobalObject::initIntlObject(JSContext *cx, Handle<GlobalObject*> global)
|
||||
if (!Intl)
|
||||
return false;
|
||||
|
||||
global->setReservedSlot(JSProto_Intl, ObjectValue(*Intl));
|
||||
global->setConstructor(JSProto_Intl, ObjectValue(*Intl));
|
||||
return true;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ ControlProfilers(bool toState)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (! Probes::ProfilingActive && toState) {
|
||||
if (! probes::ProfilingActive && toState) {
|
||||
#ifdef __APPLE__
|
||||
#if defined(MOZ_SHARK) || defined(MOZ_INSTRUMENTS)
|
||||
const char* profiler;
|
||||
@ -145,7 +145,7 @@ ControlProfilers(bool toState)
|
||||
ok = false;
|
||||
}
|
||||
#endif
|
||||
} else if (Probes::ProfilingActive && ! toState) {
|
||||
} else if (probes::ProfilingActive && ! toState) {
|
||||
#ifdef __APPLE__
|
||||
#ifdef MOZ_SHARK
|
||||
Shark::Stop();
|
||||
@ -162,7 +162,7 @@ ControlProfilers(bool toState)
|
||||
#endif
|
||||
}
|
||||
|
||||
Probes::ProfilingActive = toState;
|
||||
probes::ProfilingActive = toState;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ SetupAndGetPrototypeObjectForComplexTypeInstance(JSContext *cx,
|
||||
RootedValue complexTypePrototypePrototypeVal(cx);
|
||||
|
||||
if (!JSObject::getProperty(cx, complexTypeGlobal, complexTypeGlobal,
|
||||
cx->names().classPrototype, &complexTypePrototypeVal))
|
||||
cx->names().prototype, &complexTypePrototypeVal))
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(complexTypePrototypeVal.isObject()); // immutable binding
|
||||
@ -495,7 +495,7 @@ SetupAndGetPrototypeObjectForComplexTypeInstance(JSContext *cx,
|
||||
|
||||
if (!JSObject::getProperty(cx, complexTypePrototypeObj,
|
||||
complexTypePrototypeObj,
|
||||
cx->names().classPrototype,
|
||||
cx->names().prototype,
|
||||
&complexTypePrototypePrototypeVal))
|
||||
return nullptr;
|
||||
|
||||
@ -1333,7 +1333,7 @@ GlobalObject::initDataObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
DataCtor, DataProto))
|
||||
return false;
|
||||
|
||||
global->setReservedSlot(JSProto_Data, ObjectValue(*DataCtor));
|
||||
global->setConstructor(JSProto_Data, ObjectValue(*DataCtor));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1358,7 +1358,7 @@ GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
TypeCtor, TypeProto))
|
||||
return false;
|
||||
|
||||
global->setReservedSlot(JSProto_Type, ObjectValue(*TypeCtor));
|
||||
global->setConstructor(JSProto_Type, ObjectValue(*TypeCtor));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1369,7 +1369,7 @@ GlobalObject::initArrayTypeObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
global->createConstructor(cx, ArrayType::construct,
|
||||
cx->names().ArrayType, 2));
|
||||
|
||||
global->setReservedSlot(JSProto_ArrayTypeObject, ObjectValue(*ctor));
|
||||
global->setConstructor(JSProto_ArrayTypeObject, ObjectValue(*ctor));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1393,7 +1393,7 @@ SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey pr
|
||||
|
||||
RootedValue DataProtoVal(cx);
|
||||
if (!JSObject::getProperty(cx, DataObject, DataObject,
|
||||
cx->names().classPrototype, &DataProtoVal))
|
||||
cx->names().prototype, &DataProtoVal))
|
||||
return nullptr;
|
||||
|
||||
RootedObject DataProto(cx, &DataProtoVal.toObject());
|
||||
@ -1443,7 +1443,7 @@ InitType(JSContext *cx, HandleObject globalObj)
|
||||
|
||||
RootedValue protoVal(cx);
|
||||
if (!JSObject::getProperty(cx, ctor, ctor,
|
||||
cx->names().classPrototype, &protoVal))
|
||||
cx->names().prototype, &protoVal))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(protoVal.isObject());
|
||||
@ -1686,7 +1686,7 @@ BinaryBlock::createNull(JSContext *cx, HandleObject type, HandleValue owner)
|
||||
|
||||
RootedValue protoVal(cx);
|
||||
if (!JSObject::getProperty(cx, type, type,
|
||||
cx->names().classPrototype, &protoVal))
|
||||
cx->names().prototype, &protoVal))
|
||||
return nullptr;
|
||||
|
||||
RootedObject obj(cx,
|
||||
|
@ -1368,9 +1368,6 @@ ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleO
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!obj->getType(cx))
|
||||
return false;
|
||||
|
||||
types::EnsureTrackPropertyTypes(cx, obj, id);
|
||||
|
||||
if (val.isPrimitive()) {
|
||||
@ -5326,6 +5323,10 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *
|
||||
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
// Instantiate this global property, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx))
|
||||
types::EnsureTrackPropertyTypes(cx, global, NameToId(name));
|
||||
|
||||
// The property must be found, and it must be found as a normal data property.
|
||||
RootedShape shape(cx, global->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
@ -5383,6 +5384,10 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
|
||||
if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape))
|
||||
return true;
|
||||
|
||||
// Instantiate properties on singleton scope chain objects, for use during Ion compilation.
|
||||
if (scopeChain->hasSingletonType() && IsIonEnabled(cx))
|
||||
types::EnsureTrackPropertyTypes(cx, scopeChain, NameToId(name));
|
||||
|
||||
bool isFixedSlot;
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset);
|
||||
@ -5810,6 +5815,10 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
|
||||
|
||||
// Instantiate this property for singleton holders, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx))
|
||||
types::EnsureTrackPropertyTypes(cx, holder, NameToId(name));
|
||||
|
||||
ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native
|
||||
: ICStub::GetProp_NativePrototype;
|
||||
|
||||
@ -5919,6 +5928,10 @@ TryAttachStringGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallbac
|
||||
if (!stringProto)
|
||||
return false;
|
||||
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx))
|
||||
types::EnsureTrackPropertyTypes(cx, stringProto, NameToId(name));
|
||||
|
||||
// For now, only look for properties directly set on String.prototype
|
||||
RootedId propId(cx, NameToId(name));
|
||||
RootedShape shape(cx, stringProto->nativeLookup(cx, propId));
|
||||
@ -7465,6 +7478,11 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
|
||||
return true;
|
||||
}
|
||||
|
||||
// Keep track of the function's |prototype| property in type
|
||||
// information, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx))
|
||||
types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
|
||||
|
||||
IonSpew(IonSpew_BaselineIC,
|
||||
" Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)",
|
||||
fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno,
|
||||
|
@ -2151,7 +2151,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
|
||||
ExecutionMode executionMode = gen->info().executionMode();
|
||||
if (apply->hasSingleTarget()) {
|
||||
JSFunction *target = apply->getSingleTarget();
|
||||
if (!CanIonCompile(target, executionMode)) {
|
||||
if (target->isNative()) {
|
||||
if (!emitCallInvokeFunction(apply, copyreg))
|
||||
return false;
|
||||
emitPopArguments(apply, copyreg);
|
||||
|
@ -73,12 +73,6 @@ CanIonCompile(JSScript *script, ExecutionMode cmode)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CanIonCompile(JSFunction *fun, ExecutionMode cmode)
|
||||
{
|
||||
return fun->isInterpreted() && CanIonCompile(fun->nonLazyScript(), cmode);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CompilingOffThread(JSScript *script, ExecutionMode cmode)
|
||||
{
|
||||
|
@ -1922,7 +1922,7 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
|
||||
// Don't use GetAtomId here, we need to watch for SETPROP on
|
||||
// integer properties and bail out. We can't mark the aggregate
|
||||
// JSID_VOID type property as being in a definite slot.
|
||||
if (setprop->name() == cx->names().classPrototype ||
|
||||
if (setprop->name() == cx->names().prototype ||
|
||||
setprop->name() == cx->names().proto ||
|
||||
setprop->name() == cx->names().constructor)
|
||||
{
|
||||
|
@ -271,6 +271,13 @@ IonBuilder::canInlineTarget(JSFunction *target, bool constructing)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow constructing lazy scripts when performing the definite properties
|
||||
// analysis, as baseline has not been used to warm the caller up yet.
|
||||
if (target->isInterpretedLazy() && info().executionMode() == DefinitePropertiesAnalysis) {
|
||||
if (!target->getOrCreateScript(cx))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target->hasScript()) {
|
||||
IonSpew(IonSpew_Inlining, "Cannot inline due to lack of Non-Lazy script");
|
||||
return false;
|
||||
@ -4584,11 +4591,11 @@ IonBuilder::createThisScripted(MDefinition *callee)
|
||||
// and thus invalidation.
|
||||
MInstruction *getProto;
|
||||
if (!invalidatedIdempotentCache()) {
|
||||
MGetPropertyCache *getPropCache = MGetPropertyCache::New(callee, cx->names().classPrototype);
|
||||
MGetPropertyCache *getPropCache = MGetPropertyCache::New(callee, cx->names().prototype);
|
||||
getPropCache->setIdempotent();
|
||||
getProto = getPropCache;
|
||||
} else {
|
||||
MCallGetProperty *callGetProp = MCallGetProperty::New(callee, cx->names().classPrototype);
|
||||
MCallGetProperty *callGetProp = MCallGetProperty::New(callee, cx->names().prototype);
|
||||
callGetProp->setIdempotent();
|
||||
getProto = callGetProp;
|
||||
}
|
||||
@ -4610,7 +4617,7 @@ IonBuilder::getSingletonPrototype(JSFunction *target)
|
||||
if (targetType->unknownProperties())
|
||||
return nullptr;
|
||||
|
||||
jsid protoid = NameToId(cx->names().classPrototype);
|
||||
jsid protoid = NameToId(cx->names().prototype);
|
||||
types::HeapTypeSetKey protoProperty = targetType->property(protoid);
|
||||
|
||||
return protoProperty.singleton(constraints());
|
||||
@ -5447,7 +5454,7 @@ IonBuilder::jsop_initelem_array()
|
||||
needStub = true;
|
||||
} else if (!initializer->unknownProperties()) {
|
||||
types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID);
|
||||
if (!TypeSetIncludes(elemTypes.actualTypes, value->type(), value->resultTypeSet())) {
|
||||
if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
|
||||
elemTypes.freeze(constraints());
|
||||
needStub = true;
|
||||
}
|
||||
@ -5994,7 +6001,7 @@ IonBuilder::testSingletonProperty(JSObject *obj, JSObject *singleton,
|
||||
if (objType->unknownProperties())
|
||||
return true;
|
||||
|
||||
types::HeapTypeSetKey property = objType->property(idRoot);
|
||||
types::HeapTypeSetKey property = objType->property(NameToId(name), context());
|
||||
if (obj != holder) {
|
||||
if (property.notEmpty(constraints()))
|
||||
return true;
|
||||
@ -6076,7 +6083,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton,
|
||||
|
||||
if (object->unknownProperties())
|
||||
return true;
|
||||
types::HeapTypeSetKey property = object->property(NameToId(name));
|
||||
types::HeapTypeSetKey property = object->property(NameToId(name), context());
|
||||
if (property.notEmpty(constraints()))
|
||||
return true;
|
||||
|
||||
@ -6213,7 +6220,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject);
|
||||
Maybe<types::HeapTypeSetKey> propertyTypes;
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes.construct(staticType->property(id));
|
||||
propertyTypes.construct(staticType->property(id, context()));
|
||||
if (propertyTypes.ref().configured(constraints(), staticType)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
@ -6223,7 +6230,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
}
|
||||
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), staticType,
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), staticType,
|
||||
name, baseTypes, /* updateObserved = */ true);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
@ -6266,6 +6273,9 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
bool
|
||||
jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes)
|
||||
{
|
||||
if (!types)
|
||||
return inputTypes && inputTypes->empty();
|
||||
|
||||
switch (input) {
|
||||
case MIRType_Undefined:
|
||||
case MIRType_Null:
|
||||
@ -6324,7 +6334,7 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name)
|
||||
return jsop_setprop(name);
|
||||
}
|
||||
|
||||
if (!TypeSetIncludes(propertyTypes.actualTypes, value->type(), value->resultTypeSet()))
|
||||
if (!TypeSetIncludes(propertyTypes.maybeTypes(), value->type(), value->resultTypeSet()))
|
||||
return jsop_setprop(name);
|
||||
|
||||
current->pop();
|
||||
@ -6733,7 +6743,7 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
||||
// Emit GetElementCache.
|
||||
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), obj, nullptr, baseTypes);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), obj, nullptr, baseTypes);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
// Always add a barrier if the index might be a string, so that the cache
|
||||
@ -6782,7 +6792,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), obj, nullptr, baseTypes);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), obj, nullptr, baseTypes);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
|
||||
@ -7576,7 +7586,8 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
jsid id = NameToId(name);
|
||||
|
||||
*property = type->property(id);
|
||||
return property->actualTypes->definiteProperty() &&
|
||||
return property->maybeTypes() &&
|
||||
property->maybeTypes()->definiteProperty() &&
|
||||
!property->configured(constraints(), type);
|
||||
}
|
||||
|
||||
@ -7615,7 +7626,7 @@ TestTypeHasOwnProperty(types::TypeObjectKey *typeObj, PropertyName *name, bool &
|
||||
{
|
||||
cont = true;
|
||||
types::HeapTypeSetKey propSet = typeObj->property(NameToId(name));
|
||||
if (!propSet.actualTypes->empty())
|
||||
if (propSet.maybeTypes() && !propSet.maybeTypes()->empty())
|
||||
cont = false;
|
||||
// Note: Callers must explicitly freeze the property type set later on if optimizing.
|
||||
return true;
|
||||
@ -8032,7 +8043,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
||||
return emitted;
|
||||
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(),
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
|
||||
current->peek(-1), name, baseTypes);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
@ -8042,13 +8053,14 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
||||
|
||||
// Except when loading constants above, always use a call if we are doing
|
||||
// the definite properties analysis and not actually emitting code, to
|
||||
// simplify later analysis.
|
||||
if (info().executionMode() == DefinitePropertiesAnalysis) {
|
||||
// simplify later analysis. Also skip deeper analysis if there are no known
|
||||
// types for this operation, as it will always invalidate when executing.
|
||||
if (info().executionMode() == DefinitePropertiesAnalysis || baseTypes->empty()) {
|
||||
MDefinition *obj = current->pop();
|
||||
MCallGetProperty *call = MCallGetProperty::New(obj, name);
|
||||
current->add(call);
|
||||
current->push(call);
|
||||
return resumeAfter(call);
|
||||
return resumeAfter(call) && pushTypeBarrier(call, types, true);
|
||||
}
|
||||
|
||||
// Try to emit loads from known binary data blocks
|
||||
@ -8268,7 +8280,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
|
||||
useObj = guard;
|
||||
}
|
||||
|
||||
MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.actualTypes->definiteSlot());
|
||||
MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.maybeTypes()->definiteSlot());
|
||||
if (!barrier)
|
||||
fixed->setResultType(MIRTypeFromValueType(types->getKnownTypeTag()));
|
||||
|
||||
@ -8748,7 +8760,7 @@ IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
|
||||
if (!getDefiniteSlot(obj->resultTypeSet(), name, &property))
|
||||
return true;
|
||||
|
||||
MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.actualTypes->definiteSlot(), value);
|
||||
MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.maybeTypes()->definiteSlot(), value);
|
||||
current->add(fixed);
|
||||
current->push(value);
|
||||
|
||||
@ -9395,7 +9407,7 @@ IonBuilder::jsop_instanceof()
|
||||
break;
|
||||
|
||||
types::HeapTypeSetKey protoProperty =
|
||||
rhsType->property(NameToId(cx->names().classPrototype));
|
||||
rhsType->property(NameToId(cx->names().prototype));
|
||||
JSObject *protoObject = protoProperty.singleton(constraints());
|
||||
if (!protoObject)
|
||||
break;
|
||||
|
@ -690,6 +690,16 @@ class IonBuilder : public MIRGenerator
|
||||
return callerBuilder_ != nullptr;
|
||||
}
|
||||
|
||||
JSContext *context() {
|
||||
// JSContexts are only available to IonBuilder when running on the main
|
||||
// thread, which after bug 785905 will only occur when doing eager
|
||||
// analyses with no available baseline information. Until this bug is
|
||||
// completed, both the |cx| member and |context()| may be used.
|
||||
if (info().executionMode() == DefinitePropertiesAnalysis)
|
||||
return cx;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
||||
|
@ -554,7 +554,7 @@ HandleException(ResumeFromException *rfe)
|
||||
// the function has exited, so invoke the probe that a function
|
||||
// is exiting.
|
||||
JSScript *script = frames.script();
|
||||
Probes::exitScript(cx, script, script->function(), nullptr);
|
||||
probes::ExitScript(cx, script, script->function(), nullptr);
|
||||
if (!frames.more())
|
||||
break;
|
||||
++frames;
|
||||
@ -574,7 +574,7 @@ HandleException(ResumeFromException *rfe)
|
||||
|
||||
// Unwind profiler pseudo-stack
|
||||
JSScript *script = iter.script();
|
||||
Probes::exitScript(cx, script, script->function(), iter.baselineFrame());
|
||||
probes::ExitScript(cx, script, script->function(), iter.baselineFrame());
|
||||
// After this point, any pushed SPS frame would have been popped if it needed
|
||||
// to be. Unset the flag here so that if we call DebugEpilogue below,
|
||||
// it doesn't try to pop the SPS frame again.
|
||||
|
@ -1064,7 +1064,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
storePtr(ImmPtr(nullptr), Address(temp, ProfileEntry::offsetOfStackAddress()));
|
||||
|
||||
// Store 0 for PCIdx because that's what interpreter does.
|
||||
// (See Probes::enterScript, which calls spsProfiler.enter, which pushes an entry
|
||||
// (See probes::EnterScript, which calls spsProfiler.enter, which pushes an entry
|
||||
// with 0 pcIdx).
|
||||
store32(Imm32(0), Address(temp, ProfileEntry::offsetOfPCIdx()));
|
||||
|
||||
|
@ -221,7 +221,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
|
||||
|
||||
for (uint32_t i = 0; i < initLength; i++) {
|
||||
MDefinition *value = callInfo.getArg(i);
|
||||
if (!TypeSetIncludes(elemTypes.actualTypes, value->type(), value->resultTypeSet())) {
|
||||
if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
|
||||
elemTypes.freeze(constraints());
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
@ -332,7 +332,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
|
||||
bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
|
||||
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(),
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
|
||||
callInfo.thisArg(), nullptr, returnTypes);
|
||||
if (barrier)
|
||||
returnType = MIRType_Value;
|
||||
|
@ -2780,12 +2780,12 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
|
||||
// which are accounted for by type information, i.e. native data properties
|
||||
// and elements.
|
||||
|
||||
if (object->unknownProperties())
|
||||
if (object->unknownProperties() || observed->empty())
|
||||
return true;
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (!TypeSetIncludes(observed, MIRType_Value, property.actualTypes))
|
||||
if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
|
||||
return true;
|
||||
|
||||
// Type information for singleton objects is not required to reflect the
|
||||
@ -2807,7 +2807,8 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
|
||||
}
|
||||
|
||||
bool
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::StackTypeSet *observed, bool updateObserved)
|
||||
{
|
||||
@ -2820,11 +2821,18 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
if (!obj->isNative())
|
||||
break;
|
||||
|
||||
Value v;
|
||||
if (HasDataProperty(cx, obj, NameToId(name), &v)) {
|
||||
if (v.isUndefined())
|
||||
break;
|
||||
observed->addType(cx, types::GetValueType(v));
|
||||
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj);
|
||||
if (!typeObj->unknownProperties()) {
|
||||
types::HeapTypeSetKey property = typeObj->property(NameToId(name), propertycx);
|
||||
if (property.maybeTypes()) {
|
||||
types::TypeSet::TypeList types;
|
||||
if (!property.maybeTypes()->enumerateTypes(&types))
|
||||
return false;
|
||||
if (types.length()) {
|
||||
observed->addType(cx, types[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = obj->getProto();
|
||||
@ -2835,7 +2843,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
}
|
||||
|
||||
bool
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::StackTypeSet *observed)
|
||||
{
|
||||
@ -2850,7 +2859,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (object) {
|
||||
if (PropertyReadNeedsTypeBarrier(cx, constraints, object, name,
|
||||
if (PropertyReadNeedsTypeBarrier(cx, propertycx, constraints, object, name,
|
||||
observed, updateObserved))
|
||||
{
|
||||
return true;
|
||||
@ -2983,7 +2992,10 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
if (!property.maybeTypes())
|
||||
return false;
|
||||
|
||||
if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
return false;
|
||||
|
||||
// This freeze is not required for correctness, but ensures that we
|
||||
@ -2994,8 +3006,8 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
if (aggregateProperty.empty()) {
|
||||
aggregateProperty.construct(property);
|
||||
} else {
|
||||
if (!aggregateProperty.ref().actualTypes->isSubset(property.actualTypes) ||
|
||||
!property.actualTypes->isSubset(aggregateProperty.ref().actualTypes))
|
||||
if (!aggregateProperty.ref().maybeTypes()->isSubset(property.maybeTypes()) ||
|
||||
!property.maybeTypes()->isSubset(aggregateProperty.ref().maybeTypes()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -3030,7 +3042,7 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types =
|
||||
aggregateProperty.ref().actualTypes->clone(GetIonContext()->temp->lifoAlloc());
|
||||
aggregateProperty.ref().maybeTypes()->clone(GetIonContext()->temp->lifoAlloc());
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
@ -3085,7 +3097,7 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (!TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
|
||||
if (!TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
|
||||
// Either pobj or pvalue needs to be modified to filter out the
|
||||
// types which the value could have but are not in the property,
|
||||
// or a VM call is required. A VM call is always required if pobj
|
||||
@ -3117,10 +3129,10 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
continue;
|
||||
|
||||
if (!property.actualTypes->empty() || excluded)
|
||||
if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
|
||||
return true;
|
||||
excluded = object->isTypeObject() ? object->asTypeObject() : object->asSingleObject()->getType(GetIonContext()->cx);
|
||||
}
|
||||
|
@ -8993,10 +8993,12 @@ bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefiniti
|
||||
bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj);
|
||||
MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj);
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::StackTypeSet *observed, bool updateObserved);
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::StackTypeSet *observed);
|
||||
bool PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
|
@ -716,7 +716,7 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, bool ok)
|
||||
if (frame->hasPushedSPSFrame()) {
|
||||
cx->runtime()->spsProfiler.exit(cx, frame->script(), frame->maybeFun());
|
||||
// Unset the pushedSPSFrame flag because DebugEpilogue may get called before
|
||||
// Probes::exitScript in baseline during exception handling, and we don't
|
||||
// probes::ExitScript in baseline during exception handling, and we don't
|
||||
// want to double-pop SPS frames.
|
||||
frame->unsetPushedSPSFrame();
|
||||
}
|
||||
|
@ -1553,6 +1553,7 @@ JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *reso
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id);
|
||||
JS_ASSERT(obj->is<GlobalObject>());
|
||||
*resolved = false;
|
||||
|
||||
rt = cx->runtime();
|
||||
@ -1622,11 +1623,10 @@ JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *reso
|
||||
* If this standard class is anonymous, then we don't want to resolve
|
||||
* by name.
|
||||
*/
|
||||
JS_ASSERT(obj->is<GlobalObject>());
|
||||
if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
|
||||
return true;
|
||||
|
||||
if (IsStandardClassResolved(obj, stdnm->clasp))
|
||||
if (obj->as<GlobalObject>().isStandardClassResolved(stdnm->clasp))
|
||||
return true;
|
||||
|
||||
if (!stdnm->init(cx, obj))
|
||||
@ -1642,6 +1642,7 @@ JS_EnumerateStandardClasses(JSContext *cx, HandleObject obj)
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
MOZ_ASSERT(obj->is<GlobalObject>());
|
||||
|
||||
/*
|
||||
* Check whether we need to bind 'undefined' and define it if so.
|
||||
@ -1659,7 +1660,7 @@ JS_EnumerateStandardClasses(JSContext *cx, HandleObject obj)
|
||||
/* Initialize any classes that have not been initialized yet. */
|
||||
for (unsigned i = 0; standard_class_atoms[i].init; i++) {
|
||||
const JSStdName &stdnm = standard_class_atoms[i];
|
||||
if (!js::IsStandardClassResolved(obj, stdnm.clasp)) {
|
||||
if (!obj->as<GlobalObject>().isStandardClassResolved(stdnm.clasp)) {
|
||||
if (!stdnm.init(cx, obj))
|
||||
return false;
|
||||
}
|
||||
|
@ -3192,7 +3192,7 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
if (allocateCapacity && !EnsureNewArrayElements(cxArg, arr, length))
|
||||
return nullptr;
|
||||
|
||||
Probes::createObject(cxArg, arr);
|
||||
probes::CreateObject(cxArg, arr);
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
@ -537,7 +537,7 @@ Exception(JSContext *cx, unsigned argc, Value *vp)
|
||||
*/
|
||||
RootedObject callee(cx, &args.callee());
|
||||
RootedValue protov(cx);
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
return false;
|
||||
|
||||
if (!protov.isObject()) {
|
||||
|
@ -165,7 +165,7 @@ fun_enumerate(JSContext *cx, HandleObject obj)
|
||||
bool found;
|
||||
|
||||
if (!obj->isBoundFunction()) {
|
||||
id = NameToId(cx->names().classPrototype);
|
||||
id = NameToId(cx->names().prototype);
|
||||
if (!JSObject::hasProperty(cx, obj, id, &found, 0))
|
||||
return false;
|
||||
}
|
||||
@ -224,7 +224,7 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
|
||||
// Per ES5 15.3.5.2 a user-defined function's .prototype property is
|
||||
// initially non-configurable, non-enumerable, and writable.
|
||||
RootedValue protoVal(cx, ObjectValue(*proto));
|
||||
if (!JSObject::defineProperty(cx, obj, cx->names().classPrototype,
|
||||
if (!JSObject::defineProperty(cx, obj, cx->names().prototype,
|
||||
protoVal, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT))
|
||||
{
|
||||
@ -256,7 +256,7 @@ js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
|
||||
RootedFunction fun(cx, &obj->as<JSFunction>());
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->names().classPrototype)) {
|
||||
if (JSID_IS_ATOM(id, cx->names().prototype)) {
|
||||
/*
|
||||
* Built-in functions do not have a .prototype property per ECMA-262,
|
||||
* or (Object.prototype, Function.prototype, etc.) have that property
|
||||
@ -474,7 +474,7 @@ fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, bool *
|
||||
obj = obj->as<JSFunction>().getBoundFunctionTarget();
|
||||
|
||||
RootedValue pval(cx);
|
||||
if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))
|
||||
if (!JSObject::getProperty(cx, obj, obj, cx->names().prototype, &pval))
|
||||
return false;
|
||||
|
||||
if (pval.isPrimitive()) {
|
||||
|
@ -49,7 +49,7 @@ using mozilla::PodZero;
|
||||
|
||||
static inline jsid
|
||||
id_prototype(JSContext *cx) {
|
||||
return NameToId(cx->names().classPrototype);
|
||||
return NameToId(cx->names().prototype);
|
||||
}
|
||||
|
||||
static inline jsid
|
||||
@ -336,6 +336,39 @@ TypeSet::isSubset(TypeSet *other)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeSet::enumerateTypes(TypeList *list)
|
||||
{
|
||||
/* If any type is possible, there's no need to worry about specifics. */
|
||||
if (flags & TYPE_FLAG_UNKNOWN)
|
||||
return list->append(Type::UnknownType());
|
||||
|
||||
/* Enqueue type set members stored as bits. */
|
||||
for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
|
||||
if (flags & flag) {
|
||||
Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
|
||||
if (!list->append(type))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If any object is possible, skip specifics. */
|
||||
if (flags & TYPE_FLAG_ANYOBJECT)
|
||||
return list->append(Type::AnyObjectType());
|
||||
|
||||
/* Enqueue specific object types. */
|
||||
unsigned count = getObjectCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
TypeObjectKey *object = getObject(i);
|
||||
if (object) {
|
||||
if (!list->append(Type::ObjectType(object)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
|
||||
{
|
||||
@ -343,38 +376,9 @@ TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
|
||||
* Build all types in the set into a vector before triggering the
|
||||
* constraint, as doing so may modify this type set.
|
||||
*/
|
||||
Vector<Type> types(cx);
|
||||
|
||||
/* If any type is possible, there's no need to worry about specifics. */
|
||||
if (flags & TYPE_FLAG_UNKNOWN) {
|
||||
if (!types.append(Type::UnknownType()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
} else {
|
||||
/* Enqueue type set members stored as bits. */
|
||||
for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
|
||||
if (flags & flag) {
|
||||
Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
|
||||
if (!types.append(type))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
|
||||
/* If any object is possible, skip specifics. */
|
||||
if (flags & TYPE_FLAG_ANYOBJECT) {
|
||||
if (!types.append(Type::AnyObjectType()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
} else {
|
||||
/* Enqueue specific object types. */
|
||||
unsigned count = getObjectCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
TypeObjectKey *object = getObject(i);
|
||||
if (object) {
|
||||
if (!types.append(Type::ObjectType(object)))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeList types;
|
||||
if (!enumerateTypes(&types))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
|
||||
for (unsigned i = 0; i < types.length(); i++)
|
||||
constraint->newType(cx, this, types[i]);
|
||||
@ -566,10 +570,8 @@ class types::CompilerConstraint
|
||||
|
||||
CompilerConstraint(const HeapTypeSetKey &property)
|
||||
: property(property),
|
||||
expected(property.actualTypes->clone(IonAlloc()))
|
||||
{
|
||||
// Note: CompilerConstraintList::add watches for OOM under clone().
|
||||
}
|
||||
expected(property.maybeTypes() ? property.maybeTypes()->clone(IonAlloc()) : NULL)
|
||||
{}
|
||||
|
||||
// Generate the type constraint recording the assumption made by this
|
||||
// compilation. Returns true if the assumption originally made still holds.
|
||||
@ -580,7 +582,7 @@ void
|
||||
CompilerConstraintList::add(CompilerConstraint *constraint)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
if (!constraint || !constraint->expected || !constraints.append(constraint))
|
||||
if (!constraint || !constraints.append(constraint))
|
||||
setFailed();
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
@ -641,14 +643,17 @@ template <typename T>
|
||||
bool
|
||||
CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
|
||||
{
|
||||
if (property.actualObject->unknownProperties())
|
||||
if (property.object()->unknownProperties())
|
||||
return false;
|
||||
|
||||
if (!property.instantiate(cx))
|
||||
return false;
|
||||
|
||||
if (!data.constraintHolds(cx, property, expected))
|
||||
return false;
|
||||
|
||||
property.actualTypes->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -683,37 +688,62 @@ TypeObjectKey::newScript()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeObject *
|
||||
TypeObjectKey::maybeType()
|
||||
{
|
||||
if (isTypeObject())
|
||||
return asTypeObject();
|
||||
if (asSingleObject()->hasLazyType())
|
||||
return NULL;
|
||||
return asSingleObject()->type();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeObjectKey::unknownProperties()
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
return type->unknownProperties();
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
if (TypeObject *type = maybeType())
|
||||
return type->unknownProperties();
|
||||
return false;
|
||||
}
|
||||
|
||||
HeapTypeSetKey
|
||||
TypeObjectKey::property(jsid id)
|
||||
TypeObjectKey::property(jsid id, JSContext *maybecx /* = NULL */)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
JS_ASSERT(!unknownProperties());
|
||||
|
||||
HeapTypeSetKey property;
|
||||
property.actualObject = type;
|
||||
property.actualTypes = type->getProperty(cx, id);
|
||||
if (!property.actualTypes)
|
||||
MOZ_CRASH();
|
||||
property.object_ = this;
|
||||
property.id_ = id;
|
||||
if (TypeObject *type = maybeType())
|
||||
property.maybeTypes_ = type->maybeGetProperty(id);
|
||||
|
||||
#ifdef JS_ION
|
||||
// If we are accessing a lazily defined property which actually exists in
|
||||
// the VM and has not been instantiated yet, instantiate it now if we are
|
||||
// on the main thread and able to do so.
|
||||
if (maybecx && !property.maybeTypes() && !JSID_IS_VOID(id) && !JSID_IS_EMPTY(id)) {
|
||||
JS_ASSERT(CurrentThreadCanAccessRuntime(maybecx->runtime()));
|
||||
JSObject *singleton = isSingleObject() ? asSingleObject() : asTypeObject()->singleton;
|
||||
if (singleton && singleton->isNative() && singleton->nativeLookupPure(id)) {
|
||||
EnsureTrackPropertyTypes(maybecx, singleton, id);
|
||||
if (TypeObject *type = maybeType())
|
||||
property.maybeTypes_ = type->maybeGetProperty(id);
|
||||
}
|
||||
}
|
||||
#endif // JS_ION
|
||||
|
||||
return property;
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
HeapTypeSetKey::instantiate(JSContext *cx)
|
||||
{
|
||||
if (maybeTypes())
|
||||
return true;
|
||||
if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx))
|
||||
return false;
|
||||
maybeTypes_ = object()->maybeType()->getProperty(cx, id());
|
||||
return maybeTypes_ != NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -738,12 +768,17 @@ types::FinishCompilation(JSContext *cx, JSScript *script, ExecutionMode executio
|
||||
|
||||
*precompileInfo = RecompileInfo(index);
|
||||
|
||||
bool succeeded = true;
|
||||
|
||||
for (size_t i = 0; i < constraints->length(); i++) {
|
||||
CompilerConstraint *constraint = constraints->get(i);
|
||||
if (!constraint->generateTypeConstraint(cx, *precompileInfo)) {
|
||||
types.constrainedOutputs->back().invalidate();
|
||||
return false;
|
||||
}
|
||||
if (!constraint->generateTypeConstraint(cx, *precompileInfo))
|
||||
succeeded = false;
|
||||
}
|
||||
|
||||
if (!succeeded) {
|
||||
types.constrainedOutputs->back().invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -766,7 +801,9 @@ class ConstraintDataFreeze
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return property.actualTypes->isSubset(expected);
|
||||
return expected
|
||||
? property.maybeTypes()->isSubset(expected)
|
||||
: property.maybeTypes()->empty();
|
||||
}
|
||||
};
|
||||
|
||||
@ -842,13 +879,15 @@ TemporaryTypeSet::mightBeType(JSValueType type)
|
||||
JSValueType
|
||||
HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (actualTypes->unknown())
|
||||
TypeSet *types = maybeTypes();
|
||||
|
||||
if (!types || types->unknown())
|
||||
return JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
TypeFlags flags = actualTypes->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
|
||||
TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
|
||||
JSValueType type;
|
||||
|
||||
if (actualTypes->unknownObject() || actualTypes->getObjectCount())
|
||||
if (types->unknownObject() || types->getObjectCount())
|
||||
type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
|
||||
else
|
||||
type = GetValueTypeFromTypeFlags(flags);
|
||||
@ -863,7 +902,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
|
||||
* that the exact tag is unknown, as it will stay unknown as more types are
|
||||
* added to the set.
|
||||
*/
|
||||
JS_ASSERT_IF(actualTypes->empty(), type == JSVAL_TYPE_UNKNOWN);
|
||||
JS_ASSERT_IF(types->empty(), type == JSVAL_TYPE_UNKNOWN);
|
||||
|
||||
return type;
|
||||
}
|
||||
@ -871,7 +910,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
|
||||
bool
|
||||
HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (!actualTypes->empty())
|
||||
if (maybeTypes() && !maybeTypes()->empty())
|
||||
return true;
|
||||
freeze(constraints);
|
||||
return false;
|
||||
@ -880,7 +919,11 @@ HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
|
||||
bool
|
||||
HeapTypeSetKey::knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other)
|
||||
{
|
||||
if (!actualTypes->isSubset(other.actualTypes))
|
||||
if (!maybeTypes() || maybeTypes()->empty()) {
|
||||
freeze(constraints);
|
||||
return true;
|
||||
}
|
||||
if (!other.maybeTypes() || !maybeTypes()->isSubset(other.maybeTypes()))
|
||||
return false;
|
||||
freeze(constraints);
|
||||
return true;
|
||||
@ -898,10 +941,12 @@ TemporaryTypeSet::getSingleton()
|
||||
JSObject *
|
||||
HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (actualTypes->baseFlags() != 0 || actualTypes->getObjectCount() != 1)
|
||||
TypeSet *types = maybeTypes();
|
||||
|
||||
if (!types || types->baseFlags() != 0 || types->getObjectCount() != 1)
|
||||
return nullptr;
|
||||
|
||||
JSObject *obj = actualTypes->getSingleObject(0);
|
||||
JSObject *obj = types->getSingleObject(0);
|
||||
|
||||
if (obj)
|
||||
freeze(constraints);
|
||||
@ -912,9 +957,12 @@ HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
|
||||
bool
|
||||
HeapTypeSetKey::needsBarrier(CompilerConstraintList *constraints)
|
||||
{
|
||||
bool result = actualTypes->unknownObject()
|
||||
|| actualTypes->getObjectCount() > 0
|
||||
|| actualTypes->hasAnyFlag(TYPE_FLAG_STRING);
|
||||
TypeSet *types = maybeTypes();
|
||||
if (!types)
|
||||
return false;
|
||||
bool result = types->unknownObject()
|
||||
|| types->getObjectCount() > 0
|
||||
|| types->hasAnyFlag(TYPE_FLAG_STRING);
|
||||
if (!result)
|
||||
freeze(constraints);
|
||||
return result;
|
||||
@ -946,7 +994,7 @@ class ConstraintDataFreezeObjectFlags
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
return !invalidateOnNewObjectState(property.object()->maybeType());
|
||||
}
|
||||
};
|
||||
|
||||
@ -955,22 +1003,16 @@ class ConstraintDataFreezeObjectFlags
|
||||
bool
|
||||
TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JS_ASSERT(flags);
|
||||
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
if (type->hasAnyFlags(flags))
|
||||
return true;
|
||||
if (TypeObject *type = maybeType()) {
|
||||
if (type->hasAnyFlags(flags))
|
||||
return true;
|
||||
}
|
||||
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags)));
|
||||
return false;
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1047,7 +1089,7 @@ class ConstraintDataFreezeObjectForNewScriptTemplate
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
return !invalidateOnNewObjectState(property.object()->maybeType());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1073,7 +1115,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
return !invalidateOnNewObjectState(property.object()->maybeType());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1170,7 +1212,7 @@ class ConstraintDataFreezeConfiguredProperty
|
||||
}
|
||||
}
|
||||
|
||||
return !property.actualTypes->configuredProperty();
|
||||
return !property.maybeTypes()->configuredProperty();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1179,7 +1221,7 @@ class ConstraintDataFreezeConfiguredProperty
|
||||
bool
|
||||
HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *type)
|
||||
{
|
||||
if (actualTypes->configuredProperty())
|
||||
if (maybeTypes() && maybeTypes()->configuredProperty())
|
||||
return true;
|
||||
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeConfiguredProperty> >(*this, ConstraintDataFreezeConfiguredProperty(type)));
|
||||
@ -1255,7 +1297,8 @@ TemporaryTypeSet::convertDoubleElements(CompilerConstraintList *constraints)
|
||||
// double in their element types (as the conversion may render the type
|
||||
// information incorrect), nor for non-array objects (as their elements
|
||||
// may point to emptyObjectElements, which cannot be converted).
|
||||
if (!property.actualTypes->hasType(Type::DoubleType()) ||
|
||||
if (!property.maybeTypes() ||
|
||||
!property.maybeTypes()->hasType(Type::DoubleType()) ||
|
||||
type->clasp() != &ArrayObject::class_)
|
||||
{
|
||||
dontConvert = true;
|
||||
@ -1763,15 +1806,9 @@ bool
|
||||
types::ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints,
|
||||
HandleScript script)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSObject *proto = script->global().getOrCreateArrayPrototype(jit::GetIonContext()->cx);
|
||||
if (!proto)
|
||||
return true;
|
||||
|
||||
return PrototypeHasIndexedProperty(constraints, proto);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
if (JSObject *proto = script->global().maybeGetArrayPrototype())
|
||||
return PrototypeHasIndexedProperty(constraints, proto);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -177,8 +177,7 @@ namespace types {
|
||||
|
||||
class TypeCompartment;
|
||||
class TypeSet;
|
||||
|
||||
struct TypeObjectKey;
|
||||
class TypeObjectKey;
|
||||
|
||||
/*
|
||||
* Information about a single concrete type. We pack this into a single word,
|
||||
@ -543,6 +542,10 @@ class TypeSet
|
||||
/* Mark this type set as representing a configured property. */
|
||||
inline void setConfiguredProperty(ExclusiveContext *cx);
|
||||
|
||||
/* Get a list of all types in this set. */
|
||||
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
|
||||
bool enumerateTypes(TypeList *list);
|
||||
|
||||
/*
|
||||
* Iterate through the objects in this set. getObjectCount overapproximates
|
||||
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
|
||||
@ -1219,8 +1222,9 @@ typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,Sy
|
||||
|
||||
class HeapTypeSetKey;
|
||||
|
||||
/* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
|
||||
struct TypeObjectKey {
|
||||
// Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
|
||||
struct TypeObjectKey
|
||||
{
|
||||
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
|
||||
static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
|
||||
|
||||
@ -1259,14 +1263,40 @@ struct TypeObjectKey {
|
||||
void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints);
|
||||
HeapTypeSetKey property(jsid id);
|
||||
HeapTypeSetKey property(jsid id, JSContext *maybecx = NULL);
|
||||
|
||||
TypeObject *maybeType();
|
||||
};
|
||||
|
||||
// Representation of a heap type property which may or may not be instantiated.
|
||||
// Heap properties for singleton types are instantiated lazily as they are used
|
||||
// by the compiler, but this is only done on the main thread. If we are
|
||||
// compiling off thread and use a property which has not yet been instantiated,
|
||||
// it will be treated as empty and non-configured and will be instantiated when
|
||||
// rejoining to the main thread. If it is in fact not empty, the compilation
|
||||
// will fail; to avoid this, we try to instantiate singleton property types
|
||||
// during generation of baseline caches.
|
||||
class HeapTypeSetKey
|
||||
{
|
||||
friend class TypeObjectKey;
|
||||
|
||||
// Object and property being accessed.
|
||||
TypeObjectKey *object_;
|
||||
jsid id_;
|
||||
|
||||
// If instantiated, the underlying heap type set.
|
||||
HeapTypeSet *maybeTypes_;
|
||||
|
||||
public:
|
||||
TypeObject *actualObject;
|
||||
HeapTypeSet *actualTypes;
|
||||
HeapTypeSetKey()
|
||||
: object_(NULL), id_(JSID_EMPTY), maybeTypes_(NULL)
|
||||
{}
|
||||
|
||||
TypeObjectKey *object() const { return object_; }
|
||||
jsid id() const { return id_; }
|
||||
HeapTypeSet *maybeTypes() const { return maybeTypes_; }
|
||||
|
||||
bool instantiate(JSContext *cx);
|
||||
|
||||
void freeze(CompilerConstraintList *constraints);
|
||||
JSValueType knownTypeTag(CompilerConstraintList *constraints);
|
||||
|
@ -422,16 +422,19 @@ TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
|
||||
inline void
|
||||
EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
JS_ASSERT(!obj->hasLazyType());
|
||||
|
||||
if (!cx->typeInferenceEnabled() || obj->type()->unknownProperties())
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return;
|
||||
|
||||
id = IdToTypeId(id);
|
||||
|
||||
if (obj->hasSingletonType()) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
obj->type()->getProperty(cx, id);
|
||||
if (obj->hasLazyType() && !obj->getType(cx)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
if (!obj->type()->unknownProperties())
|
||||
obj->type()->getProperty(cx, id);
|
||||
}
|
||||
|
||||
JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
|
||||
|
@ -1557,7 +1557,7 @@ js_NewGenerator(JSContext *cx, const FrameRegs &stackRegs)
|
||||
RootedObject fun(cx, stackfp->fun());
|
||||
// FIXME: This would be faster if we could avoid doing a lookup to get
|
||||
// the prototype for the instance. Bug 906600.
|
||||
if (!JSObject::getProperty(cx, fun, fun, cx->names().classPrototype, &pval))
|
||||
if (!JSObject::getProperty(cx, fun, fun, cx->names().prototype, &pval))
|
||||
return nullptr;
|
||||
JSObject *proto = pval.isObject() ? &pval.toObject() : nullptr;
|
||||
if (!proto) {
|
||||
@ -1949,8 +1949,8 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
return false;
|
||||
|
||||
global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
|
||||
global->setSlot(JSProto_GeneratorFunction, ObjectValue(*genFunction));
|
||||
global->setSlot(JSProto_GeneratorFunction + JSProto_LIMIT, ObjectValue(*genFunctionProto));
|
||||
global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
|
||||
global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
|
||||
}
|
||||
|
||||
if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
|
||||
@ -1962,7 +1962,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
if (!DefineConstructorAndPrototype(cx, global, JSProto_StopIteration, proto, proto))
|
||||
return false;
|
||||
|
||||
MarkStandardClassInitializedNoProto(global, &StopIterationObject::class_);
|
||||
global->markStandardClassInitializedNoProto(&StopIterationObject::class_);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1495,7 +1495,7 @@ js_InitMathClass(JSContext *cx, HandleObject obj)
|
||||
if (!JS_DefineConstDoubles(cx, Math, math_constants))
|
||||
return nullptr;
|
||||
|
||||
MarkStandardClassInitializedNoProto(obj, &MathClass);
|
||||
obj->as<GlobalObject>().markStandardClassInitializedNoProto(&MathClass);
|
||||
|
||||
return Math;
|
||||
}
|
||||
|
@ -1309,7 +1309,7 @@ NewObject(ExclusiveContext *cx, const Class *clasp, types::TypeObject *type_, JS
|
||||
#endif
|
||||
}
|
||||
|
||||
Probes::createObject(cx, obj);
|
||||
probes::CreateObject(cx, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -1543,7 +1543,7 @@ JSObject*
|
||||
js::CreateThis(JSContext *cx, const Class *newclasp, HandleObject callee)
|
||||
{
|
||||
RootedValue protov(cx);
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
return nullptr;
|
||||
|
||||
JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : nullptr;
|
||||
@ -1608,7 +1608,7 @@ JSObject *
|
||||
js::CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
|
||||
{
|
||||
RootedValue protov(cx);
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
return nullptr;
|
||||
JSObject *proto;
|
||||
if (protov.isObject())
|
||||
@ -2186,8 +2186,9 @@ DefineStandardSlot(JSContext *cx, HandleObject obj, JSProtoKey key, JSAtom *atom
|
||||
JS_ASSERT(obj->isNative());
|
||||
|
||||
if (!obj->nativeLookup(cx, id)) {
|
||||
uint32_t slot = 2 * JSProto_LIMIT + key;
|
||||
obj->setReservedSlot(slot, v);
|
||||
obj->as<GlobalObject>().setConstructorPropertySlot(key, v);
|
||||
|
||||
uint32_t slot = GlobalObject::constructorPropertySlot(key);
|
||||
if (!JSObject::addProperty(cx, obj, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0))
|
||||
return false;
|
||||
AddTypePropertyId(cx, obj, id, v);
|
||||
@ -2209,8 +2210,8 @@ SetClassObject(JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto)
|
||||
if (!obj->is<GlobalObject>())
|
||||
return;
|
||||
|
||||
obj->setReservedSlot(key, ObjectOrNullValue(cobj));
|
||||
obj->setReservedSlot(JSProto_LIMIT + key, ObjectOrNullValue(proto));
|
||||
obj->as<GlobalObject>().setConstructor(key, ObjectOrNullValue(cobj));
|
||||
obj->as<GlobalObject>().setPrototype(key, ObjectOrNullValue(proto));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2220,8 +2221,8 @@ ClearClassObject(JSObject *obj, JSProtoKey key)
|
||||
if (!obj->is<GlobalObject>())
|
||||
return;
|
||||
|
||||
obj->setSlot(key, UndefinedValue());
|
||||
obj->setSlot(JSProto_LIMIT + key, UndefinedValue());
|
||||
obj->as<GlobalObject>().setConstructor(key, UndefinedValue());
|
||||
obj->as<GlobalObject>().setPrototype(key, UndefinedValue());
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -2361,37 +2362,6 @@ bad:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lazy standard classes need a way to indicate if they have been initialized.
|
||||
* Otherwise, when we delete them, we might accidentally recreate them via a
|
||||
* lazy initialization. We use the presence of a ctor or proto in the
|
||||
* global object's slot to indicate that they've been constructed, but this only
|
||||
* works for classes which have a proto and ctor. Classes which don't have one
|
||||
* can call MarkStandardClassInitializedNoProto(), and we can always check
|
||||
* whether a class is initialized by calling IsStandardClassResolved().
|
||||
*/
|
||||
bool
|
||||
js::IsStandardClassResolved(JSObject *obj, const js::Class *clasp)
|
||||
{
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
|
||||
/* If the constructor is undefined, then it hasn't been initialized. */
|
||||
return (obj->getReservedSlot(key) != UndefinedValue());
|
||||
}
|
||||
|
||||
void
|
||||
js::MarkStandardClassInitializedNoProto(JSObject *obj, const js::Class *clasp)
|
||||
{
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
|
||||
/*
|
||||
* We use True so that it's obvious what we're doing (instead of, say,
|
||||
* Null, which might be miscontrued as an error in setting Undefined).
|
||||
*/
|
||||
if (obj->getReservedSlot(key) == UndefinedValue())
|
||||
obj->setSlot(key, BooleanValue(true));
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto_,
|
||||
const Class *clasp, Native constructor, unsigned nargs,
|
||||
@ -3044,13 +3014,9 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj,
|
||||
bool
|
||||
js_GetClassObject(ExclusiveContext *cxArg, JSObject *obj, JSProtoKey key, MutableHandleObject objp)
|
||||
{
|
||||
RootedObject global(cxArg, &obj->global());
|
||||
if (!global->is<GlobalObject>()) {
|
||||
objp.set(nullptr);
|
||||
return true;
|
||||
}
|
||||
Rooted<GlobalObject*> global(cxArg, &obj->global());
|
||||
|
||||
Value v = global->getReservedSlot(key);
|
||||
Value v = global->getConstructor(key);
|
||||
if (v.isObject()) {
|
||||
objp.set(&v.toObject());
|
||||
return true;
|
||||
@ -3074,7 +3040,7 @@ js_GetClassObject(ExclusiveContext *cxArg, JSObject *obj, JSProtoKey key, Mutabl
|
||||
if (ClassInitializerOp init = lazy_prototype_init[key]) {
|
||||
if (!init(cx, global))
|
||||
return false;
|
||||
v = global->getReservedSlot(key);
|
||||
v = global->getConstructor(key);
|
||||
if (v.isObject())
|
||||
cobj = &v.toObject();
|
||||
}
|
||||
@ -3097,8 +3063,8 @@ js_IdentifyClassPrototype(JSObject *obj)
|
||||
//
|
||||
// Note that standard class objects are cached in the range [0, JSProto_LIMIT),
|
||||
// and the prototypes are cached in [JSProto_LIMIT, 2*JSProto_LIMIT).
|
||||
JSObject &global = obj->global();
|
||||
Value v = global.getReservedSlot(JSProto_LIMIT + key);
|
||||
GlobalObject &global = obj->global();
|
||||
Value v = global.getPrototype(key);
|
||||
if (v.isObject() && obj == &v.toObject())
|
||||
return key;
|
||||
|
||||
@ -5239,7 +5205,7 @@ js::GetClassPrototypePure(GlobalObject *global, JSProtoKey protoKey)
|
||||
JS_ASSERT(protoKey < JSProto_LIMIT);
|
||||
|
||||
if (protoKey != JSProto_Null) {
|
||||
const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
|
||||
const Value &v = global->getPrototype(protoKey);
|
||||
if (v.isObject())
|
||||
return &v.toObject();
|
||||
}
|
||||
@ -5268,12 +5234,12 @@ js_GetClassPrototype(ExclusiveContext *cx, JSProtoKey protoKey,
|
||||
RootedObject ctor(cx, &v.get().toObject());
|
||||
if (cx->isJSContext()) {
|
||||
if (!JSObject::getProperty(cx->asJSContext(),
|
||||
ctor, ctor, cx->names().classPrototype, &v))
|
||||
ctor, ctor, cx->names().prototype, &v))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Shape *shape = ctor->nativeLookup(cx, cx->names().classPrototype);
|
||||
Shape *shape = ctor->nativeLookup(cx, cx->names().prototype);
|
||||
if (!shape || !NativeGetPureInline(ctor, shape, v.address()))
|
||||
return false;
|
||||
}
|
||||
|
@ -1251,12 +1251,6 @@ HasOwnProperty(JSContext *cx, LookupGenericOp lookup,
|
||||
typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
|
||||
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
|
||||
|
||||
bool
|
||||
IsStandardClassResolved(JSObject *obj, const js::Class *clasp);
|
||||
|
||||
void
|
||||
MarkStandardClassInitializedNoProto(JSObject *obj, const js::Class *clasp);
|
||||
|
||||
typedef JSObject *(*ClassInitializerOp)(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -75,7 +75,7 @@ JSObject::deleteSpecial(JSContext *cx, js::HandleObject obj, js::HandleSpecialId
|
||||
inline void
|
||||
JSObject::finalize(js::FreeOp *fop)
|
||||
{
|
||||
js::Probes::finalizeObject(this);
|
||||
js::probes::FinalizeObject(this);
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(isTenured());
|
||||
@ -936,15 +936,15 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
|
||||
JS_ASSERT(!global->nativeLookup(cx, id));
|
||||
|
||||
/* Set these first in case AddTypePropertyId looks for this class. */
|
||||
global->setSlot(key, ObjectValue(*ctor));
|
||||
global->setSlot(key + JSProto_LIMIT, ObjectValue(*proto));
|
||||
global->setSlot(key + JSProto_LIMIT * 2, ObjectValue(*ctor));
|
||||
global->setConstructor(key, ObjectValue(*ctor));
|
||||
global->setPrototype(key, ObjectValue(*proto));
|
||||
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
|
||||
|
||||
types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
|
||||
if (!global->addDataProperty(cx, id, key + JSProto_LIMIT * 2, 0)) {
|
||||
global->setSlot(key, UndefinedValue());
|
||||
global->setSlot(key + JSProto_LIMIT, UndefinedValue());
|
||||
global->setSlot(key + JSProto_LIMIT * 2, UndefinedValue());
|
||||
if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {
|
||||
global->setConstructor(key, UndefinedValue());
|
||||
global->setPrototype(key, UndefinedValue());
|
||||
global->setConstructorPropertySlot(key, UndefinedValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -886,7 +886,7 @@ js_InitJSONClass(JSContext *cx, HandleObject obj)
|
||||
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
|
||||
return nullptr;
|
||||
|
||||
MarkStandardClassInitializedNoProto(global, &JSONClass);
|
||||
global->markStandardClassInitializedNoProto(&JSONClass);
|
||||
|
||||
return JSON;
|
||||
}
|
||||
|
@ -3293,7 +3293,7 @@ static const JSFunctionSpec static_methods[] = {
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
Rooted<GlobalObject*> global(cx);
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
RootedFunction ctor(cx);
|
||||
ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2);
|
||||
if (!ctor)
|
||||
@ -3306,6 +3306,6 @@ js_InitProxyClass(JSContext *cx, HandleObject obj)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MarkStandardClassInitializedNoProto(obj, &ProxyObject::uncallableClass_);
|
||||
global->markStandardClassInitializedNoProto(&ProxyObject::uncallableClass_);
|
||||
return ctor;
|
||||
}
|
||||
|
@ -4870,7 +4870,7 @@ dom_constructor(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
|
||||
RootedObject callee(cx, &args.callee());
|
||||
RootedValue protov(cx);
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &protov))
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &protov))
|
||||
return false;
|
||||
|
||||
if (!protov.isObject()) {
|
||||
|
@ -27,7 +27,6 @@
|
||||
macro(caller, caller, "caller") \
|
||||
macro(callFunction, callFunction, "callFunction") \
|
||||
macro(caseFirst, caseFirst, "caseFirst") \
|
||||
macro(classPrototype, classPrototype, "prototype") \
|
||||
macro(Collator, Collator, "Collator") \
|
||||
macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
|
||||
macro(columnNumber, columnNumber, "columnNumber") \
|
||||
@ -124,6 +123,7 @@
|
||||
macro(preventExtensions, preventExtensions, "preventExtensions") \
|
||||
macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
|
||||
macro(proto, proto, "__proto__") \
|
||||
macro(prototype, prototype, "prototype") \
|
||||
macro(return, return_, "return") \
|
||||
macro(sensitivity, sensitivity, "sensitivity") \
|
||||
macro(set, set, "set") \
|
||||
|
@ -2087,7 +2087,7 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp)
|
||||
/* Get Debugger.prototype. */
|
||||
RootedValue v(cx);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().classPrototype, &v))
|
||||
if (!JSObject::getProperty(cx, callee, callee, cx->names().prototype, &v))
|
||||
return false;
|
||||
RootedObject proto(cx, &v.toObject());
|
||||
JS_ASSERT(proto->getClass() == &Debugger::jsclass);
|
||||
|
@ -361,9 +361,9 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
|
||||
}
|
||||
|
||||
/* Add the global Function and Object properties now. */
|
||||
if (!self->addDataProperty(cx, cx->names().Object, JSProto_Object + JSProto_LIMIT * 2, 0))
|
||||
if (!self->addDataProperty(cx, cx->names().Object, constructorPropertySlot(JSProto_Object), 0))
|
||||
return nullptr;
|
||||
if (!self->addDataProperty(cx, cx->names().Function, JSProto_Function + JSProto_LIMIT * 2, 0))
|
||||
if (!self->addDataProperty(cx, cx->names().Function, constructorPropertySlot(JSProto_Function), 0))
|
||||
return nullptr;
|
||||
|
||||
/* Heavy lifting done, but lingering tasks remain. */
|
||||
@ -551,7 +551,7 @@ js::LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor_, JSObject *proto_
|
||||
RootedValue protoVal(cx, ObjectValue(*proto));
|
||||
RootedValue ctorVal(cx, ObjectValue(*ctor));
|
||||
|
||||
return JSObject::defineProperty(cx, ctor, cx->names().classPrototype,
|
||||
return JSObject::defineProperty(cx, ctor, cx->names().prototype,
|
||||
protoVal, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY) &&
|
||||
JSObject::defineProperty(cx, proto, cx->names().constructor,
|
||||
|
@ -35,31 +35,39 @@ class Debugger;
|
||||
/*
|
||||
* Global object slots are reserved as follows:
|
||||
*
|
||||
* [0, JSProto_LIMIT)
|
||||
* [0, APPLICATION_SLOTS)
|
||||
* Pre-reserved slots in all global objects set aside for the embedding's
|
||||
* use. As with all reserved slots these start out as UndefinedValue() and
|
||||
* are traced for GC purposes. Apart from that the engine never touches
|
||||
* these slots, so the embedding can do whatever it wants with them.
|
||||
* [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT)
|
||||
* Stores the original value of the constructor for the corresponding
|
||||
* JSProtoKey.
|
||||
* [JSProto_LIMIT, 2 * JSProto_LIMIT)
|
||||
* [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT)
|
||||
* Stores the prototype, if any, for the constructor for the corresponding
|
||||
* JSProtoKey offset from JSProto_LIMIT.
|
||||
* [2 * JSProto_LIMIT, 3 * JSProto_LIMIT)
|
||||
* [APPLICATION_SLOTS + 2 * JSProto_LIMIT, APPLICATION_SLOTS + 3 * JSProto_LIMIT)
|
||||
* Stores the current value of the global property named for the JSProtoKey
|
||||
* for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT.
|
||||
* [3 * JSProto_LIMIT, RESERVED_SLOTS)
|
||||
* [APPLICATION_SLOTS + 3 * JSProto_LIMIT, RESERVED_SLOTS)
|
||||
* Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
|
||||
* the original eval for this global object (implementing |var eval =
|
||||
* otherWindow.eval; eval(...)| as an indirect eval), a bit indicating
|
||||
* whether this object has been cleared (see JS_ClearScope), and a cache for
|
||||
* whether eval is allowed (per the global's Content Security Policy).
|
||||
*
|
||||
* The first two ranges are necessary to implement js::FindClassObject,
|
||||
* and spec language speaking in terms of "the original Array prototype
|
||||
* object", or "as if by the expression new Array()" referring to the original
|
||||
* Array constructor. The third range stores the (writable and even deletable)
|
||||
* Object, Array, &c. properties (although a slot won't be used again if its
|
||||
* property is deleted and readded).
|
||||
* The first two JSProto_LIMIT-sized ranges are necessary to implement
|
||||
* js::FindClassObject, and spec language speaking in terms of "the original
|
||||
* Array prototype object", or "as if by the expression new Array()" referring
|
||||
* to the original Array constructor. The third range stores the (writable and
|
||||
* even deletable) Object, Array, &c. properties (although a slot won't be used
|
||||
* again if its property is deleted and readded).
|
||||
*/
|
||||
class GlobalObject : public JSObject
|
||||
{
|
||||
/* Count of slots set aside for application use. */
|
||||
static const unsigned APPLICATION_SLOTS = 3;
|
||||
|
||||
/*
|
||||
* Count of slots to store built-in constructors, prototypes, and initial
|
||||
* visible properties for the constructors.
|
||||
@ -67,7 +75,7 @@ class GlobalObject : public JSObject
|
||||
static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3;
|
||||
|
||||
/* Various function values needed by the engine. */
|
||||
static const unsigned EVAL = STANDARD_CLASS_SLOTS;
|
||||
static const unsigned EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS;
|
||||
static const unsigned CREATE_DATAVIEW_FOR_THIS = EVAL + 1;
|
||||
static const unsigned THROWTYPEERROR = CREATE_DATAVIEW_FOR_THIS + 1;
|
||||
static const unsigned PROTO_GETTER = THROWTYPEERROR + 1;
|
||||
@ -122,23 +130,6 @@ class GlobalObject : public JSObject
|
||||
JSObject *
|
||||
initFunctionAndObjectClasses(JSContext *cx);
|
||||
|
||||
void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto) {
|
||||
JS_ASSERT(getSlotRef(key).isUndefined());
|
||||
JS_ASSERT(getSlotRef(JSProto_LIMIT + key).isUndefined());
|
||||
JS_ASSERT(getSlotRef(2 * JSProto_LIMIT + key).isUndefined());
|
||||
setSlot(key, ObjectValue(*ctor));
|
||||
setSlot(JSProto_LIMIT + key, ObjectValue(*proto));
|
||||
setSlot(2 * JSProto_LIMIT + key, ObjectValue(*ctor));
|
||||
}
|
||||
|
||||
void setObjectClassDetails(JSFunction *ctor, JSObject *proto) {
|
||||
setDetailsForKey(JSProto_Object, ctor, proto);
|
||||
}
|
||||
|
||||
void setFunctionClassDetails(JSFunction *ctor, JSObject *proto) {
|
||||
setDetailsForKey(JSProto_Function, ctor, proto);
|
||||
}
|
||||
|
||||
void setThrowTypeError(JSFunction *fun) {
|
||||
JS_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined());
|
||||
setSlot(THROWTYPEERROR, ObjectValue(*fun));
|
||||
@ -159,14 +150,38 @@ class GlobalObject : public JSObject
|
||||
setSlot(INTRINSICS, ObjectValue(*obj));
|
||||
}
|
||||
|
||||
public:
|
||||
Value getConstructor(JSProtoKey key) const {
|
||||
JS_ASSERT(key <= JSProto_LIMIT);
|
||||
return getSlot(key);
|
||||
return getSlot(APPLICATION_SLOTS + key);
|
||||
}
|
||||
|
||||
void setConstructor(JSProtoKey key, const Value &v) {
|
||||
JS_ASSERT(key <= JSProto_LIMIT);
|
||||
setSlot(APPLICATION_SLOTS + key, v);
|
||||
}
|
||||
|
||||
Value getPrototype(JSProtoKey key) const {
|
||||
JS_ASSERT(key <= JSProto_LIMIT);
|
||||
return getSlot(JSProto_LIMIT + key);
|
||||
return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key);
|
||||
}
|
||||
|
||||
void setPrototype(JSProtoKey key, const Value &value) {
|
||||
JS_ASSERT(key <= JSProto_LIMIT);
|
||||
setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value);
|
||||
}
|
||||
|
||||
static uint32_t constructorPropertySlot(JSProtoKey key) {
|
||||
JS_ASSERT(key <= JSProto_LIMIT);
|
||||
return APPLICATION_SLOTS + JSProto_LIMIT * 2 + key;
|
||||
}
|
||||
|
||||
Value getConstructorPropertySlot(JSProtoKey key) {
|
||||
return getSlot(constructorPropertySlot(key));
|
||||
}
|
||||
|
||||
void setConstructorPropertySlot(JSProtoKey key, const Value &ctor) {
|
||||
setSlot(constructorPropertySlot(key), ctor);
|
||||
}
|
||||
|
||||
bool classIsInitialized(JSProtoKey key) const {
|
||||
@ -181,6 +196,50 @@ class GlobalObject : public JSObject
|
||||
return inited;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lazy standard classes need a way to indicate they have been initialized.
|
||||
* Otherwise, when we delete them, we might accidentally recreate them via
|
||||
* a lazy initialization. We use the presence of a ctor or proto in the
|
||||
* global object's slot to indicate that they've been constructed, but this
|
||||
* only works for classes which have a proto and ctor. Classes which don't
|
||||
* have one can call markStandardClassInitializedNoProto(), and we can
|
||||
* always check whether a class is initialized by calling
|
||||
* isStandardClassResolved().
|
||||
*/
|
||||
bool isStandardClassResolved(const js::Class *clasp) const {
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
|
||||
// If the constructor is undefined, then it hasn't been initialized.
|
||||
return !getConstructor(key).isUndefined();
|
||||
}
|
||||
|
||||
void markStandardClassInitializedNoProto(const js::Class *clasp) {
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
|
||||
// We use true so that it's obvious what we're doing (instead of, say,
|
||||
// null, which might be miscontrued as an error in setting Undefined).
|
||||
if (getConstructor(key).isUndefined())
|
||||
setConstructor(key, BooleanValue(true));
|
||||
}
|
||||
|
||||
private:
|
||||
void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto) {
|
||||
JS_ASSERT(getConstructor(key).isUndefined());
|
||||
JS_ASSERT(getPrototype(key).isUndefined());
|
||||
JS_ASSERT(getConstructorPropertySlot(key).isUndefined());
|
||||
setConstructor(key, ObjectValue(*ctor));
|
||||
setPrototype(key, ObjectValue(*proto));
|
||||
setConstructorPropertySlot(key, ObjectValue(*ctor));
|
||||
}
|
||||
|
||||
void setObjectClassDetails(JSFunction *ctor, JSObject *proto) {
|
||||
setDetailsForKey(JSProto_Object, ctor, proto);
|
||||
}
|
||||
|
||||
void setFunctionClassDetails(JSFunction *ctor, JSObject *proto) {
|
||||
setDetailsForKey(JSProto_Function, ctor, proto);
|
||||
}
|
||||
|
||||
bool arrayClassInitialized() const {
|
||||
return classIsInitialized(JSProto_Array);
|
||||
}
|
||||
@ -287,6 +346,12 @@ class GlobalObject : public JSObject
|
||||
return &self->getPrototype(JSProto_Array).toObject();
|
||||
}
|
||||
|
||||
JSObject *maybeGetArrayPrototype() {
|
||||
if (arrayClassInitialized())
|
||||
return &getPrototype(JSProto_Array).toObject();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
|
||||
if (booleanClassInitialized())
|
||||
return &getPrototype(JSProto_Boolean).toObject();
|
||||
@ -343,7 +408,24 @@ class GlobalObject : public JSObject
|
||||
}
|
||||
|
||||
JSObject *getOrCreateIntlObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_Intl, initIntlObject);
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject);
|
||||
}
|
||||
|
||||
JSObject *getIteratorPrototype() {
|
||||
return &getPrototype(JSProto_Iterator).toObject();
|
||||
}
|
||||
|
||||
JSObject *getOrCreateDataObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Data, initDataObject);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateTypeObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Type, initTypeObject);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateArrayTypeObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_ArrayTypeObject,
|
||||
initArrayTypeObject);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateCollatorPrototype(JSContext *cx) {
|
||||
@ -358,22 +440,6 @@ class GlobalObject : public JSObject
|
||||
return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto);
|
||||
}
|
||||
|
||||
JSObject *getIteratorPrototype() {
|
||||
return &getPrototype(JSProto_Iterator).toObject();
|
||||
}
|
||||
|
||||
JSObject *getOrCreateDataObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_Data, initDataObject);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateTypeObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_Type, initTypeObject);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateArrayTypeObject(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_ArrayTypeObject, initArrayTypeObject);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global);
|
||||
|
||||
@ -389,7 +455,8 @@ class GlobalObject : public JSObject
|
||||
|
||||
public:
|
||||
JSObject *getOrCreateIteratorPrototype(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_LIMIT + JSProto_Iterator, initIteratorClasses);
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator,
|
||||
initIteratorClasses);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateElementIteratorPrototype(JSContext *cx) {
|
||||
@ -405,12 +472,13 @@ class GlobalObject : public JSObject
|
||||
}
|
||||
|
||||
JSObject *getOrCreateStarGeneratorFunctionPrototype(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_LIMIT + JSProto_GeneratorFunction,
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_LIMIT + JSProto_GeneratorFunction,
|
||||
initIteratorClasses);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateStarGeneratorFunction(JSContext *cx) {
|
||||
return getOrCreateObject(cx, JSProto_GeneratorFunction, initIteratorClasses);
|
||||
return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_GeneratorFunction,
|
||||
initIteratorClasses);
|
||||
}
|
||||
|
||||
JSObject *getOrCreateMapIteratorPrototype(JSContext *cx) {
|
||||
|
@ -606,10 +606,10 @@ js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, c
|
||||
|
||||
TypeScript::SetThis(cx, script, thisv);
|
||||
|
||||
Probes::startExecution(script);
|
||||
probes::StartExecution(script);
|
||||
ExecuteState state(cx, script, thisv, scopeChainArg, type, evalInFrame, result);
|
||||
bool ok = RunScript(cx, state);
|
||||
Probes::stopExecution(script);
|
||||
probes::StopExecution(script);
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -1335,7 +1335,7 @@ Interpret(JSContext *cx, RunState &state)
|
||||
* fail if cx->isExceptionPending() is true.
|
||||
*/
|
||||
if (cx->isExceptionPending()) {
|
||||
Probes::enterScript(cx, script, script->function(), regs.fp());
|
||||
probes::EnterScript(cx, script, script->function(), regs.fp());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@ -1347,7 +1347,7 @@ Interpret(JSContext *cx, RunState &state)
|
||||
if (!entryFrame->prologue(cx))
|
||||
goto error;
|
||||
} else {
|
||||
Probes::enterScript(cx, script, script->function(), entryFrame);
|
||||
probes::EnterScript(cx, script, script->function(), entryFrame);
|
||||
}
|
||||
if (cx->compartment()->debugMode()) {
|
||||
JSTrapStatus status = ScriptDebugPrologue(cx, entryFrame);
|
||||
@ -1623,7 +1623,7 @@ BEGIN_CASE(JSOP_STOP)
|
||||
if (!regs.fp()->isYielding())
|
||||
regs.fp()->epilogue(cx);
|
||||
else
|
||||
Probes::exitScript(cx, script, script->function(), regs.fp());
|
||||
probes::ExitScript(cx, script, script->function(), regs.fp());
|
||||
|
||||
#if defined(JS_ION)
|
||||
jit_return_pop_frame:
|
||||
@ -3401,7 +3401,7 @@ default:
|
||||
if (!regs.fp()->isYielding())
|
||||
regs.fp()->epilogue(cx);
|
||||
else
|
||||
Probes::exitScript(cx, script, script->function(), regs.fp());
|
||||
probes::ExitScript(cx, script, script->function(), regs.fp());
|
||||
|
||||
gc::MaybeVerifyBarriers(cx, true);
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace js {
|
||||
*/
|
||||
|
||||
inline bool
|
||||
Probes::callTrackingActive(JSContext *cx)
|
||||
probes::CallTrackingActive(JSContext *cx)
|
||||
{
|
||||
#ifdef INCLUDE_MOZILLA_DTRACE
|
||||
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
|
||||
@ -33,14 +33,14 @@ Probes::callTrackingActive(JSContext *cx)
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::wantNativeAddressInfo(JSContext *cx)
|
||||
probes::WantNativeAddressInfo(JSContext *cx)
|
||||
{
|
||||
return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION &&
|
||||
JITGranularityRequested(cx) >= JITREPORT_GRANULARITY_FUNCTION);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::enterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
probes::EnterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
StackFrame *fp)
|
||||
{
|
||||
bool ok = true;
|
||||
@ -63,7 +63,7 @@ Probes::enterScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::exitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
AbstractFramePtr fp)
|
||||
{
|
||||
bool ok = true;
|
||||
@ -88,14 +88,14 @@ Probes::exitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::exitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
probes::ExitScript(JSContext *cx, JSScript *script, JSFunction *maybeFun,
|
||||
StackFrame *fp)
|
||||
{
|
||||
return Probes::exitScript(cx, script, maybeFun, fp ? AbstractFramePtr(fp) : AbstractFramePtr());
|
||||
return probes::ExitScript(cx, script, maybeFun, fp ? AbstractFramePtr(fp) : AbstractFramePtr());
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::startExecution(JSScript *script)
|
||||
probes::StartExecution(JSScript *script)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
@ -109,7 +109,7 @@ Probes::startExecution(JSScript *script)
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::stopExecution(JSScript *script)
|
||||
probes::StopExecution(JSScript *script)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
|
@ -16,13 +16,13 @@
|
||||
|
||||
using namespace js;
|
||||
|
||||
const char Probes::nullName[] = "(null)";
|
||||
const char Probes::anonymousName[] = "(anonymous)";
|
||||
const char probes::nullName[] = "(null)";
|
||||
const char probes::anonymousName[] = "(anonymous)";
|
||||
|
||||
bool Probes::ProfilingActive = true;
|
||||
bool probes::ProfilingActive = true;
|
||||
|
||||
Probes::JITReportGranularity
|
||||
Probes::JITGranularityRequested(JSContext *cx)
|
||||
probes::JITReportGranularity
|
||||
probes::JITGranularityRequested(JSContext *cx)
|
||||
{
|
||||
if (cx->runtime()->spsProfiler.enabled())
|
||||
return JITREPORT_GRANULARITY_LINE;
|
||||
@ -31,7 +31,7 @@ Probes::JITGranularityRequested(JSContext *cx)
|
||||
|
||||
/* ICs are unregistered in a batch */
|
||||
void
|
||||
Probes::discardExecutableRegion(void *start, size_t size)
|
||||
probes::DiscardExecutableRegion(void *start, size_t size)
|
||||
{
|
||||
/*
|
||||
* Not needed for SPS because ICs are disposed of when the normal JITChunk
|
||||
@ -44,9 +44,9 @@ static const char *
|
||||
ScriptFilename(const JSScript *script)
|
||||
{
|
||||
if (!script)
|
||||
return Probes::nullName;
|
||||
return probes::nullName;
|
||||
if (!script->filename())
|
||||
return Probes::anonymousName;
|
||||
return probes::anonymousName;
|
||||
return script->filename();
|
||||
}
|
||||
|
||||
@ -54,10 +54,10 @@ static const char *
|
||||
FunctionName(JSContext *cx, JSFunction *fun, JSAutoByteString* bytes)
|
||||
{
|
||||
if (!fun)
|
||||
return Probes::nullName;
|
||||
return probes::nullName;
|
||||
if (!fun->displayAtom())
|
||||
return Probes::anonymousName;
|
||||
return bytes->encodeLatin1(cx, fun->displayAtom()) ? bytes->ptr() : Probes::nullName;
|
||||
return probes::anonymousName;
|
||||
return bytes->encodeLatin1(cx, fun->displayAtom()) ? bytes->ptr() : probes::nullName;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -68,18 +68,18 @@ FunctionName(JSContext *cx, JSFunction *fun, JSAutoByteString* bytes)
|
||||
* a number of usually unused lines of code would cause.
|
||||
*/
|
||||
void
|
||||
Probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
{
|
||||
JSAutoByteString funNameBytes;
|
||||
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), Probes::nullName,
|
||||
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), probes::nullName,
|
||||
FunctionName(cx, fun, &funNameBytes));
|
||||
}
|
||||
|
||||
void
|
||||
Probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
|
||||
{
|
||||
JSAutoByteString funNameBytes;
|
||||
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), Probes::nullName,
|
||||
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), probes::nullName,
|
||||
FunctionName(cx, fun, &funNameBytes));
|
||||
}
|
||||
#endif
|
||||
|
@ -15,13 +15,13 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace Probes {
|
||||
namespace probes {
|
||||
|
||||
/*
|
||||
* Static probes
|
||||
*
|
||||
* The probe points defined in this file are scattered around the SpiderMonkey
|
||||
* source tree. The presence of Probes::someEvent() means that someEvent is
|
||||
* source tree. The presence of probes::SomeEvent() means that someEvent is
|
||||
* about to happen or has happened. To the extent possible, probes should be
|
||||
* inserted in all paths associated with a given event, regardless of the
|
||||
* active runmode (interpreter/traceJIT/methodJIT/ionJIT).
|
||||
@ -57,37 +57,37 @@ extern const char anonymousName[];
|
||||
* to decide whether they can optimize in a way that would prevent probes from
|
||||
* firing.
|
||||
*/
|
||||
bool callTrackingActive(JSContext *);
|
||||
bool CallTrackingActive(JSContext *);
|
||||
|
||||
/*
|
||||
* Test whether anything is looking for JIT native code registration events.
|
||||
* This information will not be collected otherwise.
|
||||
*/
|
||||
bool wantNativeAddressInfo(JSContext *);
|
||||
bool WantNativeAddressInfo(JSContext *);
|
||||
|
||||
/* Entering a JS function */
|
||||
bool enterScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
bool EnterScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
|
||||
/* About to leave a JS function */
|
||||
bool exitScript(JSContext *, JSScript *, JSFunction *, AbstractFramePtr);
|
||||
bool exitScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
bool ExitScript(JSContext *, JSScript *, JSFunction *, AbstractFramePtr);
|
||||
bool ExitScript(JSContext *, JSScript *, JSFunction *, StackFrame *);
|
||||
|
||||
/* Executing a script */
|
||||
bool startExecution(JSScript *script);
|
||||
bool StartExecution(JSScript *script);
|
||||
|
||||
/* Script has completed execution */
|
||||
bool stopExecution(JSScript *script);
|
||||
bool StopExecution(JSScript *script);
|
||||
|
||||
/*
|
||||
* Object has been created. |obj| must exist (its class and size are read)
|
||||
*/
|
||||
bool createObject(ExclusiveContext *cx, JSObject *obj);
|
||||
bool CreateObject(ExclusiveContext *cx, JSObject *obj);
|
||||
|
||||
/*
|
||||
* Object is about to be finalized. |obj| must still exist (its class is
|
||||
* read)
|
||||
*/
|
||||
bool finalizeObject(JSObject *obj);
|
||||
bool FinalizeObject(JSObject *obj);
|
||||
|
||||
/* JIT code observation */
|
||||
|
||||
@ -109,11 +109,11 @@ JITGranularityRequested(JSContext *cx);
|
||||
* (ICs are unregistered in a batch, so individual ICs are not registered.)
|
||||
*/
|
||||
void
|
||||
discardExecutableRegion(void *start, size_t size);
|
||||
DiscardExecutableRegion(void *start, size_t size);
|
||||
|
||||
/*
|
||||
* Internal: DTrace-specific functions to be called during Probes::enterScript
|
||||
* and Probes::exitScript. These will not be inlined, but the argument
|
||||
* Internal: DTrace-specific functions to be called during probes::EnterScript
|
||||
* and probes::ExitScript. These will not be inlined, but the argument
|
||||
* marshalling required for these probe points is expensive enough that it
|
||||
* shouldn't really matter.
|
||||
*/
|
||||
@ -137,7 +137,7 @@ static const char *ObjectClassname(JSObject *obj) {
|
||||
#endif
|
||||
|
||||
inline bool
|
||||
Probes::createObject(ExclusiveContext *cx, JSObject *obj)
|
||||
probes::CreateObject(ExclusiveContext *cx, JSObject *obj)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
@ -150,7 +150,7 @@ Probes::createObject(ExclusiveContext *cx, JSObject *obj)
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::finalizeObject(JSObject *obj)
|
||||
probes::FinalizeObject(JSObject *obj)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
|
@ -53,7 +53,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
|
||||
JSObject *obj = js_NewGCObject<NoGC>(cx, entry->kind, heap);
|
||||
if (obj) {
|
||||
copyCachedToObject(obj, templateObj, entry->kind);
|
||||
Probes::createObject(cx, obj);
|
||||
probes::CreateObject(cx, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
|
||||
// Normal .prototype properties aren't enumerable. But for this to clone
|
||||
// correctly, it must be enumerable.
|
||||
RootedObject ctor(cx, &args[0].toObject());
|
||||
if (!JSObject::defineProperty(cx, ctor, cx->names().classPrototype, args[1],
|
||||
if (!JSObject::defineProperty(cx, ctor, cx->names().prototype, args[1],
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user