Merge inbound to central, a=merge

MozReview-Commit-ID: KIm8XUkfyZW
This commit is contained in:
Wes Kocher 2016-12-30 16:56:03 -08:00
commit 6e269458be
85 changed files with 1261 additions and 1183 deletions

View File

@ -20,6 +20,10 @@ let whitelist = [
{sourceName: /web\/viewer\.css$/i,
errorMessage: /Unknown pseudo-class.*(fullscreen|selection)/i,
isFromDevTools: false},
// PDFjs rules needed for compat with other UAs.
{sourceName: /web\/viewer\.css$/i,
errorMessage: /Unknown property.*appearance/i,
isFromDevTools: false},
// Tracked in bug 1004428.
{sourceName: /aboutaccounts\/(main|normalize)\.css$/i,
isFromDevTools: false},

View File

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.6.401
Current extension version is: 1.6.418

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, PdfjsChromeUtils,
PdfjsContentUtils, PdfStreamConverter */

View File

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true, maxlen: 100 */
/* eslint max-len: ["error", 100] */
/* globals Components, Services */
'use strict';

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils,
dump, NetworkManager, PdfJsTelemetry, PdfjsContentUtils */

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */
'use strict';

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, Services, XPCOMUtils */
'use strict';

View File

@ -23,8 +23,8 @@
}
}(this, function (exports) {
'use strict';
var pdfjsVersion = '1.6.401';
var pdfjsBuild = 'b629be05';
var pdfjsVersion = '1.6.418';
var pdfjsBuild = '59afb4b9';
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
var pdfjsLibs = {};
(function pdfjsWrapper() {
@ -1808,6 +1808,15 @@
switch (fieldType) {
case 'Tx':
return new TextWidgetAnnotationElement(parameters);
case 'Btn':
if (parameters.data.radioButton) {
return new RadioButtonWidgetAnnotationElement(parameters);
} else if (parameters.data.checkBox) {
return new CheckboxWidgetAnnotationElement(parameters);
} else {
warn('Unimplemented button widget annotation: pushbutton');
}
break;
case 'Ch':
return new ChoiceWidgetAnnotationElement(parameters);
}
@ -2075,6 +2084,45 @@
});
return TextWidgetAnnotationElement;
}();
var CheckboxWidgetAnnotationElement = function CheckboxWidgetAnnotationElementClosure() {
function CheckboxWidgetAnnotationElement(parameters) {
WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms);
}
Util.inherit(CheckboxWidgetAnnotationElement, WidgetAnnotationElement, {
render: function CheckboxWidgetAnnotationElement_render() {
this.container.className = 'buttonWidgetAnnotation checkBox';
var element = document.createElement('input');
element.disabled = this.data.readOnly;
element.type = 'checkbox';
if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
element.setAttribute('checked', true);
}
this.container.appendChild(element);
return this.container;
}
});
return CheckboxWidgetAnnotationElement;
}();
var RadioButtonWidgetAnnotationElement = function RadioButtonWidgetAnnotationElementClosure() {
function RadioButtonWidgetAnnotationElement(parameters) {
WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms);
}
Util.inherit(RadioButtonWidgetAnnotationElement, WidgetAnnotationElement, {
render: function RadioButtonWidgetAnnotationElement_render() {
this.container.className = 'buttonWidgetAnnotation radioButton';
var element = document.createElement('input');
element.disabled = this.data.readOnly;
element.type = 'radio';
element.name = this.data.fieldName;
if (this.data.fieldValue === this.data.buttonValue) {
element.setAttribute('checked', true);
}
this.container.appendChild(element);
return this.container;
}
});
return RadioButtonWidgetAnnotationElement;
}();
var ChoiceWidgetAnnotationElement = function ChoiceWidgetAnnotationElementClosure() {
function ChoiceWidgetAnnotationElement(parameters) {
WidgetAnnotationElement.call(this, parameters, parameters.renderInteractiveForms);

View File

@ -23,8 +23,8 @@
}
}(this, function (exports) {
'use strict';
var pdfjsVersion = '1.6.401';
var pdfjsBuild = 'b629be05';
var pdfjsVersion = '1.6.418';
var pdfjsBuild = '59afb4b9';
var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
var pdfjsLibs = {};
(function pdfjsWrapper() {
@ -45245,10 +45245,10 @@
}
if (!font.vertical) {
textChunk.lastAdvanceWidth = width;
textChunk.width += width * textChunk.textAdvanceScale;
textChunk.width += width;
} else {
textChunk.lastAdvanceHeight = height;
textChunk.height += Math.abs(height * textChunk.textAdvanceScale);
textChunk.height += Math.abs(height);
}
return textChunk;
}
@ -45269,6 +45269,8 @@
if (!textContentItem.initialized) {
return;
}
textContentItem.width *= textContentItem.textAdvanceScale;
textContentItem.height *= textContentItem.textAdvanceScale;
textContent.items.push(runBidiTransform(textContentItem));
textContentItem.initialized = false;
textContentItem.str.length = 0;
@ -45381,16 +45383,16 @@
advance = items[j] * textState.fontSize / 1000;
var breakTextRun = false;
if (textState.font.vertical) {
offset = advance * (textState.textHScale * textState.textMatrix[2] + textState.textMatrix[3]);
textState.translateTextMatrix(0, advance);
offset = advance;
textState.translateTextMatrix(0, offset);
breakTextRun = textContentItem.textRunBreakAllowed && advance > textContentItem.fakeMultiSpaceMax;
if (!breakTextRun) {
textContentItem.height += offset;
}
} else {
advance = -advance;
offset = advance * (textState.textHScale * textState.textMatrix[0] + textState.textMatrix[1]);
textState.translateTextMatrix(advance, 0);
offset = advance * textState.textHScale;
textState.translateTextMatrix(offset, 0);
breakTextRun = textContentItem.textRunBreakAllowed && advance > textContentItem.fakeMultiSpaceMax;
if (!breakTextRun) {
textContentItem.width += offset;
@ -45884,7 +45886,16 @@
} else if (isRef(entry)) {
hash.update(entry.toString());
} else if (isArray(entry)) {
hash.update(entry.length.toString());
var diffLength = entry.length, diffBuf = new Array(diffLength);
for (var j = 0; j < diffLength; j++) {
var diffEntry = entry[j];
if (isName(diffEntry)) {
diffBuf[j] = diffEntry.name;
} else if (isNum(diffEntry) || isRef(diffEntry)) {
diffBuf[j] = diffEntry.toString();
}
}
hash.update(diffBuf.join());
}
}
}
@ -47160,6 +47171,8 @@
switch (fieldType) {
case 'Tx':
return new TextWidgetAnnotation(parameters);
case 'Btn':
return new ButtonWidgetAnnotation(parameters);
case 'Ch':
return new ChoiceWidgetAnnotation(parameters);
}
@ -47587,17 +47600,72 @@
});
return TextWidgetAnnotation;
}();
var ButtonWidgetAnnotation = function ButtonWidgetAnnotationClosure() {
function ButtonWidgetAnnotation(params) {
WidgetAnnotation.call(this, params);
this.data.checkBox = !this.hasFieldFlag(AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
if (this.data.checkBox) {
if (!isName(this.data.fieldValue)) {
return;
}
this.data.fieldValue = this.data.fieldValue.name;
}
this.data.radioButton = this.hasFieldFlag(AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
if (this.data.radioButton) {
this.data.fieldValue = this.data.buttonValue = null;
var fieldParent = params.dict.get('Parent');
if (!isDict(fieldParent) || !fieldParent.has('V')) {
return;
}
var fieldParentValue = fieldParent.get('V');
if (!isName(fieldParentValue)) {
return;
}
this.data.fieldValue = fieldParentValue.name;
var appearanceStates = params.dict.get('AP');
if (!isDict(appearanceStates)) {
return;
}
var normalAppearanceState = appearanceStates.get('N');
if (!isDict(normalAppearanceState)) {
return;
}
var keys = normalAppearanceState.getKeys();
for (var i = 0, ii = keys.length; i < ii; i++) {
if (keys[i] !== 'Off') {
this.data.buttonValue = keys[i];
break;
}
}
}
}
Util.inherit(ButtonWidgetAnnotation, WidgetAnnotation, {
getOperatorList: function ButtonWidgetAnnotation_getOperatorList(evaluator, task, renderForms) {
var operatorList = new OperatorList();
if (renderForms) {
return Promise.resolve(operatorList);
}
if (this.appearance) {
return Annotation.prototype.getOperatorList.call(this, evaluator, task, renderForms);
}
return Promise.resolve(operatorList);
}
});
return ButtonWidgetAnnotation;
}();
var ChoiceWidgetAnnotation = function ChoiceWidgetAnnotationClosure() {
function ChoiceWidgetAnnotation(params) {
WidgetAnnotation.call(this, params);
this.data.options = [];
var options = params.dict.getArray('Opt');
var options = params.dict.get('Opt');
if (isArray(options)) {
var xref = params.xref;
for (var i = 0, ii = options.length; i < ii; i++) {
var option = options[i];
var option = xref.fetchIfRef(options[i]);
var isOptionArray = isArray(option);
this.data.options[i] = {
exportValue: isArray(option) ? option[0] : option,
displayValue: isArray(option) ? option[1] : option
exportValue: isOptionArray ? xref.fetchIfRef(option[0]) : option,
displayValue: isOptionArray ? xref.fetchIfRef(option[1]) : option
};
}
}

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* jshint esnext:true */
/* globals Components, PdfjsContentUtils, PdfJs, Services */
'use strict';

View File

@ -1,4 +1,3 @@
'use strict';
// Small subset of the webL10n API by Fabien Cazenave for pdf.js extension.

View File

@ -103,7 +103,9 @@
.annotationLayer .textWidgetAnnotation input,
.annotationLayer .textWidgetAnnotation textarea,
.annotationLayer .choiceWidgetAnnotation select {
.annotationLayer .choiceWidgetAnnotation select,
.annotationLayer .buttonWidgetAnnotation.checkBox input,
.annotationLayer .buttonWidgetAnnotation.radioButton input {
background-color: rgba(0, 54, 255, 0.13);
border: 1px solid transparent;
box-sizing: border-box;
@ -122,7 +124,9 @@
.annotationLayer .textWidgetAnnotation input[disabled],
.annotationLayer .textWidgetAnnotation textarea[disabled],
.annotationLayer .choiceWidgetAnnotation select[disabled] {
.annotationLayer .choiceWidgetAnnotation select[disabled],
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled],
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] {
background: none;
border: 1px solid transparent;
cursor: not-allowed;
@ -130,7 +134,9 @@
.annotationLayer .textWidgetAnnotation input:hover,
.annotationLayer .textWidgetAnnotation textarea:hover,
.annotationLayer .choiceWidgetAnnotation select:hover {
.annotationLayer .choiceWidgetAnnotation select:hover,
.annotationLayer .buttonWidgetAnnotation.checkBox input:hover,
.annotationLayer .buttonWidgetAnnotation.radioButton input:hover {
border: 1px solid #000;
}
@ -157,6 +163,12 @@
width: 115%;
}
.annotationLayer .buttonWidgetAnnotation.checkBox input,
.annotationLayer .buttonWidgetAnnotation.radioButton input {
-moz-appearance: none;
appearance: none;
}
.annotationLayer .popupWrapper {
position: absolute;
width: 20em;

View File

@ -4119,7 +4119,7 @@ var pdfjsWebLibs;
}
if (error === 'cancelled') {
self.error = null;
return;
return Promise.resolve(undefined);
}
self.renderingState = RenderingStates.FINISHED;
if (self.loadingIconDiv) {
@ -4145,21 +4145,25 @@ var pdfjsWebLibs;
pageNumber: self.id,
cssTransform: false
});
if (error) {
return Promise.reject(error);
}
return Promise.resolve(undefined);
};
var paintTask = this.renderer === RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper);
paintTask.onRenderContinue = renderContinueCallback;
this.paintTask = paintTask;
var resultPromise = paintTask.promise.then(function () {
finishPaintTask(null);
if (textLayer) {
pdfPage.getTextContent({ normalizeWhitespace: true }).then(function textContentResolved(textContent) {
textLayer.setTextContent(textContent);
textLayer.render(TEXT_LAYER_RENDER_DELAY);
});
}
return finishPaintTask(null).then(function () {
if (textLayer) {
pdfPage.getTextContent({ normalizeWhitespace: true }).then(function textContentResolved(textContent) {
textLayer.setTextContent(textContent);
textLayer.render(TEXT_LAYER_RENDER_DELAY);
});
}
});
}, function (reason) {
finishPaintTask(reason);
throw reason;
return finishPaintTask(reason);
});
if (this.annotationLayerFactory) {
if (!this.annotationLayer) {

View File

@ -0,0 +1,18 @@
{
"llvm_revision": "290055",
"stages": "1",
"build_libcxx": true,
"build_type": "Release",
"assertions": false,
"import_clang_tidy": true,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/trunk",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/trunk",
"python_path": "/usr/bin/python2.7",
"gcc_dir": "/home/worker/workspace/build/src/gcc",
"cc": "/home/worker/workspace/build/src/gcc/bin/gcc",
"cxx": "/home/worker/workspace/build/src/gcc/bin/g++"
}

View File

@ -163,6 +163,8 @@ WebGLContext::InitWebGL2(FailureReason* const out_failReason)
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
gl->fGenTransformFeedbacks(1, &mEmptyTFO);
////
if (!gl->IsGLES()) {

View File

@ -132,11 +132,26 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
const ScopedLazyBind readBind(gl, target, buffer);
if (byteLen) {
const auto mappedBytes = gl->fMapBufferRange(target, srcByteOffset, glByteLen,
const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
GLenum mapTarget = target;
if (isTF) {
gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
mapTarget = LOCAL_GL_ARRAY_BUFFER;
}
const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
LOCAL_GL_MAP_READ_BIT);
// Warning: Possibly shared memory. See bug 1225033.
memcpy(bytes, mappedBytes, byteLen);
gl->fUnmapBuffer(target);
gl->fUnmapBuffer(mapTarget);
if (isTF) {
const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
: 0);
gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
}
}
}

View File

@ -81,10 +81,18 @@ WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
////
if (mBoundTransformFeedback) {
mBoundTransformFeedback->AddBufferBindCounts(-1);
}
mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
MakeContextCurrent();
gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
if (mBoundTransformFeedback) {
mBoundTransformFeedback->AddBufferBindCounts(+1);
}
}
void

View File

@ -18,6 +18,8 @@ WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
, mContent(Kind::Undefined)
, mUsage(LOCAL_GL_STATIC_DRAW)
, mByteLength(0)
, mTFBindCount(0)
, mNonTFBindCount(0)
{
mContext->mBuffers.insertBack(this);
}

View File

@ -26,7 +26,6 @@ class WebGLBuffer final
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLTexture;
friend class WebGLTransformFeedback;
public:
enum class Kind {
@ -66,6 +65,35 @@ public:
bool ValidateCanBindToTarget(const char* funcName, GLenum target);
void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
////
static void AddBindCount(GLenum target, WebGLBuffer* buffer, int8_t addVal) {
if (!buffer)
return;
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
MOZ_ASSERT_IF(addVal < 0, buffer->mTFBindCount >= size_t(-addVal));
buffer->mTFBindCount += addVal;
} else {
MOZ_ASSERT_IF(addVal < 0, buffer->mNonTFBindCount >= size_t(-addVal));
buffer->mNonTFBindCount += addVal;
}
}
static void SetSlot(GLenum target, WebGLBuffer* newBuffer,
WebGLRefPtr<WebGLBuffer>* const out_slot)
{
WebGLBuffer* const oldBuffer = *out_slot;
AddBindCount(target, oldBuffer, -1);
AddBindCount(target, newBuffer, +1);
*out_slot = newBuffer;
}
bool IsBoundForTF() const { return bool(mTFBindCount); }
bool IsBoundForNonTF() const { return bool(mNonTFBindCount); }
////
const GLenum mGLName;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
@ -78,6 +106,8 @@ protected:
GLenum mUsage;
size_t mByteLength;
UniquePtr<WebGLElementArrayCache> mCache;
size_t mTFBindCount;
size_t mNonTFBindCount;
};
} // namespace mozilla

View File

@ -120,7 +120,7 @@ WebGLContext::WebGLContext()
, mMaxFetchedInstances(0)
, mLayerIsMirror(false)
, mBypassShaderValidation(false)
, mBuffersForUB_Dirty(true)
, mEmptyTFO(0)
, mContextLossHandler(this)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
@ -250,7 +250,6 @@ WebGLContext::DestroyResourcesAndContext()
mQuerySlot_TimeElapsed = nullptr;
mIndexedUniformBufferBindings.clear();
OnUBIndexedBindingsChanged();
//////
@ -268,6 +267,13 @@ WebGLContext::DestroyResourcesAndContext()
//////
if (mEmptyTFO) {
gl->fDeleteTransformFeedbacks(1, &mEmptyTFO);
mEmptyTFO = 0;
}
//////
mFakeBlack_2D_0000 = nullptr;
mFakeBlack_2D_0001 = nullptr;
mFakeBlack_CubeMap_0000 = nullptr;
@ -2385,42 +2391,6 @@ WebGLContext::ValidateArrayBufferView(const char* funcName,
return true;
}
////
const decltype(WebGLContext::mBuffersForUB)&
WebGLContext::BuffersForUB() const
{
if (mBuffersForUB_Dirty) {
mBuffersForUB.clear();
for (const auto& cur : mIndexedUniformBufferBindings) {
if (cur.mBufferBinding) {
mBuffersForUB.insert(cur.mBufferBinding.get());
}
}
mBuffersForUB_Dirty = false;
}
return mBuffersForUB;
}
////
bool
WebGLContext::ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer)
{
if (!mBoundTransformFeedback)
return true;
const auto& buffersForTF = mBoundTransformFeedback->BuffersForTF();
if (buffersForTF.count(buffer)) {
ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for transform"
" feedback.",
funcName);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop

View File

@ -1654,8 +1654,6 @@ protected:
return true;
}
bool ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer);
public:
template<typename T>
bool ValidateNonNull(const char* funcName, const dom::Nullable<T>& maybe) {
@ -1882,17 +1880,9 @@ protected:
////////////////////////////////////
private:
mutable bool mBuffersForUB_Dirty;
mutable std::set<const WebGLBuffer*> mBuffersForUB;
public:
void OnUBIndexedBindingsChanged() const { mBuffersForUB_Dirty = true; }
const decltype(mBuffersForUB)& BuffersForUB() const;
////////////////////////////////////
protected:
GLuint mEmptyTFO;
// Generic Vertex Attributes
// Though CURRENT_VERTEX_ATTRIB is listed under "Vertex Shader State" in the spec
// state tables, this isn't vertex shader /object/ state. This array is merely state

View File

@ -75,8 +75,27 @@ WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
return nullptr;
}
if (!ValidateForNonTransformFeedback(funcName, buffer.get()))
return nullptr;
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
if (mBoundTransformFeedback->IsActiveAndNotPaused()) {
ErrorInvalidOperation("%s: Cannot select TRANSFORM_FEEDBACK_BUFFER when"
" transform feedback is active and unpaused.",
funcName);
return nullptr;
}
if (buffer->IsBoundForNonTF()) {
ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
" non-transform-feedback.",
funcName);
return nullptr;
}
} else {
if (buffer->IsBoundForTF()) {
ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
" transform feedback.",
funcName);
return nullptr;
}
}
return buffer.get();
}
@ -132,7 +151,7 @@ WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
gl->MakeCurrent();
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
*slot = buffer;
WebGLBuffer::SetSlot(target, buffer, slot);
if (buffer) {
buffer->SetContentAfterBind(target);
}
@ -201,23 +220,14 @@ WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
////
*genericBinding = buffer;
indexedBinding->mBufferBinding = buffer;
WebGLBuffer::SetSlot(target, buffer, genericBinding);
WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
indexedBinding->mRangeStart = 0;
indexedBinding->mRangeSize = 0;
if (buffer) {
buffer->SetContentAfterBind(target);
}
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
mBoundTransformFeedback->OnIndexedBindingsChanged();
break;
case LOCAL_GL_UNIFORM:
OnUBIndexedBindingsChanged();
break;
}
}
void
@ -296,23 +306,14 @@ WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
////
*genericBinding = buffer;
indexedBinding->mBufferBinding = buffer;
WebGLBuffer::SetSlot(target, buffer, genericBinding);
WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
indexedBinding->mRangeStart = offset;
indexedBinding->mRangeSize = size;
if (buffer) {
buffer->SetContentAfterBind(target);
}
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
mBoundTransformFeedback->OnIndexedBindingsChanged();
break;
case LOCAL_GL_UNIFORM:
OnUBIndexedBindingsChanged();
break;
}
}
////////////////////////////////////////
@ -477,39 +478,41 @@ WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
////
const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
const auto fnClearIfBuffer = [&](GLenum target, WebGLRefPtr<WebGLBuffer>& bindPoint) {
if (bindPoint == buffer) {
bindPoint = nullptr;
WebGLBuffer::SetSlot(target, nullptr, &bindPoint);
}
};
fnClearIfBuffer(mBoundArrayBuffer);
fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);
fnClearIfBuffer(0, mBoundArrayBuffer);
fnClearIfBuffer(0, mBoundVertexArray->mElementArrayBuffer);
for (auto& cur : mBoundVertexArray->mAttribs) {
fnClearIfBuffer(0, cur.mBuf);
}
// WebGL binding points
if (IsWebGL2()) {
fnClearIfBuffer(mBoundCopyReadBuffer);
fnClearIfBuffer(mBoundCopyWriteBuffer);
fnClearIfBuffer(mBoundPixelPackBuffer);
fnClearIfBuffer(mBoundPixelUnpackBuffer);
fnClearIfBuffer(mBoundUniformBuffer);
fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);
fnClearIfBuffer(0, mBoundCopyReadBuffer);
fnClearIfBuffer(0, mBoundCopyWriteBuffer);
fnClearIfBuffer(0, mBoundPixelPackBuffer);
fnClearIfBuffer(0, mBoundPixelUnpackBuffer);
fnClearIfBuffer(0, mBoundUniformBuffer);
fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
mBoundTransformFeedback->mGenericBufferBinding);
if (!mBoundTransformFeedback->mIsActive) {
for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
fnClearIfBuffer(binding.mBufferBinding);
fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
binding.mBufferBinding);
}
}
for (auto& binding : mIndexedUniformBufferBindings) {
fnClearIfBuffer(binding.mBufferBinding);
fnClearIfBuffer(0, binding.mBufferBinding);
}
}
for (auto& cur : mBoundVertexArray->mAttribs) {
fnClearIfBuffer(cur.mBuf);
}
////
buffer->RequestDelete();

View File

@ -356,6 +356,7 @@ public:
// Check UBO sizes.
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
@ -374,18 +375,10 @@ public:
*out_error = true;
return;
}
}
////
const auto& tfo = mWebGL->mBoundTransformFeedback;
if (tfo) {
const auto& buffersForTF = tfo->BuffersForTF();
const auto& buffersForUB = mWebGL->BuffersForUB();
if (DoSetsIntersect(buffersForTF, buffersForUB)) {
mWebGL->ErrorInvalidOperation("%s: At least one WebGLBuffer is bound for"
" both transform feedback and as a uniform"
" buffer.",
if (binding->mBufferBinding->IsBoundForTF()) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is bound or"
" in use for transform feedback.",
funcName);
*out_error = true;
return;
@ -394,7 +387,38 @@ public:
////
for (const auto& progAttrib : mWebGL->mActiveProgramLinkInfo->attribs) {
const auto& tfo = mWebGL->mBoundTransformFeedback;
if (tfo && tfo->IsActiveAndNotPaused()) {
uint32_t numUsed;
switch (linkInfo->transformFeedbackBufferMode) {
case LOCAL_GL_INTERLEAVED_ATTRIBS:
numUsed = 1;
break;
case LOCAL_GL_SEPARATE_ATTRIBS:
numUsed = linkInfo->transformFeedbackVaryings.size();
break;
default:
MOZ_CRASH();
}
for (uint32_t i = 0; i < numUsed; ++i) {
const auto& buffer = tfo->mIndexedBindings[i].mBufferBinding;
if (buffer->IsBoundForNonTF()) {
mWebGL->ErrorInvalidOperation("%s: Transform feedback varying %u's"
" buffer is bound for"
" non-transform-feedback.",
funcName, i);
*out_error = true;
return;
}
}
}
////
for (const auto& progAttrib : linkInfo->attribs) {
const auto& loc = progAttrib.mLoc;
if (loc == -1)
continue;
@ -404,6 +428,14 @@ public:
GLenum attribDataBaseType;
if (attribData.mEnabled) {
attribDataBaseType = attribData.BaseType();
if (attribData.mBuf->IsBoundForTF()) {
mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u's buffer is bound"
" or in use for transform feedback.",
funcName, loc);
*out_error = true;
return;
}
} else {
attribDataBaseType = mWebGL->mGenericVertexAttribTypes[loc];
}

View File

@ -592,12 +592,19 @@ WebGLContext::GetAttribLocation(const WebGLProgram& prog, const nsAString& name)
JS::Value
WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
{
const char funcName[] = "getBufferParameter";
if (IsContextLost())
return JS::NullValue();
const auto& buffer = ValidateBufferSelection("getBufferParameter", target);
if (!buffer)
const auto& slot = ValidateBufferSlot(funcName, target);
if (!slot)
return JS::NullValue();
const auto& buffer = *slot;
if (!buffer) {
ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
return JS::NullValue();
}
switch (pname) {
case LOCAL_GL_BUFFER_SIZE:

View File

@ -25,6 +25,10 @@ WebGLContext::BindVertexArray(WebGLVertexArray* array)
MakeContextCurrent();
if (mBoundVertexArray) {
mBoundVertexArray->AddBufferBindCounts(-1);
}
if (array == nullptr) {
array = mDefaultVertexArray;
}
@ -32,6 +36,9 @@ WebGLContext::BindVertexArray(WebGLVertexArray* array)
array->BindVertexArray();
MOZ_ASSERT(mBoundVertexArray == array);
if (mBoundVertexArray) {
mBoundVertexArray->AddBufferBindCounts(+1);
}
}
already_AddRefed<WebGLVertexArray>

View File

@ -435,6 +435,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
: prog(prog)
, transformFeedbackBufferMode(prog->mNextLink_TransformFeedbackBufferMode)
{ }
webgl::LinkedProgramInfo::~LinkedProgramInfo()
@ -697,21 +698,35 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
if (!IsLinked())
return JS::NumberValue(0);
return JS::NumberValue(LinkInfo()->uniformBlocks.size());
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
if (!IsLinked())
return JS::NumberValue(0);
return JS::NumberValue(LinkInfo()->transformFeedbackVaryings.size());
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
if (!IsLinked())
return JS::NumberValue(LOCAL_GL_INTERLEAVED_ATTRIBS);
return JS::NumberValue(LinkInfo()->transformFeedbackBufferMode);
}
}
switch (pname) {
case LOCAL_GL_ATTACHED_SHADERS:
return JS::NumberValue( int(bool(mVertShader.get())) + int(bool(mFragShader)) );
case LOCAL_GL_ACTIVE_UNIFORMS:
if (!IsLinked())
return JS::NumberValue(0);
return JS::NumberValue(LinkInfo()->uniforms.size());
case LOCAL_GL_ACTIVE_ATTRIBUTES:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
if (!IsLinked())
return JS::NumberValue(0);
return JS::NumberValue(LinkInfo()->attribs.size());
case LOCAL_GL_DELETE_STATUS:
return JS::BooleanValue(IsDeleteRequested());
@ -725,6 +740,7 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
if (gl->WorkAroundDriverBugs())
return JS::BooleanValue(true);
#endif
// Todo: Implement this in our code.
return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
default:

View File

@ -87,6 +87,7 @@ struct LinkedProgramInfo final
//////
WebGLProgram* const prog;
const GLenum transformFeedbackBufferMode;
std::vector<AttribInfo> attribs;
std::vector<UniformInfo*> uniforms; // Owns its contents.

View File

@ -17,7 +17,6 @@ WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
, mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
, mIsPaused(false)
, mIsActive(false)
, mBuffersForTF_Dirty(true)
{
mContext->mTransformFeedbacks.insertBack(this);
}
@ -37,28 +36,6 @@ WebGLTransformFeedback::Delete()
removeFrom(mContext->mTransformFeedbacks);
}
////
const decltype(WebGLTransformFeedback::mBuffersForTF)&
WebGLTransformFeedback::BuffersForTF() const
{
// The generic bind point cannot incur undefined read/writes because otherwise it
// would be impossible to read back from this. The spec implies that readback from
// the TRANSFORM_FEEDBACK target is possible, just not simultaneously with being
// "bound or in use for transform feedback".
// Therefore, only the indexed bindings of the TFO count.
if (mBuffersForTF_Dirty) {
mBuffersForTF.clear();
for (const auto& cur : mIndexedBindings) {
if (cur.mBufferBinding) {
mBuffersForTF.insert(cur.mBufferBinding.get());
}
}
mBuffersForTF_Dirty = false;
}
return mBuffersForTF;
}
////////////////////////////////////////
void
@ -209,6 +186,18 @@ WebGLTransformFeedback::ResumeTransformFeedback()
////////////////////////////////////////
void
WebGLTransformFeedback::AddBufferBindCounts(int8_t addVal) const
{
const GLenum target = LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER;
WebGLBuffer::AddBindCount(target, mGenericBufferBinding.get(), addVal);
for (const auto& binding : mIndexedBindings) {
WebGLBuffer::AddBindCount(target, binding.mBufferBinding.get(), addVal);
}
}
////////////////////////////////////////
JSObject*
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{

View File

@ -17,6 +17,7 @@ class WebGLTransformFeedback final
, public WebGLRefCountedObject<WebGLTransformFeedback>
, public LinkedListElement<WebGLTransformFeedback>
{
friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback;
friend class WebGLContext;
friend class WebGL2Context;
@ -36,9 +37,6 @@ private:
MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertPosition;
MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertCapacity;
mutable bool mBuffersForTF_Dirty;
mutable std::set<const WebGLBuffer*> mBuffersForTF;
public:
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
private:
@ -52,10 +50,9 @@ public:
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
////
bool IsActiveAndNotPaused() const { return mIsActive && !mIsPaused; }
void OnIndexedBindingsChanged() const { mBuffersForTF_Dirty = true; }
const decltype(mBuffersForTF)& BuffersForTF() const;
void AddBufferBindCounts(int8_t addVal) const;
// GL Funcs
void BeginTransformFeedback(GLenum primMode);

View File

@ -28,6 +28,21 @@ WebGLVertexArray::WebGLVertexArray(WebGLContext* webgl)
mContext->mVertexArrays.insertBack(this);
}
WebGLVertexArray::~WebGLVertexArray()
{
MOZ_ASSERT(IsDeleted());
}
void
WebGLVertexArray::AddBufferBindCounts(int8_t addVal) const
{
const GLenum target = 0; // Anything non-TF is fine.
WebGLBuffer::AddBindCount(target, mElementArrayBuffer.get(), addVal);
for (const auto& attrib : mAttribs) {
WebGLBuffer::AddBindCount(target, attrib.mBuf.get(), addVal);
}
}
WebGLVertexArray*
WebGLVertexArray::Create(WebGLContext* webgl)
{

View File

@ -10,7 +10,6 @@
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
#include "WebGLBuffer.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
#include "WebGLVertexAttribData.h"
@ -48,12 +47,11 @@ public:
GLuint GLName() const { return mGLName; }
void AddBufferBindCounts(int8_t addVal) const;
protected:
explicit WebGLVertexArray(WebGLContext* webgl);
virtual ~WebGLVertexArray() {
MOZ_ASSERT(IsDeleted());
}
virtual ~WebGLVertexArray();
virtual void GenVertexArray() = 0;
virtual void BindVertexArrayImpl() = 0;

View File

@ -6,6 +6,7 @@
#include "WebGLVertexAttribData.h"
#include "GLContext.h"
#include "WebGLBuffer.h"
namespace mozilla {
@ -71,7 +72,7 @@ WebGLVertexAttribData::VertexAttribPointer(bool integerFunc, WebGLBuffer* buf,
uint32_t stride, uint64_t byteOffset)
{
mIntegerFunc = integerFunc;
mBuf = buf;
WebGLBuffer::SetSlot(0, buf, &mBuf);
mType = type;
mBaseType = AttribPointerBaseType(integerFunc, type);
mSize = size;

View File

@ -61,8 +61,6 @@ shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "0");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "0");
gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4, gl.STATIC_DRAW);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer1");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "0");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "0");
@ -99,13 +97,11 @@ shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");
gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4, gl.STATIC_DRAW);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer3");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");
gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 12, gl.STATIC_DRAW);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buffer3");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)", "8");
shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)", "4");

View File

@ -168,7 +168,10 @@ GetPluginPaths(const nsAString& aPluginPath,
// Mac sandbox rules expect paths to actual files and directories -- not
// soft links.
libDirectory->Normalize();
aPluginDirectoryPath = GetNativeTarget(libDirectory);
libFile->Normalize();
aPluginFilePath = GetNativeTarget(libFile);
return true;

View File

@ -3381,7 +3381,10 @@ XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result)
mRedirectCallback->OnRedirectVerifyCallback(result);
mRedirectCallback = nullptr;
return result;
// It's important that we return success here. If we return the result code
// that we were passed, JavaScript callers who cancel the redirect will wind
// up throwing an exception in the process.
return NS_OK;
}
/////////////////////////////////////////////////////

View File

@ -0,0 +1,26 @@
getTZKeyName in common/wintz.cpp leaks registry handle.
https://ssl.icu-project.org/trac/ticket/12908
diff --git a/intl/icu/source/common/wintz.c b/intl/icu/source/common/wintz.c
--- a/intl/icu/source/common/wintz.c
+++ b/intl/icu/source/common/wintz.c
@@ -211,16 +211,18 @@ static LONG getTZKeyName(char* tzKeyName
hkey,
"TimeZoneKeyName",
NULL,
NULL,
(LPBYTE)tzKeyName,
&cbData);
}
+ RegCloseKey(hkey);
+
return result;
}
/*
This code attempts to detect the Windows time zone, as set in the
Windows Date and Time control panel. It attempts to work on
multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized
installs. It works by directly interrogating the registry and

View File

@ -216,6 +216,8 @@ static LONG getTZKeyName(char* tzKeyName, int32_t length) {
&cbData);
}
RegCloseKey(hkey);
return result;
}

View File

@ -61,6 +61,7 @@ for patch in \
bug-1172609-timezone-recreateDefault.diff \
bug-1198952-workaround-make-3.82-bug.diff \
bug-1228227-bug-1263325-libc++-gcc_hidden.diff \
bug-1325858-close-key.diff \
ucol_getKeywordValuesForLocale-ulist_resetList.diff \
unum_formatDoubleForFields.diff \
; do

View File

@ -0,0 +1,7 @@
(function(y) {
for (var k = 0; k < 9; ++k) {
try {
y ** y == a;
} catch (e) {}
}
})();

View File

@ -0,0 +1,4 @@
this.x = [];
Function.apply(null, this.x);
Object.defineProperty(this, "x", {get: valueOf});
assertEq(evaluate("this.x;"), this);

View File

@ -415,9 +415,9 @@ BaselineCacheIRCompiler::emitCallScriptedGetterResult()
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter, "DoCallNativeGetter");
typedef bool (*CallNativeGetterFn)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction CallNativeGetterInfo =
FunctionInfo<CallNativeGetterFn>(CallNativeGetter, "CallNativeGetter");
bool
BaselineCacheIRCompiler::emitCallNativeGetterResult()
@ -439,7 +439,7 @@ BaselineCacheIRCompiler::emitCallNativeGetterResult()
masm.Push(obj);
masm.Push(scratch);
if (!callVM(masm, DoCallNativeGetterInfo))
if (!callVM(masm, CallNativeGetterInfo))
return false;
stubFrame.leave(masm);

View File

@ -698,7 +698,6 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script,
_(Call_ScriptedApplyArray) \
_(Call_ScriptedApplyArguments) \
_(Call_ScriptedFunCall) \
_(GetProp_CallNativeGlobal) \
_(GetProp_Generic) \
_(SetProp_CallScripted) \
_(SetProp_CallNative)

View File

@ -435,10 +435,6 @@ ICTypeUpdate_ObjectGroup::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter, "DoCallNativeGetter");
//
// ToBool_Fallback
//
@ -963,7 +959,7 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_
if (!attached && !JitOptions.disableCacheIR) {
ICStubEngine engine = ICStubEngine::Baseline;
GetPropIRGenerator gen(cx, pc, CacheKind::GetElem, engine, &isTemporarilyUnoptimizable,
lhs, rhs);
lhs, rhs, CanAttachGetter::Yes);
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, info.outerScript(cx), stub);
@ -2357,133 +2353,6 @@ ICIn_Dense::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
// Try to update existing SetProp setter call stubs for the given holder in
// place with a new shape and setter.
static bool
UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub,
ICStub::Kind kind,
NativeObject* holder,
JSObject* receiver,
JSFunction* setter)
{
MOZ_ASSERT(kind == ICStub::SetProp_CallScripted ||
kind == ICStub::SetProp_CallNative);
MOZ_ASSERT(holder);
MOZ_ASSERT(receiver);
bool isOwnSetter = (holder == receiver);
bool foundMatchingStub = false;
ReceiverGuard receiverGuard(receiver);
for (ICStubConstIterator iter = fallbackStub->beginChainConst(); !iter.atEnd(); iter++) {
if (iter->kind() == kind) {
ICSetPropCallSetter* setPropStub = static_cast<ICSetPropCallSetter*>(*iter);
if (setPropStub->holder() == holder && setPropStub->isOwnSetter() == isOwnSetter) {
// If this is an own setter, update the receiver guard as well,
// since that's the shape we'll be guarding on. Furthermore,
// isOwnSetter() relies on holderShape_ and receiverGuard_ being
// the same shape.
if (isOwnSetter)
setPropStub->receiverGuard().update(receiverGuard);
MOZ_ASSERT(setPropStub->holderShape() != holder->lastProperty() ||
!setPropStub->receiverGuard().matches(receiverGuard),
"Why didn't we end up using this stub?");
// We want to update the holder shape to match the new one no
// matter what, even if the receiver shape is different.
setPropStub->holderShape() = holder->lastProperty();
// Make sure to update the setter, since a shape change might
// have changed which setter we want to use.
setPropStub->setter() = setter;
if (setPropStub->receiverGuard().matches(receiverGuard))
foundMatchingStub = true;
}
}
}
return foundMatchingStub;
}
// Attach an optimized stub for a GETGNAME/CALLGNAME getter op.
static bool
TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode* pc,
ICGetName_Fallback* stub,
Handle<LexicalEnvironmentObject*> globalLexical,
HandlePropertyName name, bool* attached,
bool* isTemporarilyUnoptimizable)
{
MOZ_ASSERT(globalLexical->isGlobal());
RootedId id(cx, NameToId(name));
// There must not be a shadowing binding on the global lexical scope.
if (globalLexical->lookup(cx, id))
return true;
RootedGlobalObject global(cx, &globalLexical->global());
// The property must be found, and it must be found as a normal data property.
RootedShape shape(cx);
RootedNativeObject current(cx, global);
while (true) {
shape = current->lookup(cx, id);
if (shape)
break;
JSObject* proto = current->staticPrototype();
if (!proto || !proto->is<NativeObject>())
return true;
current = &proto->as<NativeObject>();
}
// Instantiate this global property, for use during Ion compilation.
if (IsIonEnabled(cx))
EnsureTrackPropertyTypes(cx, current, id);
// Try to add a getter stub. We don't handle scripted getters yet; if this
// changes we need to make sure IonBuilder::getPropTryCommonGetter (which
// requires a Baseline stub) handles non-outerized this objects correctly.
bool isScripted;
if (IsCacheableGetPropCall(cx, global, current, shape, &isScripted, isTemporarilyUnoptimizable) &&
!isScripted)
{
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
// The CallNativeGlobal stub needs to generate 3 shape checks:
//
// 1. The global lexical scope shape check.
// 2. The global object shape check.
// 3. The holder shape check.
//
// 1 is done as the receiver check, as for GETNAME the global lexical scope is in the
// receiver position. 2 is done as a manual check that other GetProp stubs don't do. 3 is
// done as the holder check per normal.
//
// In the case the holder is the global object, check 2 is redundant but is not yet
// optimized away.
JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName/NativeGetter) stub");
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativeGlobal, current,
globalLexical, getter))
{
*attached = true;
return true;
}
ICGetPropCallNativeCompiler compiler(cx, ICStub::GetProp_CallNativeGlobal,
ICStubCompiler::Engine::Baseline,
monitorStub, globalLexical, current,
getter, script->pcToOffset(pc),
/* inputDefinitelyObject = */ true);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
}
return true;
}
static bool
DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_,
HandleObject envChain, MutableHandleValue res)
@ -2502,7 +2371,6 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
RootedPropertyName name(cx, script->getName(pc));
bool attached = false;
bool isTemporarilyUnoptimizable = false;
// Attach new stub.
if (stub->numOptimizedStubs() >= ICGetName_Fallback::MAX_OPTIMIZED_STUBS) {
@ -2510,12 +2378,16 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
attached = true;
}
if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) {
if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub,
envChain.as<LexicalEnvironmentObject>(),
name, &attached, &isTemporarilyUnoptimizable))
{
return false;
if (!attached && !JitOptions.disableCacheIR) {
ICStubEngine engine = ICStubEngine::Baseline;
GetNameIRGenerator gen(cx, pc, script, envChain, name);
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, info.outerScript(cx), stub);
if (newStub) {
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
attached = true;
}
}
}
@ -2538,23 +2410,8 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
// Add a type monitor stub for the resulting value.
if (!stub->addMonitorStubForValue(cx, &info, res))
return false;
if (attached)
return true;
if (!JitOptions.disableCacheIR) {
ICStubEngine engine = ICStubEngine::Baseline;
GetNameIRGenerator gen(cx, pc, script, envChain, name);
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, info.outerScript(cx), stub);
if (newStub) {
JitSpew(JitSpew_BaselineIC, " Attached CacheIR stub");
attached = true;
}
}
}
if (!attached && !isTemporarilyUnoptimizable)
if (!attached)
stub->noteUnoptimizableAccess();
return true;
}
@ -2803,6 +2660,54 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
return true;
}
// Try to update existing SetProp setter call stubs for the given holder in
// place with a new shape and setter.
static bool
UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub,
ICStub::Kind kind,
NativeObject* holder,
JSObject* receiver,
JSFunction* setter)
{
MOZ_ASSERT(kind == ICStub::SetProp_CallScripted ||
kind == ICStub::SetProp_CallNative);
MOZ_ASSERT(holder);
MOZ_ASSERT(receiver);
bool isOwnSetter = (holder == receiver);
bool foundMatchingStub = false;
ReceiverGuard receiverGuard(receiver);
for (ICStubConstIterator iter = fallbackStub->beginChainConst(); !iter.atEnd(); iter++) {
if (iter->kind() == kind) {
ICSetPropCallSetter* setPropStub = static_cast<ICSetPropCallSetter*>(*iter);
if (setPropStub->holder() == holder && setPropStub->isOwnSetter() == isOwnSetter) {
// If this is an own setter, update the receiver guard as well,
// since that's the shape we'll be guarding on. Furthermore,
// isOwnSetter() relies on holderShape_ and receiverGuard_ being
// the same shape.
if (isOwnSetter)
setPropStub->receiverGuard().update(receiverGuard);
MOZ_ASSERT(setPropStub->holderShape() != holder->lastProperty() ||
!setPropStub->receiverGuard().matches(receiverGuard),
"Why didn't we end up using this stub?");
// We want to update the holder shape to match the new one no
// matter what, even if the receiver shape is different.
setPropStub->holderShape() = holder->lastProperty();
// Make sure to update the setter, since a shape change might
// have changed which setter we want to use.
setPropStub->setter() = setter;
if (setPropStub->receiverGuard().matches(receiverGuard))
foundMatchingStub = true;
}
}
}
return foundMatchingStub;
}
// Attach an optimized property set stub for a SETPROP/SETGNAME/SETNAME op on
// an accessor property.
static bool

View File

@ -11,6 +11,8 @@
#include "jit/BaselineIC.h"
#include "jit/CacheIRCompiler.h"
#include "jsscriptinlines.h"
#include "vm/EnvironmentObject-inl.h"
#include "vm/ObjectGroup-inl.h"
@ -670,22 +672,6 @@ BaselineInspector::templateCallObject()
return &res->as<CallObject>();
}
static Shape*
GlobalShapeForGetPropFunction(ICStub* stub)
{
if (stub->isGetProp_CallNativeGlobal()) {
ICGetProp_CallNativeGlobal* nstub = stub->toGetProp_CallNativeGlobal();
if (nstub->isOwnGetter())
return nullptr;
Shape* shape = nstub->globalShape();
MOZ_ASSERT(shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL);
return shape;
}
return nullptr;
}
static bool
MatchCacheIRReceiverGuard(CacheIRReader& reader, ICCacheIR_Monitored* stub, ObjOperandId objId,
ReceiverGuard* receiver)
@ -734,12 +720,89 @@ MatchCacheIRReceiverGuard(CacheIRReader& reader, ICCacheIR_Monitored* stub, ObjO
return true;
}
static bool
AddCacheIRGlobalGetter(ICCacheIR_Monitored* stub, bool innerized,
JSObject** holder_, Shape** holderShape_,
JSFunction** commonGetter, Shape** globalShape_, bool* isOwnProperty,
BaselineInspector::ReceiverVector& receivers,
BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
JSScript* script)
{
// We are matching on the IR generated by tryAttachGlobalNameGetter:
//
// GuardShape objId
// globalId = LoadEnclosingEnvironment objId
// GuardShape globalId
// <holderId = LoadObject <holder>>
// <GuardShape holderId>
// CallNativeGetterResult globalId
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardShape, objId))
return false;
Shape* globalLexicalShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
if (!reader.matchOp(CacheOp::LoadEnclosingEnvironment, objId))
return false;
ObjOperandId globalId = reader.objOperandId();
if (!reader.matchOp(CacheOp::GuardShape, globalId))
return false;
Shape* globalShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
MOZ_ASSERT(globalShape->getObjectClass()->flags & JSCLASS_IS_GLOBAL);
JSObject* holder = &script->global();
Shape* holderShape = globalShape;
if (reader.matchOp(CacheOp::LoadObject)) {
ObjOperandId holderId = reader.objOperandId();
holder = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
if (!reader.matchOp(CacheOp::GuardShape, holderId))
return false;
holderShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
}
// This guard will always fail, try the next stub.
if (holder->as<NativeObject>().lastProperty() != holderShape)
return true;
if (!reader.matchOp(CacheOp::CallNativeGetterResult, globalId))
return false;
size_t offset = reader.stubOffset();
JSFunction* getter =
&stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
ReceiverGuard receiver;
receiver.shape = globalLexicalShape;
if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
return false;
if (!*commonGetter) {
*holder_ = holder;
*holderShape_ = holderShape;
*commonGetter = getter;
*globalShape_ = globalShape;
// This is always false, because the getters never live on the globalLexical.
*isOwnProperty = false;
} else if (*isOwnProperty || holderShape != *holderShape_ || globalShape != *globalShape_) {
return false;
} else {
MOZ_ASSERT(*commonGetter == getter);
}
return true;
}
static bool
AddCacheIRGetPropFunction(ICCacheIR_Monitored* stub, bool innerized,
JSObject** holder, Shape** holderShape,
JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty,
BaselineInspector::ReceiverVector& receivers,
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
JSScript* script)
{
// We match either an own getter:
//
@ -768,8 +831,11 @@ AddCacheIRGetPropFunction(ICCacheIR_Monitored* stub, bool innerized,
CacheIRReader reader(stub->stubInfo());
ObjOperandId objId = ObjOperandId(0);
if (!reader.matchOp(CacheOp::GuardIsObject, objId))
return false;
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape, commonGetter,
globalShape, isOwnProperty, receivers, convertUnboxedGroups,
script);
}
if (innerized) {
if (!reader.matchOp(CacheOp::GuardClass, objId) ||
@ -880,31 +946,11 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, bool innerized,
const ICEntry& entry = icEntryFromPC(pc);
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isGetProp_CallNativeGlobal()) {
ICGetPropCallGetter* nstub = static_cast<ICGetPropCallGetter*>(stub);
bool isOwn = nstub->isOwnGetter();
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
return false;
if (!*commonGetter) {
*holder = isOwn ? nullptr : nstub->holder().get();
*holderShape = nstub->holderShape();
*commonGetter = nstub->getter();
*globalShape = GlobalShapeForGetPropFunction(nstub);
*isOwnProperty = isOwn;
} else if (nstub->holderShape() != *holderShape ||
GlobalShapeForGetPropFunction(nstub) != *globalShape ||
isOwn != *isOwnProperty)
{
return false;
} else {
MOZ_ASSERT(*commonGetter == nstub->getter());
}
} else if (stub->isCacheIR_Monitored()) {
if (stub->isCacheIR_Monitored()) {
if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), innerized,
holder, holderShape,
commonGetter, globalShape, isOwnProperty, receivers,
convertUnboxedGroups))
convertUnboxedGroups, script))
{
return false;
}

View File

@ -30,12 +30,14 @@ IRGenerator::IRGenerator(JSContext* cx, jsbytecode* pc, CacheKind cacheKind)
GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, jsbytecode* pc, CacheKind cacheKind,
ICStubEngine engine,
bool* isTemporarilyUnoptimizable,
HandleValue val, HandleValue idVal)
HandleValue val, HandleValue idVal,
CanAttachGetter canAttachGetter)
: IRGenerator(cx, pc, cacheKind),
val_(val),
idVal_(idVal),
engine_(engine),
isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
canAttachGetter_(canAttachGetter),
preliminaryObjectAction_(PreliminaryObjectAction::None)
{}
@ -223,7 +225,8 @@ enum NativeGetPropCacheability {
static NativeGetPropCacheability
CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
MutableHandleNativeObject holder, MutableHandleShape shape,
jsbytecode* pc, ICStubEngine engine, bool* isTemporarilyUnoptimizable)
jsbytecode* pc, ICStubEngine engine, CanAttachGetter canAttachGetter,
bool* isTemporarilyUnoptimizable)
{
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
@ -253,6 +256,9 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc))
return CanAttachReadSlot;
if (canAttachGetter == CanAttachGetter::No)
return CanAttachNone;
if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable)) {
// See bug 1226816.
if (engine != ICStubEngine::IonSharedIC)
@ -425,7 +431,8 @@ GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId, Handle
RootedNativeObject holder(cx_);
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
engine_, isTemporarilyUnoptimizable_);
engine_, canAttachGetter_,
isTemporarilyUnoptimizable_);
MOZ_ASSERT_IF(idempotent(),
type == CanAttachNone || (type == CanAttachReadSlot && holder));
switch (type) {
@ -476,7 +483,8 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, H
RootedShape shape(cx_);
RootedNativeObject holder(cx_);
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
engine_, isTemporarilyUnoptimizable_);
engine_, canAttachGetter_,
isTemporarilyUnoptimizable_);
if (type != CanAttachCallGetter ||
!IsCacheableGetPropCallNative(windowObj, holder, shape))
{
@ -584,7 +592,7 @@ GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId o
RootedShape shape(cx_);
NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
pc_, engine_,
pc_, engine_, canAttachGetter_,
isTemporarilyUnoptimizable_);
MOZ_ASSERT_IF(idempotent(),
canCache == CanAttachNone || (canCache == CanAttachReadSlot && holder));
@ -1153,12 +1161,44 @@ GetNameIRGenerator::tryAttachStub()
if (tryAttachGlobalNameValue(envId, id))
return true;
if (tryAttachGlobalNameGetter(envId, id))
return true;
if (tryAttachEnvironmentName(envId, id))
return true;
return false;
}
bool
CanAttachGlobalName(JSContext* cx, Handle<LexicalEnvironmentObject*> globalLexical, HandleId id,
MutableHandleNativeObject holder, MutableHandleShape shape)
{
// The property must be found, and it must be found as a normal data property.
RootedNativeObject current(cx, globalLexical);
while (true) {
shape.set(current->lookup(cx, id));
if (shape)
break;
if (current == globalLexical) {
current = &globalLexical->global();
} else {
// In the browser the global prototype chain should be immutable.
if (!current->staticPrototypeIsImmutable())
return false;
JSObject* proto = current->staticPrototype();
if (!proto || !proto->is<NativeObject>())
return false;
current = &proto->as<NativeObject>();
}
}
holder.set(current);
return true;
}
bool
GetNameIRGenerator::tryAttachGlobalNameValue(ObjOperandId objId, HandleId id)
{
@ -1168,44 +1208,31 @@ GetNameIRGenerator::tryAttachGlobalNameValue(ObjOperandId objId, HandleId id)
Handle<LexicalEnvironmentObject*> globalLexical = env_.as<LexicalEnvironmentObject>();
MOZ_ASSERT(globalLexical->isGlobal());
// The property must be found, and it must be found as a normal data property.
RootedShape shape(cx_);
RootedNativeObject current(cx_, globalLexical);
while (true) {
shape = current->lookup(cx_, id);
if (shape)
break;
if (current == globalLexical) {
current = &globalLexical->global();
} else {
// In the browser the global prototype chain should be immutable.
if (!current->staticPrototypeIsImmutable())
return false;
JSObject* proto = current->staticPrototype();
if (!proto || !proto->is<NativeObject>())
return false;
current = &proto->as<NativeObject>();
}
}
RootedNativeObject holder(cx_);
RootedShape shape(cx_);
if (!CanAttachGlobalName(cx_, globalLexical, id, &holder, &shape))
return false;
// The property must be found, and it must be found as a normal data property.
if (!shape->hasDefaultGetter() || !shape->hasSlot())
return false;
// Instantiate this global property, for use during Ion compilation.
if (IsIonEnabled(cx_))
EnsureTrackPropertyTypes(cx_, current, id);
EnsureTrackPropertyTypes(cx_, holder, id);
if (current == globalLexical) {
if (holder == globalLexical) {
// There is no need to guard on the shape. Lexical bindings are
// non-configurable, and this stub cannot be shared across globals.
size_t dynamicSlotOffset = current->dynamicSlotIndex(shape->slot()) * sizeof(Value);
size_t dynamicSlotOffset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
writer.loadDynamicSlotResult(objId, dynamicSlotOffset);
} else {
// Check the prototype chain from the global to the current
// Check the prototype chain from the global to the holder
// prototype. Ignore the global lexical scope as it doesn't figure
// into the prototype chain. We guard on the global lexical
// scope's shape independently.
if (!IsCacheableGetPropReadSlotForIonOrCacheIR(&globalLexical->global(), current, shape))
if (!IsCacheableGetPropReadSlotForIonOrCacheIR(&globalLexical->global(), holder, shape))
return false;
// Shape guard for global lexical.
@ -1216,19 +1243,59 @@ GetNameIRGenerator::tryAttachGlobalNameValue(ObjOperandId objId, HandleId id)
writer.guardShape(globalId, globalLexical->global().lastProperty());
ObjOperandId holderId = globalId;
if (current != &globalLexical->global()) {
if (holder != &globalLexical->global()) {
// Shape guard holder.
holderId = writer.loadObject(current);
writer.guardShape(holderId, current->lastProperty());
holderId = writer.loadObject(holder);
writer.guardShape(holderId, holder->lastProperty());
}
EmitLoadSlotResult(writer, holderId, current, shape);
EmitLoadSlotResult(writer, holderId, holder, shape);
}
writer.typeMonitorResult();
return true;
}
bool
GetNameIRGenerator::tryAttachGlobalNameGetter(ObjOperandId objId, HandleId id)
{
if (!IsGlobalOp(JSOp(*pc_)) || script_->hasNonSyntacticScope())
return false;
Handle<LexicalEnvironmentObject*> globalLexical = env_.as<LexicalEnvironmentObject>();
MOZ_ASSERT(globalLexical->isGlobal());
RootedNativeObject holder(cx_);
RootedShape shape(cx_);
if (!CanAttachGlobalName(cx_, globalLexical, id, &holder, &shape))
return false;
if (holder == globalLexical)
return false;
if (!IsCacheableGetPropCallNative(&globalLexical->global(), holder, shape))
return false;
if (IsIonEnabled(cx_))
EnsureTrackPropertyTypes(cx_, holder, id);
// Shape guard for global lexical.
writer.guardShape(objId, globalLexical->lastProperty());
// Guard on the shape of the GlobalObject.
ObjOperandId globalId = writer.loadEnclosingEnvironment(objId);
writer.guardShape(globalId, globalLexical->global().lastProperty());
if (holder != &globalLexical->global()) {
// Shape guard holder.
ObjOperandId holderId = writer.loadObject(holder);
writer.guardShape(holderId, holder->lastProperty());
}
EmitCallGetterResultNoGuards(writer, &globalLexical->global(), holder, shape, globalId);
return true;
}
bool
GetNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId, HandleId id)
{

View File

@ -720,6 +720,8 @@ class MOZ_RAII IRGenerator
CacheKind cacheKind() const { return cacheKind_; }
};
enum class CanAttachGetter { Yes, No };
// GetPropIRGenerator generates CacheIR for a GetProp IC.
class MOZ_RAII GetPropIRGenerator : public IRGenerator
{
@ -727,6 +729,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
HandleValue idVal_;
ICStubEngine engine_;
bool* isTemporarilyUnoptimizable_;
CanAttachGetter canAttachGetter_;
enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
PreliminaryObjectAction preliminaryObjectAction_;
@ -777,7 +780,8 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
public:
GetPropIRGenerator(JSContext* cx, jsbytecode* pc, CacheKind cacheKind, ICStubEngine engine,
bool* isTemporarilyUnoptimizable, HandleValue val, HandleValue idVal);
bool* isTemporarilyUnoptimizable, HandleValue val, HandleValue idVal,
CanAttachGetter canAttachGetter);
bool tryAttachStub();
bool tryAttachIdempotentStub();
@ -798,6 +802,7 @@ class MOZ_RAII GetNameIRGenerator : public IRGenerator
HandlePropertyName name_;
bool tryAttachGlobalNameValue(ObjOperandId objId, HandleId id);
bool tryAttachGlobalNameGetter(ObjOperandId objId, HandleId id);
bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
public:

View File

@ -127,12 +127,18 @@ IonGetPropertyIC::update(JSContext* cx, HandleScript outerScript, IonGetProperty
bool attached = false;
if (!JitOptions.disableCacheIR && !ic->disabled()) {
if (ic->canAttachStub()) {
// IonBuilder calls PropertyReadNeedsTypeBarrier to determine if it
// needs a type barrier. Unfortunately, PropertyReadNeedsTypeBarrier
// does not account for getters, so we should only attach a getter
// stub if we inserted a type barrier.
CanAttachGetter canAttachGetter =
ic->monitoredResult() ? CanAttachGetter::Yes : CanAttachGetter::No;
jsbytecode* pc = ic->idempotent() ? nullptr : ic->pc();
RootedValue objVal(cx, ObjectValue(*obj));
bool isTemporarilyUnoptimizable;
GetPropIRGenerator gen(cx, pc, ic->kind(), ICStubEngine::IonIC,
&isTemporarilyUnoptimizable,
objVal, idVal);
objVal, idVal, canAttachGetter);
if (ic->idempotent() ? gen.tryAttachIdempotentStub() : gen.tryAttachStub()) {
attached = ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
outerScript);

View File

@ -173,7 +173,7 @@ struct TempObject
"Placement new argument type must inherit from TempObject");
MOZ_ASSERT(pos);
return pos;
}
}
};
template <typename T>

View File

@ -237,6 +237,16 @@ DefaultJitOptions::DefaultJitOptions()
// included in the bounds check.
SET_DEFAULT(wasmFoldOffsets, true);
// Until which wasm bytecode size should we accumulate functions, in order
// to compile efficiently on helper threads (see also bug 1320374).
SET_DEFAULT(wasmBatchThreshold, 10000);
// In order to have different batching thresholds for Ion and the wasm
// baseline, and since a same batch can contain both Ion and baseline
// compiled functions, we make Ion functions weight more by using a scaling
// factor.
SET_DEFAULT(wasmBatchIonScaleFactor, 9);
// Determines whether we suppress using signal handlers
// for interrupting jit-ed code. This is used only for testing.
SET_DEFAULT(ionInterruptWithoutSignals, false);

View File

@ -87,6 +87,8 @@ struct DefaultJitOptions
uint32_t branchPruningBlockSpanFactor;
uint32_t branchPruningEffectfulInstFactor;
uint32_t branchPruningThreshold;
uint32_t wasmBatchThreshold;
uint32_t wasmBatchIonScaleFactor;
mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
mozilla::Maybe<uint32_t> forcedDefaultIonSmallFunctionWarmUpThreshold;
mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;

View File

@ -175,7 +175,6 @@ ICStub::NonCacheIRStubMakesGCCalls(Kind kind)
case Call_ScriptedFunCall:
case Call_StringSplit:
case WarmUpCounter_Fallback:
case GetProp_CallNativeGlobal:
case GetProp_Generic:
case SetProp_CallScripted:
case SetProp_CallNative:
@ -352,15 +351,6 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
break;
}
case ICStub::GetProp_CallNativeGlobal: {
ICGetProp_CallNativeGlobal* callStub = toGetProp_CallNativeGlobal();
callStub->receiverGuard().trace(trc);
TraceEdge(trc, &callStub->holder(), "baseline-getpropcallnativeglobal-stub-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getpropcallnativeglobal-stub-holdershape");
TraceEdge(trc, &callStub->globalShape(), "baseline-getpropcallnativeglobal-stub-globalshape");
TraceEdge(trc, &callStub->getter(), "baseline-getpropcallnativeglobal-stub-getter");
break;
}
case ICStub::SetProp_Native: {
ICSetProp_Native* propStub = toSetProp_Native();
TraceEdge(trc, &propStub->shape(), "baseline-setpropnative-stub-shape");
@ -2108,68 +2098,6 @@ IsCacheableGetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh
return true;
}
// Try to update all existing GetProp/GetName getter call stubs that match the
// given holder in place with a new shape and getter. fallbackStub can be
// either an ICGetProp_Fallback or an ICGetName_Fallback.
//
// If 'getter' is an own property, holder == receiver must be true.
bool
UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
ICStub::Kind kind,
HandleNativeObject holder,
HandleObject receiver,
HandleFunction getter)
{
MOZ_ASSERT(kind == ICStub::GetProp_CallNativeGlobal);
MOZ_ASSERT(fallbackStub->isGetName_Fallback() ||
fallbackStub->isGetProp_Fallback());
MOZ_ASSERT(holder);
MOZ_ASSERT(receiver);
bool isOwnGetter = (holder == receiver);
bool foundMatchingStub = false;
ReceiverGuard receiverGuard(receiver);
for (ICStubConstIterator iter = fallbackStub->beginChainConst(); !iter.atEnd(); iter++) {
if (iter->kind() == kind) {
ICGetPropCallGetter* getPropStub = static_cast<ICGetPropCallGetter*>(*iter);
if (getPropStub->holder() == holder && getPropStub->isOwnGetter() == isOwnGetter) {
// If this is an own getter, update the receiver guard as well,
// since that's the shape we'll be guarding on. Furthermore,
// isOwnGetter() relies on holderShape_ and receiverGuard_ being
// the same shape.
if (isOwnGetter)
getPropStub->receiverGuard().update(receiverGuard);
MOZ_ASSERT(getPropStub->holderShape() != holder->lastProperty() ||
!getPropStub->receiverGuard().matches(receiverGuard) ||
getPropStub->toGetProp_CallNativeGlobal()->globalShape() !=
receiver->as<LexicalEnvironmentObject>().global().lastProperty(),
"Why didn't we end up using this stub?");
// We want to update the holder shape to match the new one no
// matter what, even if the receiver shape is different.
getPropStub->holderShape() = holder->lastProperty();
// Make sure to update the getter, since a shape change might
// have changed which getter we want to use.
getPropStub->getter() = getter;
if (getPropStub->isGetProp_CallNativeGlobal()) {
ICGetProp_CallNativeGlobal* globalStub =
getPropStub->toGetProp_CallNativeGlobal();
globalStub->globalShape() =
receiver->as<LexicalEnvironmentObject>().global().lastProperty();
}
if (getPropStub->receiverGuard().matches(receiverGuard))
foundMatchingStub = true;
}
}
}
return foundMatchingStub;
}
bool
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, jsid id,
JSObject** lastProto, size_t* protoChainDepthOut)
@ -2296,7 +2224,7 @@ DoGetPropFallback(JSContext* cx, void* payload, ICGetProp_Fallback* stub_,
if (!attached && !JitOptions.disableCacheIR) {
RootedValue idVal(cx, StringValue(name));
GetPropIRGenerator gen(cx, pc, CacheKind::GetProp, engine, &isTemporarilyUnoptimizable,
val, idVal);
val, idVal, CanAttachGetter::Yes);
if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
engine, info.outerScript(cx), stub);
@ -2430,18 +2358,6 @@ GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
}
}
static void
GuardGlobalObject(MacroAssembler& masm, HandleObject holder, Register globalLexicalReg,
Register holderReg, Register scratch, size_t globalShapeOffset, Label* failure)
{
if (holder->is<GlobalObject>())
return;
masm.extractObject(Address(globalLexicalReg, EnvironmentObject::offsetOfEnclosingEnvironment()),
holderReg);
masm.loadPtr(Address(ICStubReg, globalShapeOffset), scratch);
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, failure);
}
bool
GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle<ShapeVector> shapes)
{
@ -2457,135 +2373,6 @@ GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle<ShapeVector>
return true;
}
//
// VM function to help call native getters.
//
bool
DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result)
{
MOZ_ASSERT(callee->isNative());
JSNative natfun = callee->native();
JS::AutoValueArray<2> vp(cx);
vp[0].setObject(*callee.get());
vp[1].setObject(*obj.get());
if (!natfun(cx, 0, vp.begin()))
return false;
result.set(vp[0]);
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter, "DoCallNativeGetter");
bool
ICGetPropCallNativeCompiler::generateStubCode(MacroAssembler& masm)
{
Label failure;
AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
Register objReg = InvalidReg;
if (inputDefinitelyObject_) {
objReg = R0.scratchReg();
} else {
// Guard input is an object and unbox.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
objReg = masm.extractObject(R0, ExtractTemp0);
}
Register scratch = regs.takeAnyExcluding(ICTailCallReg);
// Shape guard.
GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
ICGetPropCallGetter::offsetOfReceiverGuard(), &failure);
if (receiver_ != holder_) {
Register holderReg = regs.takeAny();
// If we are generating a non-lexical GETGNAME stub, we must also
// guard on the shape of the GlobalObject.
if (kind == ICStub::GetProp_CallNativeGlobal) {
MOZ_ASSERT(receiver_->is<LexicalEnvironmentObject>() &&
receiver_->as<LexicalEnvironmentObject>().isGlobal());
GuardGlobalObject(masm, holder_, objReg, holderReg, scratch,
ICGetProp_CallNativeGlobal::offsetOfGlobalShape(), &failure);
}
masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfHolder()), holderReg);
masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfHolderShape()), scratch);
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure);
regs.add(holderReg);
}
// Box and push obj onto baseline frame stack for decompiler
if (engine_ == Engine::Baseline) {
if (inputDefinitelyObject_)
masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
EmitStowICValues(masm, 1);
if (inputDefinitelyObject_)
objReg = masm.extractObject(R0, ExtractTemp0);
}
// Push a stub frame so that we can perform a non-tail call.
enterStubFrame(masm, scratch);
// Load callee function.
Register callee = regs.takeAny();
masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfGetter()), callee);
// If we're calling a getter on the global, inline the logic for the
// 'this' hook on the global lexical scope and manually push the global.
if (kind == ICStub::GetProp_CallNativeGlobal)
masm.extractObject(Address(objReg, EnvironmentObject::offsetOfEnclosingEnvironment()),
objReg);
// Push args for vm call.
masm.Push(objReg);
masm.Push(callee);
regs.add(R0);
if (!callVM(DoCallNativeGetterInfo, masm))
return false;
leaveStubFrame(masm);
if (engine_ == Engine::Baseline)
EmitUnstowICValues(masm, 1, /* discard = */true);
// Enter type monitor IC to type-check result.
EmitEnterTypeMonitorIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
ICStub*
ICGetPropCallNativeCompiler::getStub(ICStubSpace* space)
{
ReceiverGuard guard(receiver_);
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
switch (kind) {
case ICStub::GetProp_CallNativeGlobal: {
Shape* globalShape = receiver_->as<LexicalEnvironmentObject>().global().lastProperty();
return newStub<ICGetProp_CallNativeGlobal>(space, getStubCode(), firstMonitorStub_,
guard, holder_, holderShape, globalShape,
getter_, pcOffset_);
}
default:
MOZ_CRASH("Bad stub kind");
}
}
/* static */ ICGetProp_Generic*
ICGetProp_Generic::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
ICGetProp_Generic& other)
@ -2678,31 +2465,6 @@ BaselineScript::noteAccessedGetter(uint32_t pcOffset)
stub->toGetProp_Fallback()->noteAccessedGetter();
}
ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
ReceiverGuard receiverGuard, JSObject* holder,
Shape* holderShape, JSFunction* getter,
uint32_t pcOffset)
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
receiverGuard_(receiverGuard),
holder_(holder),
holderShape_(holderShape),
getter_(getter),
pcOffset_(pcOffset)
{
MOZ_ASSERT(kind == ICStub::GetProp_CallNativeGlobal);
}
/* static */ ICGetProp_CallNativeGlobal*
ICGetProp_CallNativeGlobal::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
ICGetProp_CallNativeGlobal& other)
{
return New<ICGetProp_CallNativeGlobal>(cx, space, other.jitCode(), firstMonitorStub,
other.receiverGuard(), other.holder_,
other.holderShape_, other.globalShape_,
other.getter_, other.pcOffset_);
}
//
// TypeMonitor_Fallback
//

View File

@ -2256,10 +2256,6 @@ GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle<ShapeVector>
void
CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
MOZ_MUST_USE bool
DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result);
void
LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result);
@ -2384,158 +2380,6 @@ ReferenceTypeFromSimpleTypeDescrKey(uint32_t key)
return ReferenceTypeDescr::Type(key >> 1);
}
class ICGetPropCallGetter : public ICMonitoredStub
{
friend class ICStubSpace;
protected:
// Shape/group of receiver object. Used for both own and proto getters.
// In the GetPropCallDOMProxyNative case, the receiver guard enforces
// the proxy handler, because Shape implies Class.
HeapReceiverGuard receiverGuard_;
// Holder and holder shape. For own getters, guarding on receiverGuard_ is
// sufficient, although Ion may use holder_ and holderShape_ even for own
// getters. In this case holderShape_ == receiverGuard_.shape_ (isOwnGetter
// below relies on this).
GCPtrObject holder_;
GCPtrShape holderShape_;
// Function to call.
GCPtrFunction getter_;
// PC offset of call
uint32_t pcOffset_;
ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
ReceiverGuard receiverGuard, JSObject* holder,
Shape* holderShape, JSFunction* getter, uint32_t pcOffset);
public:
GCPtrObject& holder() {
return holder_;
}
GCPtrShape& holderShape() {
return holderShape_;
}
GCPtrFunction& getter() {
return getter_;
}
HeapReceiverGuard& receiverGuard() {
return receiverGuard_;
}
bool isOwnGetter() const {
MOZ_ASSERT(holder_->isNative());
MOZ_ASSERT(holderShape_);
return receiverGuard_.shape() == holderShape_;
}
static size_t offsetOfHolder() {
return offsetof(ICGetPropCallGetter, holder_);
}
static size_t offsetOfHolderShape() {
return offsetof(ICGetPropCallGetter, holderShape_);
}
static size_t offsetOfGetter() {
return offsetof(ICGetPropCallGetter, getter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetPropCallGetter, pcOffset_);
}
static size_t offsetOfReceiverGuard() {
return offsetof(ICGetPropCallGetter, receiverGuard_);
}
class Compiler : public ICStubCompiler {
protected:
ICStub* firstMonitorStub_;
RootedObject receiver_;
RootedObject holder_;
RootedFunction getter_;
uint32_t pcOffset_;
virtual int32_t getKey() const {
// ICGetPropCallNativeCompiler::getKey adds more bits to our
// return value, so be careful when making changes here.
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(HeapReceiverGuard::keyBits(receiver_) << 17) |
(static_cast<int32_t>(receiver_ != holder_) << 19);
}
public:
Compiler(JSContext* cx, ICStub::Kind kind, Engine engine, ICStub* firstMonitorStub,
HandleObject receiver, HandleObject holder, HandleFunction getter,
uint32_t pcOffset)
: ICStubCompiler(cx, kind, engine),
firstMonitorStub_(firstMonitorStub),
receiver_(cx, receiver),
holder_(cx, holder),
getter_(cx, getter),
pcOffset_(pcOffset)
{
MOZ_ASSERT(kind == ICStub::GetProp_CallNativeGlobal);
}
};
};
// Stub for calling a native getter on the GlobalObject.
class ICGetProp_CallNativeGlobal : public ICGetPropCallGetter
{
friend class ICStubSpace;
protected:
GCPtrShape globalShape_;
ICGetProp_CallNativeGlobal(JitCode* stubCode, ICStub* firstMonitorStub,
ReceiverGuard receiverGuard,
JSObject* holder, Shape* holderShape, Shape* globalShape,
JSFunction* getter, uint32_t pcOffset)
: ICGetPropCallGetter(GetProp_CallNativeGlobal, stubCode, firstMonitorStub,
receiverGuard, holder, holderShape, getter, pcOffset),
globalShape_(globalShape)
{ }
public:
static ICGetProp_CallNativeGlobal* Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub,
ICGetProp_CallNativeGlobal& other);
GCPtrShape& globalShape() {
return globalShape_;
}
static size_t offsetOfGlobalShape() {
return offsetof(ICGetProp_CallNativeGlobal, globalShape_);
}
};
class ICGetPropCallNativeCompiler : public ICGetPropCallGetter::Compiler
{
bool inputDefinitelyObject_;
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
virtual int32_t getKey() const {
int32_t baseKey = ICGetPropCallGetter::Compiler::getKey();
MOZ_ASSERT((baseKey >> 21) == 0);
return baseKey | (static_cast<int32_t>(inputDefinitelyObject_) << 21);
}
public:
ICGetPropCallNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStubCompiler::Engine engine,
ICStub* firstMonitorStub, HandleObject receiver,
HandleObject holder, HandleFunction getter, uint32_t pcOffset,
bool inputDefinitelyObject = false)
: ICGetPropCallGetter::Compiler(cx, kind, engine, firstMonitorStub, receiver, holder,
getter, pcOffset),
inputDefinitelyObject_(inputDefinitelyObject)
{}
ICStub* getStub(ICStubSpace* space);
};
// JSOP_NEWARRAY
// JSOP_NEWINIT

View File

@ -35,7 +35,6 @@ namespace jit {
_(Compare_Int32WithBoolean) \
\
_(GetProp_Fallback) \
_(GetProp_CallNativeGlobal) \
_(GetProp_Generic) \
\
_(CacheIR_Monitored) \

View File

@ -1372,6 +1372,24 @@ ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
return Proxy::get(cx, proxy, receiver, id, vp);
}
bool
CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result)
{
MOZ_ASSERT(callee->isNative());
JSNative natfun = callee->native();
JS::AutoValueArray<2> vp(cx);
vp[0].setObject(*callee.get());
vp[1].setObject(*obj.get());
if (!natfun(cx, 0, vp.begin()))
return false;
result.set(vp[0]);
return true;
}
bool
EqualStringsHelper(JSString* str1, JSString* str2)
{

View File

@ -818,6 +818,11 @@ MOZ_MUST_USE bool
ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
MutableHandleValue vp);
MOZ_MUST_USE bool
CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result);
MOZ_MUST_USE bool
EqualStringsHelper(JSString* str1, JSString* str2);

View File

@ -8436,9 +8436,11 @@ StoreAsmJSModuleInCache(AsmJSParser& parser, Module& module, ExclusiveContext* c
size_t bytecodeSize, compiledSize;
module.serializedSize(&bytecodeSize, &compiledSize);
MOZ_RELEASE_ASSERT(bytecodeSize == 0);
MOZ_RELEASE_ASSERT(compiledSize <= UINT32_MAX);
size_t serializedSize = 2 * sizeof(uint32_t) +
bytecodeSize + compiledSize +
size_t serializedSize = sizeof(uint32_t) +
compiledSize +
moduleChars.serializedSize();
JS::OpenAsmJSCacheEntryForWriteOp open = cx->asmJSCacheOps().openEntryForWrite;
@ -8461,16 +8463,10 @@ StoreAsmJSModuleInCache(AsmJSParser& parser, Module& module, ExclusiveContext* c
// between any two builds (regardless of platform, architecture, ...).
// (The Module::assumptionsMatch() guard everything in the Module and
// afterwards.)
MOZ_RELEASE_ASSERT(bytecodeSize <= UINT32_MAX);
MOZ_RELEASE_ASSERT(compiledSize <= UINT32_MAX);
cursor = WriteScalar<uint32_t>(cursor, bytecodeSize);
cursor = WriteScalar<uint32_t>(cursor, compiledSize);
uint8_t* compiledBegin = cursor;
uint8_t* bytecodeBegin = compiledBegin + compiledSize;;
module.serialize(bytecodeBegin, bytecodeSize, compiledBegin, compiledSize);
cursor = bytecodeBegin + bytecodeSize;
module.serialize(/* bytecodeBegin = */ nullptr, /* bytecodeSize = */ 0, cursor, compiledSize);
cursor += compiledSize;
cursor = moduleChars.serialize(cursor);
@ -8501,33 +8497,29 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
size_t remain = entry.serializedSize;
const uint8_t* cursor = entry.memory;
uint32_t bytecodeSize, compiledSize;
(cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &bytecodeSize)) &&
(cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &compiledSize));
uint32_t compiledSize;
cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &compiledSize);
if (!cursor)
return true;
const uint8_t* compiledBegin = cursor;
const uint8_t* bytecodeBegin = compiledBegin + compiledSize;
Assumptions assumptions;
if (!assumptions.initBuildIdFromContext(cx))
return false;
if (!Module::assumptionsMatch(assumptions, compiledBegin, remain))
if (!Module::assumptionsMatch(assumptions, cursor, remain))
return true;
MutableAsmJSMetadata asmJSMetadata = cx->new_<AsmJSMetadata>();
if (!asmJSMetadata)
return false;
*module = Module::deserialize(bytecodeBegin, bytecodeSize, compiledBegin, compiledSize,
asmJSMetadata.get());
*module = Module::deserialize(/* bytecodeBegin = */ nullptr, /* bytecodeSize = */ 0,
cursor, compiledSize, asmJSMetadata.get());
if (!*module) {
ReportOutOfMemory(cx);
return false;
}
cursor = bytecodeBegin + bytecodeSize;
cursor += compiledSize;
// Due to the hash comparison made by openEntryForRead, this should succeed
// with high probability.

View File

@ -512,7 +512,7 @@ class BaseCompiler
Assembler::Condition latentIntCmp_; // Comparison operator, if latentOp_ == Compare, int types
Assembler::DoubleCondition latentDoubleCmp_;// Comparison operator, if latentOp_ == Compare, float types
FuncCompileResults& compileResults_;
FuncOffsets offsets_;
MacroAssembler& masm; // No '_' suffix - too tedious...
AllocatableGeneralRegisterSet availGPR_;
@ -567,11 +567,12 @@ class BaseCompiler
Decoder& decoder,
const FuncBytes& func,
const ValTypeVector& locals,
FuncCompileResults& compileResults);
TempAllocator* alloc,
MacroAssembler* masm);
MOZ_MUST_USE bool init();
void finish();
FuncOffsets finish();
MOZ_MUST_USE bool emitFunction();
@ -2053,7 +2054,7 @@ class BaseCompiler
JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
SigIdDesc sigId = env_.funcSigs[func_.index()]->id;
GenerateFunctionPrologue(masm, localSize_, sigId, &compileResults_.offsets());
GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_);
MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_));
@ -2148,7 +2149,7 @@ class BaseCompiler
// Restore the TLS register in case it was overwritten by the function.
loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
GenerateFunctionEpilogue(masm, localSize_, &compileResults_.offsets());
GenerateFunctionEpilogue(masm, localSize_, &offsets_);
#if defined(JS_ION_PERF)
// FIXME - profiling code missing. Bug 1286948.
@ -2162,7 +2163,7 @@ class BaseCompiler
masm.wasmEmitTrapOutOfLineCode();
compileResults_.offsets().end = masm.currentOffset();
offsets_.end = masm.currentOffset();
// A frame greater than 256KB is implausible, probably an attack,
// so fail the compilation.
@ -7540,12 +7541,13 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
Decoder& decoder,
const FuncBytes& func,
const ValTypeVector& locals,
FuncCompileResults& compileResults)
TempAllocator* alloc,
MacroAssembler* masm)
: env_(env),
iter_(decoder, func.lineOrBytecode()),
func_(func),
lastReadCallSite_(0),
alloc_(compileResults.alloc()),
alloc_(*alloc),
locals_(locals),
localSize_(0),
varLow_(0),
@ -7558,8 +7560,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
latentType_(ValType::I32),
latentIntCmp_(Assembler::Equal),
latentDoubleCmp_(Assembler::DoubleEqual),
compileResults_(compileResults),
masm(compileResults_.masm()),
masm(*masm),
availGPR_(GeneralRegisterSet::All()),
availFPU_(FloatRegisterSet::All()),
#ifdef DEBUG
@ -7702,13 +7703,15 @@ BaseCompiler::init()
return true;
}
void
FuncOffsets
BaseCompiler::finish()
{
MOZ_ASSERT(done(), "all bytes must be consumed");
MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
masm.flushBuffer();
return offsets_;
}
static LiveRegisterSet
@ -7756,12 +7759,11 @@ js::wasm::BaselineCanCompile(const FunctionGenerator* fg)
}
bool
js::wasm::BaselineCompileFunction(CompileTask* task)
js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit)
{
MOZ_ASSERT(task->mode() == CompileTask::CompileMode::Baseline);
MOZ_ASSERT(unit->mode() == CompileMode::Baseline);
const FuncBytes& func = task->func();
FuncCompileResults& results = task->results();
const FuncBytes& func = unit->func();
Decoder d(func.bytes());
@ -7775,19 +7777,18 @@ js::wasm::BaselineCompileFunction(CompileTask* task)
// The MacroAssembler will sometimes access the jitContext.
JitContext jitContext(&results.alloc());
JitContext jitContext(&task->alloc());
// One-pass baseline compilation.
BaseCompiler f(task->env(), d, func, locals, results);
BaseCompiler f(task->env(), d, func, locals, &task->alloc(), &task->masm());
if (!f.init())
return false;
if (!f.emitFunction())
return false;
f.finish();
unit->finish(f.finish());
return true;
}

View File

@ -24,6 +24,7 @@ namespace wasm {
class FunctionGenerator;
class CompileTask;
class FuncCompileUnit;
// Return true if BaselineCompileFunction can generate code for the
// function held in the FunctionGenerator. If false is returned a
@ -39,7 +40,7 @@ BaselineCanCompile(const FunctionGenerator* fg);
// Generate adequate code quickly.
bool
BaselineCompileFunction(CompileTask* task);
BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit);
} // namespace wasm
} // namespace js

View File

@ -19,7 +19,6 @@
#ifndef wasm_compile_h
#define wasm_compile_h
#include "wasm/WasmJS.h"
#include "wasm/WasmModule.h"
namespace js {
@ -40,7 +39,7 @@ struct CompileArgs
{
Assumptions assumptions;
ScriptedCaller scriptedCaller;
MOZ_INIT_OUTSIDE_CTOR bool alwaysBaseline;
bool alwaysBaseline;
CompileArgs(Assumptions&& assumptions, ScriptedCaller&& scriptedCaller)
: assumptions(Move(assumptions)),

View File

@ -55,6 +55,8 @@ ModuleGenerator::ModuleGenerator()
startOfUnpatchedCallsites_(0),
parallel_(false),
outstanding_(0),
currentTask_(nullptr),
batchedBytecode_(0),
activeFuncDef_(nullptr),
startedFuncDefs_(false),
finishedFuncDefs_(false),
@ -96,6 +98,8 @@ ModuleGenerator::~ModuleGenerator()
} else {
MOZ_ASSERT(!outstanding_);
}
MOZ_ASSERT_IF(finishedFuncDefs_, !batchedBytecode_);
MOZ_ASSERT_IF(finishedFuncDefs_, !currentTask_);
}
bool
@ -391,42 +395,45 @@ ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits)
bool
ModuleGenerator::finishTask(CompileTask* task)
{
const FuncBytes& func = task->func();
FuncCompileResults& results = task->results();
masm_.haltingAlign(CodeAlignment);
// Before merging in the new function's code, if calls in a prior function
// body might go out of range, insert far jumps to extend the range.
if ((masm_.size() - startOfUnpatchedCallsites_) + results.masm().size() > JumpRange()) {
if ((masm_.size() - startOfUnpatchedCallsites_) + task->masm().size() > JumpRange()) {
startOfUnpatchedCallsites_ = masm_.size();
if (!patchCallSites())
return false;
}
// Offset the recorded FuncOffsets by the offset of the function in the
// whole module's code segment.
uint32_t offsetInWhole = masm_.size();
results.offsets().offsetBy(offsetInWhole);
for (const FuncCompileUnit& unit : task->units()) {
const FuncBytes& func = unit.func();
// Add the CodeRange for this function.
uint32_t funcCodeRangeIndex = metadata_->codeRanges.length();
if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
return false;
// Offset the recorded FuncOffsets by the offset of the function in the
// whole module's code segment.
FuncOffsets offsets = unit.offsets();
offsets.offsetBy(offsetInWhole);
MOZ_ASSERT(!funcIsCompiled(func.index()));
funcToCodeRange_[func.index()] = funcCodeRangeIndex;
// Add the CodeRange for this function.
uint32_t funcCodeRangeIndex = metadata_->codeRanges.length();
if (!metadata_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), offsets))
return false;
MOZ_ASSERT(!funcIsCompiled(func.index()));
funcToCodeRange_[func.index()] = funcCodeRangeIndex;
}
// Merge the compiled results into the whole-module masm.
mozilla::DebugOnly<size_t> sizeBefore = masm_.size();
if (!masm_.asmMergeWith(results.masm()))
if (!masm_.asmMergeWith(task->masm()))
return false;
MOZ_ASSERT(masm_.size() == offsetInWhole + task->masm().size());
if (!task->reset(&freeFuncBytes_))
return false;
MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
UniqueBytes recycled;
task->reset(&recycled);
freeTasks_.infallibleAppend(task);
return freeBytes_.emplaceBack(Move(recycled));
return true;
}
bool
@ -864,15 +871,6 @@ ModuleGenerator::startFuncDefs()
for (size_t i = 0; i < numTasks; i++)
freeTasks_.infallibleAppend(&tasks_[i]);
if (!freeBytes_.reserve(numTasks))
return false;
for (size_t i = 0; i < numTasks; i++) {
auto bytes = js::MakeUnique<Bytes>();
if (!bytes)
return false;
freeBytes_.infallibleAppend(Move(bytes));
}
startedFuncDefs_ = true;
MOZ_ASSERT(!finishedFuncDefs_);
return true;
@ -885,58 +883,81 @@ ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
MOZ_ASSERT(!activeFuncDef_);
MOZ_ASSERT(!finishedFuncDefs_);
if (!freeBytes_.empty()) {
fg->bytes_ = Move(freeBytes_.back());
freeBytes_.popBack();
if (!freeFuncBytes_.empty()) {
fg->funcBytes_ = Move(freeFuncBytes_.back());
freeFuncBytes_.popBack();
} else {
fg->bytes_ = js::MakeUnique<Bytes>();
if (!fg->bytes_)
fg->funcBytes_ = js::MakeUnique<FuncBytes>();
if (!fg->funcBytes_)
return false;
}
fg->lineOrBytecode_ = lineOrBytecode;
if (!currentTask_) {
if (freeTasks_.empty() && !finishOutstandingTask())
return false;
currentTask_ = freeTasks_.popCopy();
}
fg->funcBytes_->setLineOrBytecode(lineOrBytecode);
fg->m_ = this;
activeFuncDef_ = fg;
return true;
}
bool
ModuleGenerator::launchBatchCompile()
{
MOZ_ASSERT(currentTask_);
size_t numBatchedFuncs = currentTask_->units().length();
MOZ_ASSERT(numBatchedFuncs);
if (parallel_) {
if (!StartOffThreadWasmCompile(currentTask_))
return false;
outstanding_++;
} else {
if (!CompileFunction(currentTask_))
return false;
if (!finishTask(currentTask_))
return false;
}
currentTask_ = nullptr;
batchedBytecode_ = 0;
numFinishedFuncDefs_ += numBatchedFuncs;
return true;
}
bool
ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg)
{
MOZ_ASSERT(activeFuncDef_ == fg);
auto func = js::MakeUnique<FuncBytes>(Move(fg->bytes_),
funcIndex,
funcSig(funcIndex),
fg->lineOrBytecode_,
Move(fg->callSiteLineNums_));
if (!func)
return false;
UniqueFuncBytes func = Move(fg->funcBytes_);
func->setFunc(funcIndex, &funcSig(funcIndex));
auto mode = alwaysBaseline_ && BaselineCanCompile(fg)
? CompileTask::CompileMode::Baseline
: CompileTask::CompileMode::Ion;
? CompileMode::Baseline
: CompileMode::Ion;
if (freeTasks_.empty() && !finishOutstandingTask())
CheckedInt<uint32_t> newBatched = func->bytes().length();
if (mode == CompileMode::Ion)
newBatched *= JitOptions.wasmBatchIonScaleFactor;
newBatched += batchedBytecode_;
if (!currentTask_->units().emplaceBack(Move(func), mode))
return false;
CompileTask* task = freeTasks_.popCopy();
task->init(Move(func), mode);
if (parallel_) {
if (!StartOffThreadWasmCompile(task))
return false;
outstanding_++;
} else {
if (!CompileFunction(task))
return false;
if (!finishTask(task))
return false;
}
if (newBatched.isValid() && newBatched.value() < JitOptions.wasmBatchThreshold)
batchedBytecode_ = newBatched.value();
else if (!launchBatchCompile())
return false;
fg->m_ = nullptr;
activeFuncDef_ = nullptr;
numFinishedFuncDefs_++;
return true;
}
@ -947,6 +968,9 @@ ModuleGenerator::finishFuncDefs()
MOZ_ASSERT(!activeFuncDef_);
MOZ_ASSERT(!finishedFuncDefs_);
if (currentTask_ && !launchBatchCompile())
return false;
while (outstanding_ > 0) {
if (!finishOutstandingTask())
return false;
@ -1146,14 +1170,18 @@ wasm::CompileFunction(CompileTask* task)
TraceLoggerThread* logger = TraceLoggerForCurrentThread();
AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation);
switch (task->mode()) {
case wasm::CompileTask::CompileMode::Ion:
return wasm::IonCompileFunction(task);
case wasm::CompileTask::CompileMode::Baseline:
return wasm::BaselineCompileFunction(task);
case wasm::CompileTask::CompileMode::None:
break;
for (FuncCompileUnit& unit : task->units()) {
switch (unit.mode()) {
case CompileMode::Ion:
if (!IonCompileFunction(task, &unit))
return false;
break;
case CompileMode::Baseline:
if (!BaselineCompileFunction(task, &unit))
return false;
break;
}
}
MOZ_CRASH("Uninitialized task");
return true;
}

View File

@ -36,124 +36,158 @@ struct CompileArgs;
class FunctionGenerator;
typedef Vector<UniqueBytes, 0, SystemAllocPolicy> UniqueBytesVector;
// The FuncBytes class represents a single, concurrently-compilable function.
// A FuncBytes object is composed of the wasm function body bytes along with the
// ambient metadata describing the function necessary to compile it.
class FuncBytes
{
UniqueBytes bytes_;
Bytes bytes_;
uint32_t index_;
const SigWithId& sig_;
const SigWithId* sig_;
uint32_t lineOrBytecode_;
Uint32Vector callSiteLineNums_;
public:
FuncBytes(UniqueBytes bytes,
uint32_t index,
const SigWithId& sig,
uint32_t lineOrBytecode,
Uint32Vector&& callSiteLineNums)
: bytes_(Move(bytes)),
index_(index),
sig_(sig),
lineOrBytecode_(lineOrBytecode),
callSiteLineNums_(Move(callSiteLineNums))
FuncBytes()
: index_(UINT32_MAX),
sig_(nullptr),
lineOrBytecode_(UINT32_MAX)
{}
Bytes& bytes() { return *bytes_; }
const Bytes& bytes() const { return *bytes_; }
UniqueBytes recycle() { return Move(bytes_); }
Bytes& bytes() {
return bytes_;
}
MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
return callSiteLineNums_.append(lineno);
}
void setLineOrBytecode(uint32_t lineOrBytecode) {
MOZ_ASSERT(lineOrBytecode_ == UINT32_MAX);
lineOrBytecode_ = lineOrBytecode;
}
void setFunc(uint32_t index, const SigWithId* sig) {
MOZ_ASSERT(index_ == UINT32_MAX);
MOZ_ASSERT(sig_ == nullptr);
index_ = index;
sig_ = sig;
}
void reset() {
bytes_.clear();
index_ = UINT32_MAX;
sig_ = nullptr;
lineOrBytecode_ = UINT32_MAX;
callSiteLineNums_.clear();
}
const Bytes& bytes() const { return bytes_; }
uint32_t index() const { return index_; }
const SigWithId& sig() const { return sig_; }
const SigWithId& sig() const { return *sig_; }
uint32_t lineOrBytecode() const { return lineOrBytecode_; }
const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
};
typedef UniquePtr<FuncBytes> UniqueFuncBytes;
typedef Vector<UniqueFuncBytes, 8, SystemAllocPolicy> UniqueFuncBytesVector;
// The FuncCompileResults class contains the results of compiling a single
// function body, ready to be merged into the whole-module MacroAssembler.
class FuncCompileResults
enum class CompileMode
{
jit::TempAllocator alloc_;
jit::MacroAssembler masm_;
FuncOffsets offsets_;
FuncCompileResults(const FuncCompileResults&) = delete;
FuncCompileResults& operator=(const FuncCompileResults&) = delete;
public:
explicit FuncCompileResults(LifoAlloc& lifo)
: alloc_(&lifo),
masm_(jit::MacroAssembler::WasmToken(), alloc_)
{}
jit::TempAllocator& alloc() { return alloc_; }
jit::MacroAssembler& masm() { return masm_; }
FuncOffsets& offsets() { return offsets_; }
Baseline,
Ion
};
// A CompileTask represents the task of compiling a single function body. An
// CompileTask is filled with the wasm code to be compiled on the main
// validation thread, sent off to a compilation helper thread which creates
// the FuncCompileResults, and finally sent back to the validation thread. To
// save time allocating and freeing memory, CompileTasks are reset() and
// reused.
// FuncCompileUnit contains all the data necessary to produce and store the
// results of a single function's compilation.
class FuncCompileUnit
{
UniqueFuncBytes func_;
CompileMode mode_;
FuncOffsets offsets_;
DebugOnly<bool> finished_;
public:
FuncCompileUnit(UniqueFuncBytes func, CompileMode mode)
: func_(Move(func)),
mode_(mode),
finished_(false)
{}
const FuncBytes& func() const { return *func_; }
CompileMode mode() const { return mode_; }
FuncOffsets offsets() const { MOZ_ASSERT(finished_); return offsets_; }
void finish(FuncOffsets offsets) {
MOZ_ASSERT(!finished_);
offsets_ = offsets;
finished_ = true;
}
UniqueFuncBytes recycle() {
MOZ_ASSERT(finished_);
func_->reset();
return Move(func_);
}
};
typedef Vector<FuncCompileUnit, 8, SystemAllocPolicy> FuncCompileUnitVector;
// A CompileTask represents the task of compiling a batch of functions. It is
// filled with a certain number of function's bodies that are sent off to a
// compilation helper thread, which fills in the resulting code offsets, and
// finally sent back to the validation thread. To save time allocating and
// freeing memory, CompileTasks are reset() and reused.
class CompileTask
{
public:
enum class CompileMode { None, Baseline, Ion };
private:
const ModuleEnvironment& env_;
LifoAlloc lifo_;
UniqueFuncBytes func_;
CompileMode mode_;
Maybe<FuncCompileResults> results_;
const ModuleEnvironment& env_;
LifoAlloc lifo_;
Maybe<jit::TempAllocator> alloc_;
Maybe<jit::MacroAssembler> masm_;
FuncCompileUnitVector units_;
CompileTask(const CompileTask&) = delete;
CompileTask& operator=(const CompileTask&) = delete;
void init() {
alloc_.emplace(&lifo_);
masm_.emplace(jit::MacroAssembler::WasmToken(), *alloc_);
}
public:
CompileTask(const ModuleEnvironment& env, size_t defaultChunkSize)
: env_(env), lifo_(defaultChunkSize), func_(nullptr), mode_(CompileMode::None)
{}
: env_(env),
lifo_(defaultChunkSize)
{
init();
}
LifoAlloc& lifo() {
return lifo_;
}
jit::TempAllocator& alloc() {
return *alloc_;
}
const ModuleEnvironment& env() const {
return env_;
}
void init(UniqueFuncBytes func, CompileMode mode) {
MOZ_ASSERT(!func_);
func_ = Move(func);
results_.emplace(lifo_);
mode_ = mode;
jit::MacroAssembler& masm() {
return *masm_;
}
CompileMode mode() const {
return mode_;
FuncCompileUnitVector& units() {
return units_;
}
const FuncBytes& func() const {
MOZ_ASSERT(func_);
return *func_;
}
FuncCompileResults& results() {
return *results_;
}
void reset(UniqueBytes* recycled) {
if (func_) {
*recycled = Move(func_->recycle());
(*recycled)->clear();
bool reset(UniqueFuncBytesVector* freeFuncBytes) {
for (FuncCompileUnit& unit : units_) {
if (!freeFuncBytes->emplaceBack(Move(unit.recycle())))
return false;
}
func_.reset(nullptr);
results_.reset();
units_.clear();
masm_.reset();
alloc_.reset();
lifo_.releaseAll();
mode_ = CompileMode::None;
init();
return true;
}
};
@ -196,7 +230,9 @@ class MOZ_STACK_CLASS ModuleGenerator
uint32_t outstanding_;
CompileTaskVector tasks_;
CompileTaskPtrVector freeTasks_;
UniqueBytesVector freeBytes_;
UniqueFuncBytesVector freeFuncBytes_;
CompileTask* currentTask_;
uint32_t batchedBytecode_;
// Assertions
DebugOnly<FunctionGenerator*> activeFuncDef_;
@ -206,6 +242,7 @@ class MOZ_STACK_CLASS ModuleGenerator
bool funcIsCompiled(uint32_t funcIndex) const;
const CodeRange& funcCodeRange(uint32_t funcIndex) const;
uint32_t numFuncImports() const;
MOZ_MUST_USE bool patchCallSites(TrapExitOffsetArray* maybeTrapExits = nullptr);
MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits);
MOZ_MUST_USE bool finishTask(CompileTask* task);
@ -217,12 +254,11 @@ class MOZ_STACK_CLASS ModuleGenerator
MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
MOZ_MUST_USE bool launchBatchCompile();
MOZ_MUST_USE bool initAsmJS(Metadata* asmJSMetadata);
MOZ_MUST_USE bool initWasm();
// Functions declarations:
uint32_t numFuncImports() const;
public:
explicit ModuleGenerator();
~ModuleGenerator();
@ -275,10 +311,11 @@ class MOZ_STACK_CLASS ModuleGenerator
};
// A FunctionGenerator encapsulates the generation of a single function body.
// ModuleGenerator::startFunc must be called after construction and before doing
// anything else. After the body is complete, ModuleGenerator::finishFunc must
// be called before the FunctionGenerator is destroyed and the next function is
// started.
// ModuleGenerator::startFuncDef must be called after construction and before
// doing anything else.
//
// After the body is complete, ModuleGenerator::finishFuncDef must be called
// before the FunctionGenerator is destroyed and the next function is started.
class MOZ_STACK_CLASS FunctionGenerator
{
@ -288,16 +325,11 @@ class MOZ_STACK_CLASS FunctionGenerator
bool usesSimd_;
bool usesAtomics_;
// Data created during function generation, then handed over to the
// FuncBytes in ModuleGenerator::finishFunc().
UniqueBytes bytes_;
Uint32Vector callSiteLineNums_;
uint32_t lineOrBytecode_;
UniqueFuncBytes funcBytes_;
public:
FunctionGenerator()
: m_(nullptr), usesSimd_(false), usesAtomics_(false), bytes_(nullptr), lineOrBytecode_(0)
: m_(nullptr), usesSimd_(false), usesAtomics_(false), funcBytes_(nullptr)
{}
bool usesSimd() const {
@ -315,10 +347,10 @@ class MOZ_STACK_CLASS FunctionGenerator
}
Bytes& bytes() {
return *bytes_;
return funcBytes_->bytes();
}
MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
return callSiteLineNums_.append(lineno);
return funcBytes_->addCallSiteLineNum(lineno);
}
};

View File

@ -168,8 +168,6 @@ class FunctionCompiler
uint32_t blockDepth_;
ControlFlowPatchsVector blockPatches_;
FuncCompileResults& compileResults_;
// TLS pointer argument to the current function.
MWasmParameter* tlsPointer_;
@ -178,8 +176,7 @@ class FunctionCompiler
Decoder& decoder,
const FuncBytes& func,
const ValTypeVector& locals,
MIRGenerator& mirGen,
FuncCompileResults& compileResults)
MIRGenerator& mirGen)
: env_(env),
iter_(decoder, func.lineOrBytecode()),
func_(func),
@ -194,14 +191,12 @@ class FunctionCompiler
maxStackArgBytes_(0),
loopDepth_(0),
blockDepth_(0),
compileResults_(compileResults),
tlsPointer_(nullptr)
{}
const ModuleEnvironment& env() const { return env_; }
IonOpIter& iter() { return iter_; }
TempAllocator& alloc() const { return alloc_; }
MacroAssembler& masm() const { return compileResults_.masm(); }
const Sig& sig() const { return func_.sig(); }
TrapOffset trapOffset() const {
@ -3697,12 +3692,12 @@ EmitExpr(FunctionCompiler& f)
}
bool
wasm::IonCompileFunction(CompileTask* task)
wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit)
{
MOZ_ASSERT(task->mode() == CompileTask::CompileMode::Ion);
MOZ_ASSERT(unit->mode() == CompileMode::Ion);
const FuncBytes& func = task->func();
FuncCompileResults& results = task->results();
const FuncBytes& func = unit->func();
const ModuleEnvironment& env = task->env();
Decoder d(func.bytes());
@ -3711,18 +3706,18 @@ wasm::IonCompileFunction(CompileTask* task)
ValTypeVector locals;
if (!locals.appendAll(func.sig().args()))
return false;
if (!DecodeLocalEntries(d, task->env().kind, &locals))
if (!DecodeLocalEntries(d, env.kind, &locals))
return false;
// Set up for Ion compilation.
JitContext jitContext(&results.alloc());
JitContext jitContext(&task->alloc());
const JitCompileOptions options;
MIRGraph graph(&results.alloc());
MIRGraph graph(&task->alloc());
CompileInfo compileInfo(locals.length());
MIRGenerator mir(nullptr, options, &results.alloc(), &graph, &compileInfo,
MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo,
IonOptimizations.get(OptimizationLevel::Wasm));
mir.initMinWasmHeapLength(task->env().minMemoryLength);
mir.initMinWasmHeapLength(env.minMemoryLength);
// Capture the prologue's trap site before decoding the function.
@ -3730,7 +3725,7 @@ wasm::IonCompileFunction(CompileTask* task)
// Build MIR graph
{
FunctionCompiler f(task->env(), d, func, locals, mir, results);
FunctionCompiler f(env, d, func, locals, mir);
if (!f.init())
return false;
@ -3770,11 +3765,15 @@ wasm::IonCompileFunction(CompileTask* task)
if (!lir)
return false;
SigIdDesc sigId = task->env().funcSigs[func.index()]->id;
SigIdDesc sigId = env.funcSigs[func.index()]->id;
CodeGenerator codegen(&mir, lir, &results.masm());
if (!codegen.generateWasm(sigId, prologueTrapOffset, &results.offsets()))
CodeGenerator codegen(&mir, lir, &task->masm());
FuncOffsets offsets;
if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets))
return false;
unit->finish(offsets);
}
return true;

View File

@ -25,10 +25,11 @@ namespace js {
namespace wasm {
class CompileTask;
class FuncCompileUnit;
// Generates very fast code at the expense of compilation time.
MOZ_MUST_USE bool
IonCompileFunction(CompileTask* task);
IonCompileFunction(CompileTask* task, FuncCompileUnit* unit);
} // namespace wasm
} // namespace js

View File

@ -141,7 +141,7 @@ LinkData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
Module::serializedSize(size_t* maybeBytecodeSize, size_t* maybeCompiledSize) const
{
if (maybeBytecodeSize)
*maybeBytecodeSize = SerializedPodVectorSize(bytecode_->bytes);
*maybeBytecodeSize = bytecode_->bytes.length();
if (maybeCompiledSize) {
*maybeCompiledSize = assumptions_.serializedSize() +
@ -164,9 +164,13 @@ Module::serialize(uint8_t* maybeBytecodeBegin, size_t maybeBytecodeSize,
if (maybeBytecodeBegin) {
// Bytecode deserialization is not guarded by Assumptions and thus must not
// change incompatibly between builds.
// change incompatibly between builds. Thus, for simplicity, the format
// of the bytecode file is simply a .wasm file (thus, backwards
// compatibility is ensured by backwards compatibility of the wasm
// binary format).
uint8_t* bytecodeEnd = SerializePodVector(maybeBytecodeBegin, bytecode_->bytes);
const Bytes& bytes = bytecode_->bytes;
uint8_t* bytecodeEnd = WriteBytes(maybeBytecodeBegin, bytes.begin(), bytes.length());
MOZ_RELEASE_ASSERT(bytecodeEnd == maybeBytecodeBegin + maybeBytecodeSize);
}
@ -204,14 +208,10 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
Metadata* maybeMetadata)
{
MutableBytes bytecode = js_new<ShareableBytes>();
if (!bytecode)
if (!bytecode || !bytecode->bytes.initLengthUninitialized(bytecodeSize))
return nullptr;
const uint8_t* bytecodeEnd = DeserializePodVector(bytecodeBegin, &bytecode->bytes);
if (!bytecodeEnd)
return nullptr;
MOZ_RELEASE_ASSERT(bytecodeEnd == bytecodeBegin + bytecodeSize);
memcpy(bytecode->bytes.begin(), bytecodeBegin, bytecodeSize);
Assumptions assumptions;
const uint8_t* cursor = assumptions.deserialize(compiledBegin, compiledSize);
@ -344,15 +344,15 @@ wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
compiledMapping.get(), compiledInfo.size);
}
// Since the compiled file's assumptions don't match, we must recompile from
// bytecode. The bytecode file format is simply that of a .wasm (see
// Module::serialize).
MutableBytes bytecode = js_new<ShareableBytes>();
if (!bytecode)
if (!bytecode || !bytecode->bytes.initLengthUninitialized(bytecodeInfo.size))
return nullptr;
const uint8_t* bytecodeEnd = DeserializePodVector(bytecodeMapping.get(), &bytecode->bytes);
if (!bytecodeEnd)
return nullptr;
MOZ_RELEASE_ASSERT(bytecodeEnd == bytecodeMapping.get() + bytecodeInfo.size);
memcpy(bytecode->bytes.begin(), bytecodeMapping.get(), bytecodeInfo.size);
ScriptedCaller scriptedCaller;
scriptedCaller.filename = Move(filename);

View File

@ -137,7 +137,7 @@ static inline uint8_t*
SerializePodVector(uint8_t* cursor, const mozilla::Vector<T, N, SystemAllocPolicy>& vec)
{
// This binary format must not change without taking into consideration the
// constraints in Assumptions::serialize and Module::serialize.
// constraints in Assumptions::serialize.
cursor = WriteScalar<uint32_t>(cursor, vec.length());
cursor = WriteBytes(cursor, vec.begin(), vec.length() * sizeof(T));

View File

@ -53,6 +53,7 @@
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/URL.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/ConsoleReportCollector.h"
@ -1405,29 +1406,27 @@ Loader::InsertSheetInDoc(StyleSheet* aSheet,
nsresult
Loader::InsertChildSheet(StyleSheet* aSheet,
StyleSheet* aParentSheet,
ImportRule* aParentRule)
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule)
{
LOG(("css::Loader::InsertChildSheet"));
NS_PRECONDITION(aSheet, "Nothing to insert");
NS_PRECONDITION(aParentSheet, "Need a parent to insert into");
NS_PRECONDITION(aParentSheet, "How did we get imported?");
// XXXheycam The InsertChildSheet API doesn't work with ServoStyleSheets,
// since they won't have Gecko ImportRules in them.
if (aSheet->IsServo()) {
return NS_ERROR_FAILURE;
MOZ_ASSERT(aSheet, "Nothing to insert");
MOZ_ASSERT(aParentSheet, "Need a parent to insert into");
MOZ_ASSERT_IF(aSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
MOZ_ASSERT_IF(aSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
if (aSheet->IsGecko()) {
// child sheets should always start out enabled, even if they got
// cloned off of top-level sheets which were disabled
aSheet->AsGecko()->SetEnabled(true);
aGeckoParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
} else {
RefPtr<RawServoStyleSheet> sheet =
Servo_ImportRule_GetSheet(aServoParentRule).Consume();
aSheet->AsServo()->SetSheetForImport(sheet);
}
// child sheets should always start out enabled, even if they got
// cloned off of top-level sheets which were disabled
aSheet->AsGecko()->SetEnabled(true);
aParentSheet->AppendStyleSheet(aSheet);
aParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
LOG((" Inserting into parent sheet"));
// LOG((" Inserting into parent sheet at position %d", insertionPoint));
return NS_OK;
}
@ -1775,7 +1774,8 @@ Loader::ParseSheet(const nsAString& aInput,
aLoadData->mLineNumber);
} else {
rv =
aLoadData->mSheet->AsServo()->ParseSheet(aInput, sheetURI, baseURI,
aLoadData->mSheet->AsServo()->ParseSheet(this,
aInput, sheetURI, baseURI,
aLoadData->mSheet->Principal(),
aLoadData->mLineNumber);
}
@ -1991,7 +1991,7 @@ Loader::LoadInlineStyle(nsIContent* aElement,
bool* aIsAlternate)
{
LOG(("css::Loader::LoadInlineStyle"));
NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
MOZ_ASSERT(mParsingDatas.IsEmpty(), "We're in the middle of a parse?");
*aCompleted = true;
@ -2197,13 +2197,19 @@ nsresult
Loader::LoadChildSheet(StyleSheet* aParentSheet,
nsIURI* aURL,
nsMediaList* aMedia,
ImportRule* aParentRule,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule,
LoaderReusableStyleSheets* aReusableSheets)
{
LOG(("css::Loader::LoadChildSheet"));
NS_PRECONDITION(aURL, "Must have a URI to load");
NS_PRECONDITION(aParentSheet, "Must have a parent sheet");
// Servo doesn't support reusable sheets.
MOZ_ASSERT_IF(aReusableSheets, aParentSheet->IsGecko());
MOZ_ASSERT_IF(aParentSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
MOZ_ASSERT_IF(aParentSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
if (!mEnabled) {
LOG_WARN((" Not enabled"));
return NS_ERROR_NOT_AVAILABLE;
@ -2215,7 +2221,11 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
// check for an owning document: if none, don't bother walking up the parent
// sheets
if (aParentSheet->GetOwningDocument()) {
//
// FIXME(emilio): Figure out whether this walk up is necessary (try seems
// green without it), and fix the parenting of stylesheets in the servo case
// if that's the case.
if (aParentSheet->GetOwningDocument() && aParentSheet->IsGecko()) {
StyleSheet* topSheet = aParentSheet;
while (StyleSheet* parent = topSheet->GetParentSheet()) {
topSheet = parent;
@ -2266,7 +2276,7 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
StyleSheetState state;
if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, reusableSheet)) {
sheet = reusableSheet;
aParentRule->SetSheet(reusableSheet);
aGeckoParentRule->SetSheet(reusableSheet);
state = eSheetComplete;
} else {
bool isAlternate;
@ -2283,7 +2293,8 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
}
rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
rv = InsertChildSheet(sheet, aParentSheet, aGeckoParentRule,
aServoParentRule);
NS_ENSURE_SUCCESS(rv, rv);
if (state == eSheetComplete) {

View File

@ -285,15 +285,19 @@ public:
* @param aParentSheet the parent of this child sheet
* @param aURL the URL of the child sheet
* @param aMedia the already-parsed media list for the child sheet
* @param aRule the @import rule importing this child. This is used to
* properly order the child sheet list of aParentSheet.
* @param aGeckoParentRule the @import rule importing this child, when using
* Gecko's style system. This is used to properly
* order the child sheet list of aParentSheet.
* @param aServoParentRule the @import rule importing this child, when using
* Servo's style system.
* @param aSavedSheets any saved style sheets which could be reused
* for this load
*/
nsresult LoadChildSheet(StyleSheet* aParentSheet,
nsIURI* aURL,
nsMediaList* aMedia,
ImportRule* aRule,
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule,
LoaderReusableStyleSheets* aSavedSheets);
/**
@ -484,7 +488,8 @@ private:
nsresult InsertChildSheet(StyleSheet* aSheet,
StyleSheet* aParentSheet,
ImportRule* aParentRule);
ImportRule* aGeckoParentRule,
const RawServoImportRule* aServoParentRule);
nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
bool aIsPreload,

View File

@ -11,3 +11,4 @@ SERVO_ARC_TYPE(StyleSheet, RawServoStyleSheet)
SERVO_ARC_TYPE(ComputedValues, ServoComputedValues)
SERVO_ARC_TYPE(DeclarationBlock, RawServoDeclarationBlock)
SERVO_ARC_TYPE(StyleRule, RawServoStyleRule)
SERVO_ARC_TYPE(ImportRule, RawServoImportRule)

View File

@ -26,12 +26,26 @@ SERVO_BINDING_FUNC(Servo_Element_ShouldTraverse, bool, RawGeckoElementBorrowed n
SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
mozilla::css::SheetParsingMode parsing_mode)
SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* gecko_stylesheet,
const nsACString* data,
mozilla::css::SheetParsingMode parsing_mode,
const nsACString* base_url,
ThreadSafeURIHolder* base,
ThreadSafeURIHolder* referrer,
ThreadSafePrincipalHolder* principal)
SERVO_BINDING_FUNC(Servo_ImportRule_GetSheet,
RawServoStyleSheetStrong,
const RawServoImportRuleBorrowed import_rule)
SERVO_BINDING_FUNC(Servo_StyleSheet_ClearAndUpdate,
void,
RawServoStyleSheetBorrowed stylesheet,
mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* gecko_stylesheet,
const nsACString* data,
ThreadSafeURIHolder* base,
ThreadSafeURIHolder* referrer,
ThreadSafePrincipalHolder* principal)
SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
RawServoStyleSheetBorrowed sheet)
SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,

View File

@ -10,6 +10,7 @@
#include "StyleStructContext.h"
#include "gfxFontFamilyList.h"
#include "nsAttrValueInlines.h"
#include "nsCSSParser.h"
#include "nsCSSRuleProcessor.h"
#include "nsContentUtils.h"
#include "nsDOMTokenList.h"
@ -20,6 +21,7 @@
#include "nsINode.h"
#include "nsIPrincipal.h"
#include "nsNameSpaceManager.h"
#include "nsNetUtil.h"
#include "nsRuleNode.h"
#include "nsString.h"
#include "nsStyleStruct.h"
@ -1027,6 +1029,40 @@ Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut aCSSValue, int32_t aIndex)
return &aCSSValue->GetArrayValue()->Item(aIndex);
}
void
Gecko_LoadStyleSheet(css::Loader* aLoader,
ServoStyleSheet* aParent,
RawServoImportRuleBorrowed aImportRule,
const uint8_t* aURLString,
uint32_t aURLStringLength,
const uint8_t* aMediaString,
uint32_t aMediaStringLength)
{
MOZ_ASSERT(aLoader, "Should've catched this before");
MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
MOZ_ASSERT(aURLString, "Invalid URLs shouldn't be loaded!");
RefPtr<nsMediaList> media = new nsMediaList();
if (aMediaStringLength) {
MOZ_ASSERT(aMediaString);
// TODO(emilio, bug 1325878): This is not great, though this is going away
// soon anyway, when we can have a Servo-backed nsMediaList.
nsDependentCSubstring medium(reinterpret_cast<const char*>(aMediaString),
aMediaStringLength);
nsCSSParser mediumParser(aLoader);
mediumParser.ParseMediaList(
NS_ConvertUTF8toUTF16(medium), nullptr, 0, media);
}
nsDependentCSubstring urlSpec(reinterpret_cast<const char*>(aURLString),
aURLStringLength);
// Servo's loader guarantees that the URL is valid.
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), urlSpec));
aLoader->LoadChildSheet(aParent, uri, media, nullptr, aImportRule, nullptr);
}
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
#define STYLE_STRUCT(name, checkdata_cb) \

View File

@ -29,6 +29,7 @@ class nsIPrincipal;
class nsIURI;
struct nsFont;
namespace mozilla {
class ServoStyleSheet;
class FontFamilyList;
enum FontFamilyType : uint32_t;
}
@ -95,6 +96,13 @@ RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed
RawGeckoElementBorrowedOrNull Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed element);
RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowed element);
RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
void Gecko_LoadStyleSheet(mozilla::css::Loader* loader,
mozilla::ServoStyleSheet* parent,
RawServoImportRuleBorrowed import_rule,
const uint8_t* url_bytes,
uint32_t url_length,
const uint8_t* media_bytes,
uint32_t media_length);
// By default, Servo walks the DOM by traversing the siblings of the DOM-view
// first child. This generally works, but misses anonymous children, which we

View File

@ -62,21 +62,17 @@ ServoStyleSheet::GetParentSheet() const
void
ServoStyleSheet::AppendStyleSheet(ServoStyleSheet* aSheet)
{
// XXXheycam: When we implement support for child sheets, we'll have
// to fix SetOwningDocument to propagate the owning document down
// to the children.
MOZ_CRASH("stylo: not implemented");
aSheet->mDocument = mDocument;
}
nsresult
ServoStyleSheet::ParseSheet(const nsAString& aInput,
ServoStyleSheet::ParseSheet(css::Loader* aLoader,
const nsAString& aInput,
nsIURI* aSheetURI,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
uint32_t aLineNumber)
{
DropSheet();
RefPtr<ThreadSafeURIHolder> base = new ThreadSafeURIHolder(aBaseURI);
RefPtr<ThreadSafeURIHolder> referrer = new ThreadSafeURIHolder(aSheetURI);
RefPtr<ThreadSafePrincipalHolder> principal =
@ -87,8 +83,15 @@ ServoStyleSheet::ParseSheet(const nsAString& aInput,
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 input(aInput);
mSheet = Servo_StyleSheet_FromUTF8Bytes(&input, mParsingMode, &baseString,
base, referrer, principal).Consume();
if (!mSheet) {
mSheet =
Servo_StyleSheet_FromUTF8Bytes(aLoader, this, &input, mParsingMode,
&baseString, base, referrer,
principal).Consume();
} else {
Servo_StyleSheet_ClearAndUpdate(mSheet, aLoader, this, &input, base,
referrer, principal);
}
return NS_OK;
}

View File

@ -18,6 +18,10 @@ namespace mozilla {
class ServoCSSRuleList;
namespace css {
class Loader;
}
/**
* CSS style sheet object that is a wrapper for a Servo Stylesheet.
*/
@ -36,7 +40,8 @@ public:
ServoStyleSheet* GetParentSheet() const;
void AppendStyleSheet(ServoStyleSheet* aSheet);
MOZ_MUST_USE nsresult ParseSheet(const nsAString& aInput,
MOZ_MUST_USE nsresult ParseSheet(css::Loader* aLoader,
const nsAString& aInput,
nsIURI* aSheetURI,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
@ -56,6 +61,10 @@ public:
#endif
RawServoStyleSheet* RawSheet() const { return mSheet; }
void SetSheetForImport(RawServoStyleSheet* aSheet) {
MOZ_ASSERT(!mSheet);
mSheet = aSheet;
}
// WebIDL StyleSheet API
nsMediaList* Media() final;

View File

@ -3796,8 +3796,8 @@ CSSParserImpl::ProcessImport(const nsString& aURLSpec,
uint32_t aColumnNumber)
{
RefPtr<css::ImportRule> rule = new css::ImportRule(aMedia, aURLSpec,
aLineNumber,
aColumnNumber);
aLineNumber,
aColumnNumber);
(*aAppendFunc)(rule, aData);
// Diagnose bad URIs even if we don't have a child loader.
@ -3815,7 +3815,9 @@ CSSParserImpl::ProcessImport(const nsString& aURLSpec,
}
if (mChildLoader) {
mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule, mReusableSheets);
mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule,
/* aServoParentRule = */ nullptr,
mReusableSheets);
}
}

View File

@ -971,7 +971,10 @@ nsLayoutStylesheetCache::BuildPreferenceSheet(RefPtr<StyleSheet>* aSheet,
if (sheet->IsGecko()) {
sheet->AsGecko()->ReparseSheet(sheetText);
} else {
nsresult rv = sheet->AsServo()->ParseSheet(sheetText, uri, uri, nullptr, 0);
ServoStyleSheet* servoSheet = sheet->AsServo();
// NB: The pref sheet never has @import rules.
nsresult rv =
servoSheet->ParseSheet(nullptr, sheetText, uri, uri, nullptr, 0);
// Parsing the about:PreferenceStyleSheet URI can only fail on OOM. If we
// are OOM before we parsed any documents we might as well abort.
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));

View File

@ -1027,7 +1027,20 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
nsLayoutUtils::RectToGfxRect(aParams.borderArea,
frame->PresContext()->AppUnitsPerDevPixel());
context.Rectangle(drawingRect, true);
context.SetColor(Color(0.0, 1.0, 0.0, 1.0));
Color overlayColor(0.0f, 0.0f, 0.0f, 0.8f);
if (maskUsage.shouldGenerateMaskLayer) {
overlayColor.r = 1.0f; // red represents css positioned mask.
}
if (maskUsage.shouldApplyClipPath ||
maskUsage.shouldGenerateClipMaskLayer) {
overlayColor.g = 1.0f; // green represents clip-path:<clip-source>.
}
if (maskUsage.shouldApplyBasicShape) {
overlayColor.b = 1.0f; // blue represents
// clip-path:<basic-shape>||<geometry-box>.
}
context.SetColor(overlayColor);
context.Fill();
}

View File

@ -135,7 +135,6 @@ static const char pluginSandboxRules[] =
"(allow file-read*\n"
" (regex #\"^/etc$\")\n"
" (regex #\"^/dev/u?random$\")\n"
" (regex #\"^/(private/)?var($|/)\")\n"
" (literal \"/usr/share/icu/icudt51l.dat\")\n"
" (regex #\"^/System/Library/Displays/Overrides/*\")\n"
" (regex #\"^/System/Library/CoreServices/CoreTypes.bundle/*\")\n"

View File

@ -23,6 +23,28 @@ linux64-clang/opt:
- 'taskcluster/scripts/misc/build-clang-linux.sh'
- 'taskcluster/taskgraph/transforms/job/toolchain.py'
linux64-clang-tidy/opt:
description: "Clang-tidy build"
treeherder:
kind: build
platform: linux64/opt
symbol: Cc(Clang-Tidy)
tier: 1
run:
using: toolchain-script
script: build-clang-tidy-linux.sh
worker-type: aws-provisioner-v1/gecko-{level}-b-linux
worker:
implementation: docker-worker
docker-image: {in-tree: desktop-build}
max-run-time: 36000
when:
files-changed:
- 'build/clang-plugin/**'
- 'build/build-clang/**'
- 'taskcluster/scripts/misc/build-clang-tidy-linux.sh'
- 'taskcluster/taskgraph/transforms/job/toolchain.py'
linux64-gcc/opt:
description: "GCC toolchain build"
treeherder:

View File

@ -0,0 +1,30 @@
#!/bin/bash
set -x -e -v
# This script is for building clang for Linux.
WORKSPACE=$HOME/workspace
HOME_DIR=$WORKSPACE/build
UPLOAD_DIR=$WORKSPACE/artifacts
# Fetch our toolchain from tooltool
cd $HOME_DIR
wget -O tooltool.py https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py
chmod +x tooltool.py
: TOOLTOOL_CACHE ${TOOLTOOL_CACHE:=/home/worker/tooltool-cache}
export TOOLTOOL_CACHE
cd src
$HOME_DIR/tooltool.py -m browser/config/tooltool-manifests/linux64/releng.manifest fetch
# gets a bit too verbose here
set +x
cd build/build-clang
# |mach python| sets up a virtualenv for us!
../../mach python ./build-clang.py -c clang-tidy-linux64.json
set -x
# Put a tarball in the artifacts dir
mkdir -p $UPLOAD_DIR
cp clang.tar.* $UPLOAD_DIR

View File

@ -544,17 +544,13 @@ SpecialPowersObserverAPI.prototype = {
}
case "SPStartupExtension": {
let {ExtensionData, Management} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
let {ExtensionData} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
let id = aMessage.data.id;
let extension = this._extensions.get(id);
let startupListener = (msg, ext) => {
if (ext == extension) {
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id]});
Management.off("startup", startupListener);
}
};
Management.on("startup", startupListener);
extension.on("startup", () => {
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id]});
});
// Make sure the extension passes the packaging checks when
// they're run on a bare archive rather than a running instance,
@ -579,7 +575,6 @@ SpecialPowersObserverAPI.prototype = {
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionStarted", args: []});
}).catch(e => {
dump(`Extension startup failed: ${e}\n${e.stack}`);
Management.off("startup", startupListener);
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionFailed", args: []});
});
return undefined;

View File

@ -813,14 +813,14 @@ HttpObserverManager = {
// Check whether we've already added a listener to this channel,
// so we don't wind up chaining multiple listeners.
let channelData = getData(channel);
if (!channelData.listener && channel instanceof Ci.nsITraceableChannel) {
if (!channelData.hasListener && channel instanceof Ci.nsITraceableChannel) {
let responseStatus = channel.responseStatus;
// skip redirections, https://bugzilla.mozilla.org/show_bug.cgi?id=728901#c8
if (responseStatus < 300 || responseStatus >= 400) {
let listener = new StartStopListener(this, loadContext);
let orig = channel.setNewListener(listener);
listener.orig = orig;
channelData.listener = listener;
channelData.hasListener = true;
}
}
}

View File

@ -150,3 +150,6 @@ if CONFIG['GNU_CXX']:
'-Wno-error=shadow',
'-Wno-ignored-qualifiers', # due to use of breakpad headers
]
with Files('**'):
BUG_COMPONENT = ('Core', 'Gecko Profiler')

View File

@ -1,69 +0,0 @@
// Test that we get `js::SavedStacks::saveCurrentStack` frames.
function run_test() {
let p = Cc["@mozilla.org/tools/profiler;1"];
// Just skip the test if the profiler component isn't present.
if (!p)
return;
p = p.getService(Ci.nsIProfiler);
if (!p)
return;
const { saveStack } = Cu.getJSTestingFunctions();
const ms = 5;
p.StartProfiler(100, ms, ["js"], 1);
let then = Date.now();
while (Date.now() - then < 30000) {
function a() {
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
saveStack();
}
a();
a();
a();
a();
a();
function b() {
a();
}
b();
b();
b();
b();
b();
}
var profile = p.getProfileData().threads[0];
do_check_neq(profile.samples.data.length, 0);
let found = false;
for (let sample of profile.samples.data) {
const stack = getInflatedStackLocations(profile, sample);
for (let frame of stack) {
if (frame.indexOf("js::SavedStacks::saveCurrentStack") >= 0) {
found = true;
break;
}
}
}
do_check_true(found);
p.StopProfiler();
}

View File

@ -15,5 +15,4 @@ skip-if = true
skip-if = !debug
[test_enterjit_osr_enabling.js]
skip-if = !debug
[test_asm.js]
[test_saved_stacks.js]
[test_asm.js]