mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:11:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1235610 - Add xpctall support for Bitrig and DragonFly. r=glandium (02b7d40eb3)
- Bug 1252072 - Prevent ASan instrumentation for unsafe xpcom functions. r=froydnj (881bfc18c0)
- Bug 1245099 - Fixed uninitialized variable warning. r=bsmedberg (6481aad0d5)
- Bug 1196370 - Remove the clang assembly workaround from bug 1028613. r=ehsan (b8b6f1a5e8)
- Bug 1234860 - move win32 NS_InvokeByIndex implementation to a separate assembly file; r=aklotz,ted.m (73ca54348f)
- Bug 1248534 (part 1) - Remove XPT encoding support. r=khuey. (e84c4dfd32)
- Bug 1248534 (part 2) - Remove unused XPT flags. r=khuey. (264be694d0)
- Bug 1248534 (part 3) - Remove almost all support for XPT annotations. r=khuey. (97a0d86e0b)
- Bug 1248534 (part 4) - Remove unused fields from XPTConstValue. r=khuey. (9eccf9eba5)
- Bug 1248534 (part 5) - Remove XPTDatapool. r=khuey. (139dab7a9f)
- Bug 1248534 (part 6) - Stack-allocate XPTState. r=khuey. (f32ce7cc9e)
- Bug 1249174 (part 7) - Only define XPTArena::name if XPT_ARENA_LOGGING is defined. r=khuey. (174a20c0a3)
- Bug 1248534 (part 8) - Remove useless XPT freeing code. r=khuey. (a5ade9739b)
- Bug 1248534 (part 9) - Remove XPT arena logging code. r=khuey. (a996dfad76)
- Bug 1251458 - Reinstate annotation handling in .xpt files. r=khuey. (fbe8d573bd)
- Bug 1249174 (part 1) - Don't store the unused XPTTypeDescriptorTags::argnum2 field in memory. r=khuey. (e1d12965eb)
- Bug 1253877 - Baldr: cast -1 to uint8 to avoid 'shifting negative' error on CLOSED TREE (r=bustage) (cdf8031264)
- Bug 1258599 - OdinMonkey: MIPS: Only reserving stack for argument registers on O32. r=huangwenjun06 (a77220a9fa)
- Bug 1253137 - Baldr: fold if_else into if to match ml-proto (r=sunfish) (54e89aafe3)
- Bug 1249174 (part 2) - Shrink xptiInterfaceEntry by reordering its fields. r=khuey. (c4d7c15e6e)
- Bug 1253137 - Baldr: update br_table syntax to match ml-proto (r=sunfish) (e7f253e4d8)
- Bug 1249174 (part 3) - Don't store the unused XPTInterfaceDirectoryEntry::name_space field in memory. r=khuey. (c308508e74)
- Bug 1249174 (part 4) - Don't store unused XPTHeader fields in memory. r=khuey. (2dfd238a54)
- Bug 1249174 (part 5) - Remove the useless BLK_HDR::size field. r=khuey. (1a362c278e)
- Bug 1249174 (part 6) - Shrink XPTTypeDescriptor. r=khuey. (5a313327fe)
- Bug 1249174 (part 7.5) - Avoid wasted space around XPT strings. r=khuey. (ac3653802c)
- Bug 1249174 (part 8) - Shrink XPTInterfaceDescriptor. r=khuey. (e9dc929d37)
- Bug 1254188 - Baldr: handle recycled phis when closing a loop with a value (r=bbouvier) (2cb0895472)
- Bug 1254167: Don't allow folding to full range for atomic accesses; r=sunfish (96a851efda)
- Bug 1256637: Set definition before returning early in EmitBrTable; r=luke (0fdb365e82)
- Bug 1255695 - BaldrMonkey: Implement unaligned accesses. r=luke (205b798249)
- Bug 1238121 - Properly guard Profiler's RAII classes r=BenWa f=mystor (a3db8e6bc9)
- Bug 1251787 - Remove remaining references to MOZILLA_XPCOMRT_API from tools. r=mstange (1632205437)
- align profiler (c2638ecf1f)
- Bug 1235502 - Fix -Wunreachable-code warning in tools/profiler/. r=BenWa (0d564937c9)
- Bug 1221846 - Properly close the tasktracer property in the GeckoSampler JSON blob. r=BenWa (dca640fb03)
- Bug 1239498 - Use Stackwalk64 on win x64. r=jrmuizel (50ffe8a649)
- Bug 1258269: Declare logging string-literals in exception_handler.cc as 'const char[]' to fix build warning & for consistency. r=ted (a9454e735f)
- parts of Bug 1151175 - Update libvpx update.py for 1.4.0. (8700fa48ab)
- Bug 1249590 - Bullet-proofing AsyncShutdown wrt exceptions;r=froydnj (7e512f1029)
- Bug 1021151 - avoid memory leak in NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT, use nsAutoPtr instead of naked ptr. r=Ehsan (d0eb754af2)
- Bug 1255223 - Null crash when logging weak maps. r=mccr8. (0d02b4b469)
- Bug 1250134 - assert mJSRuntime when IsGrayJS() is true. r=mccr8 (a3987102ed)
- Bug 1254131: Fix non-unified wasm build. r=luke (cacb86e4d0)
- Bug 1246929 - Skip installing functions and properties on builtins for the self-hosting global. r=Waldo (aa04041de9)
- Bug 986294 - Remove Proxy.create from addon-sdk. r=mossop (da3d6c40ea)
- Bug 1243805 - Replace Proxy.create with new Proxy in devtools l10n code. r=jryans (9886f857be)
- Bug 1245141 - Use new Proxy for AddonManager.addonTypes. r=mossop (6cc8dd0870)
- Bug 1253866 - Remove Proxy.create from crash tests. r=bz (76a421cf97)
- Bug 892903 - Remove Proxy.create and Proxy.createFunction. r=efaust (7b572deb10)
- Bug 1049041 - Remove scary warning about mutating [[Prototype]]. r=efaust. (367ac3f6c5)
- Bug 1257445 - #ifdef on __GLIBC__ for sched_getcpu, which is a glibc feature. r=jimb (171a1729c1)
- Followup for bug 1257445 - Remove the AutoStopwatch::getCPU implementation using sched_getcpu. r=jimb (221f52d4c4)
- Bug 1178317 - eliminate large static constructor from ShimInterfaceInfo.cpp; r=poiru (aa66704aee)
- Bug 1247580 P1 Allow old nsIX509Cert serialized objects to be read off disk. r=bz (1f8bc280a6)
- Bug 1247580 P2 Add gtest to ensure we can continue to deserialize old security info strings. r=bz (323059ac29)
- Bug 864842 - Show error for browsing Windows drive without media, r=michal (1e438bdf2f)
- Bug 1233283 - Remove unless tmp from ReadDir in nsLocalFileWin. r=froydnj (1565d1cc14)
- Bug 1258498: Use fallible allocation in nsScriptableInputStream::ReadBytes. r= froydnj (eebcb8050d)
- Bug 1236108: Add temp directory for sandboxed content processes to directory r=bsmedberg (8384b33c10)
- Bug 1255362 - Null-check GetContainer() before using it in image-related ConfigureLayer() methods. r=mstange a=Tomcat (beab7149f1)
- Bug 1205473 - Add a state bit to optimize building event regions. r=mattwoodrow (c8b1eb9839)
- Bug 1222886 - Remove unused nsCSSParser::{SetStyleSheet,SetChildLoader,SetQuirkMode} methods. r=bzbarsky (c9c6621083)
- Bug 1247327. Fix WebGL acceptance rates in telemetry. r=milan (de10319664)
- Bug 1249664 - Save dropped-down state in nsPresState. r=dbaron (734c3ee18b)
- Bug 1256745 - Cancel the DidPaint timer in SetShell(nullptr). r=mattwoodrow (d2a4202512)
- Bug 1238846 (part 1) - Remove some dead code in nsLayoutUtils. r=mattwoodrow. (e6af806e52)
- Bug 1252414 - Handle lost_context for webgl ClearBuffer*. r=jgilbert (e6728605ff)
- Bug 1228687: ScopedResolveTexturesForDraw needs the context to be current, so make those calls earlier. r=jgilbert (6e731187c5)
- Bug 1247532 - Annotate intentional switch fallthrough to suppress -Wimplicit-fallthrough warning in dom/canvas/. r=jgilbert (d7faec1848)
- Bug 1249483 - Stop filling A with 1.0 on readback from no-alpha. - r=jrmuizel (9bf71fb220)
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
function K(v) { return function() { return v; } }
|
||||
|
||||
var errorProxy = Proxy.create({get: function() { throw new Error(); }});
|
||||
var errorProxy = new Proxy({}, {get: function() { throw new Error(); }});
|
||||
|
||||
function boom()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
var nodeList = document.documentElement.childNodes;
|
||||
nodeList.__proto__ = null;
|
||||
var p = Proxy.create({getPropertyDescriptor: function() {return nodeList}});
|
||||
p.x;
|
||||
var p = new Proxy({}, {getOwnPropertyDescriptor: function() {return nodeList}});
|
||||
Reflect.getOwnPropertyDescriptor(p, "x");
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var a = document.getElementsByTagName("div");
|
||||
a.__proto__ = Proxy.create({has: function() { throw new Error; }});
|
||||
for (var p in a) {
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
||||
@@ -143,7 +143,6 @@ load 700090-1.html
|
||||
load 700090-2.html
|
||||
load 700512.html
|
||||
load 706283-1.html
|
||||
load 708405-1.html
|
||||
load 709384.html
|
||||
load 709954.html
|
||||
load 713417-1.html
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
HTMLElement.prototype.__proto__ = Proxy.create({}, {});
|
||||
HTMLElement.prototype.__proto__ = new Proxy({}, {});
|
||||
try {
|
||||
window.Image;
|
||||
} finally {
|
||||
|
||||
@@ -139,11 +139,8 @@ CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL1Context::Create();
|
||||
if (!ret) {
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0);
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1);
|
||||
|
||||
break;
|
||||
|
||||
@@ -151,11 +148,8 @@ CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL2Context::Create();
|
||||
if (!ret) {
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0);
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1);
|
||||
|
||||
break;
|
||||
|
||||
@@ -204,8 +198,16 @@ CanvasRenderingContextHelper::GetContext(JSContext* aCx,
|
||||
// See bug 645792 and bug 1215072.
|
||||
// We want to throw only if dictionary initialization fails,
|
||||
// so only in case aRv has been set to some error value.
|
||||
if (contextType == CanvasContextType::WebGL1)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0);
|
||||
else if (contextType == CanvasContextType::WebGL2)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0);
|
||||
return nullptr;
|
||||
}
|
||||
if (contextType == CanvasContextType::WebGL1)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1);
|
||||
else if (contextType == CanvasContextType::WebGL2)
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1);
|
||||
} else {
|
||||
// We already have a context of some type.
|
||||
if (contextType != mCurrentContextType)
|
||||
|
||||
@@ -94,6 +94,10 @@ WebGL2Context::ClearBufferfv_base(GLenum buffer, GLint drawbuffer, const GLfloat
|
||||
void
|
||||
WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawbuffer, const dom::Int32Array& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
value.ComputeLengthAndData();
|
||||
if (!ValidateClearBuffer("clearBufferiv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
@@ -105,6 +109,10 @@ WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawbuffer, const dom::Int32Ar
|
||||
void
|
||||
WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawbuffer, const dom::Sequence<GLint>& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateClearBuffer("clearBufferiv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
}
|
||||
@@ -115,6 +123,10 @@ WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawbuffer, const dom::Sequenc
|
||||
void
|
||||
WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const dom::Uint32Array& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
value.ComputeLengthAndData();
|
||||
if (!ValidateClearBuffer("clearBufferuiv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
@@ -126,6 +138,10 @@ WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const dom::Uint32
|
||||
void
|
||||
WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const dom::Sequence<GLuint>& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateClearBuffer("clearBufferuiv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
}
|
||||
@@ -136,6 +152,10 @@ WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const dom::Sequen
|
||||
void
|
||||
WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawbuffer, const dom::Float32Array& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
value.ComputeLengthAndData();
|
||||
if (!ValidateClearBuffer("clearBufferfv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
@@ -147,6 +167,10 @@ WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawbuffer, const dom::Float32
|
||||
void
|
||||
WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawbuffer, const dom::Sequence<GLfloat>& value)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateClearBuffer("clearBufferfv", buffer, drawbuffer, value.Length())) {
|
||||
return;
|
||||
}
|
||||
@@ -157,6 +181,10 @@ WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawbuffer, const dom::Sequenc
|
||||
void
|
||||
WebGL2Context::ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer != LOCAL_GL_DEPTH_STENCIL) {
|
||||
return ErrorInvalidEnumInfo("clearBufferfi: buffer", buffer);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
{
|
||||
MOZ_ASSERT(webgl->gl->IsCurrent());
|
||||
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
|
||||
|
||||
const auto fnResolveAll = [this, funcName](const TexturesT& textures)
|
||||
@@ -220,7 +222,7 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
@@ -246,6 +248,8 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@@ -274,6 +278,8 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@@ -409,7 +415,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLContext::EnumName(type));
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
@@ -436,6 +442,8 @@ WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@@ -473,6 +481,8 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
|
||||
@@ -838,7 +838,7 @@ WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
|
||||
case LOCAL_GL_RENDERBUFFER_SAMPLES:
|
||||
if (!IsWebGL2())
|
||||
break;
|
||||
// fallthrough
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case LOCAL_GL_RENDERBUFFER_WIDTH:
|
||||
case LOCAL_GL_RENDERBUFFER_HEIGHT:
|
||||
@@ -1207,57 +1207,6 @@ WebGLContext::PixelStorei(GLenum pname, GLint param)
|
||||
ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
|
||||
}
|
||||
|
||||
// `width` in pixels.
|
||||
// `stride` in bytes.
|
||||
static void
|
||||
SetFullAlpha(void* data, GLenum format, GLenum type, size_t width, size_t height,
|
||||
size_t stride)
|
||||
{
|
||||
if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
// Just memset the rows.
|
||||
uint8_t* row = static_cast<uint8_t*>(data);
|
||||
for (size_t j = 0; j < height; ++j) {
|
||||
memset(row, 0xff, width);
|
||||
row += stride;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
for (size_t j = 0; j < height; ++j) {
|
||||
uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
|
||||
|
||||
uint8_t* pAlpha = row + 3;
|
||||
uint8_t* pAlphaEnd = pAlpha + 4*width;
|
||||
while (pAlpha != pAlphaEnd) {
|
||||
*pAlpha = 0xff;
|
||||
pAlpha += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
|
||||
for (size_t j = 0; j < height; ++j) {
|
||||
uint8_t* rowBytes = static_cast<uint8_t*>(data) + j*stride;
|
||||
float* row = reinterpret_cast<float*>(rowBytes);
|
||||
|
||||
float* pAlpha = row + 3;
|
||||
float* pAlphaEnd = pAlpha + 4*width;
|
||||
while (pAlpha != pAlphaEnd) {
|
||||
*pAlpha = 1.0f;
|
||||
pAlpha += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unhandled case, how'd we get here?");
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum destFormat, GLenum destType, void* destBytes,
|
||||
@@ -1763,25 +1712,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
|
||||
row += rowStride.value();
|
||||
}
|
||||
}
|
||||
|
||||
// if we're reading alpha, we may need to do fixup. Note that we don't allow
|
||||
// GL_ALPHA to readpixels currently, but we had the code written for it already.
|
||||
const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
|
||||
format == LOCAL_GL_RGBA;
|
||||
if (!formatHasAlpha)
|
||||
return;
|
||||
|
||||
bool needAlphaFilled;
|
||||
if (mBoundReadFramebuffer) {
|
||||
needAlphaFilled = !mBoundReadFramebuffer->ColorAttachment(0).HasAlpha();
|
||||
} else {
|
||||
needAlphaFilled = !mOptions.alpha;
|
||||
}
|
||||
|
||||
if (!needAlphaFilled)
|
||||
return;
|
||||
|
||||
SetFullAlpha(data, format, type, width, height, rowStride.value());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -593,7 +593,7 @@ class Decoder
|
||||
} while (shift < numBitsInSevens);
|
||||
if (!remainderBits || !readFixedU8(&byte) || (byte & 0x80))
|
||||
return false;
|
||||
uint8_t mask = 0x7f & (-1 << remainderBits);
|
||||
uint8_t mask = 0x7f & (uint8_t(-1) << remainderBits);
|
||||
if ((byte & mask) != ((byte & (1 << (remainderBits - 1))) ? mask : 0))
|
||||
return false;
|
||||
*out = s | SInt(byte) << shift;
|
||||
|
||||
@@ -333,7 +333,7 @@ ModuleGenerator::finishTask(IonCompileTask* task)
|
||||
funcIndexToCodeRange_[func.index()] = funcCodeRangeIndex;
|
||||
|
||||
// Merge the compiled results into the whole-module masm.
|
||||
DebugOnly<size_t> sizeBefore = masm_.size();
|
||||
mozilla::DebugOnly<size_t> sizeBefore = masm_.size();
|
||||
if (!masm_.asmMergeWith(results.masm()))
|
||||
return false;
|
||||
MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
|
||||
|
||||
@@ -1084,7 +1084,8 @@ class FunctionCompiler
|
||||
}
|
||||
}
|
||||
|
||||
bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge)
|
||||
bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge,
|
||||
MDefinition** loopResult)
|
||||
{
|
||||
if (!loopEntry->setBackedgeAsmJS(backedge))
|
||||
return false;
|
||||
@@ -1096,6 +1097,10 @@ class FunctionCompiler
|
||||
phi->setUnused();
|
||||
}
|
||||
|
||||
// The loop result may also be referencing a recycled phi.
|
||||
if (*loopResult && (*loopResult)->isUnused())
|
||||
*loopResult = (*loopResult)->toPhi()->getOperand(0);
|
||||
|
||||
// Fix up phis stored in the slots Vector of pending blocks.
|
||||
for (BlockVector& vec : targets_) {
|
||||
for (MBasicBlock* block : vec) {
|
||||
@@ -1123,7 +1128,7 @@ class FunctionCompiler
|
||||
}
|
||||
|
||||
public:
|
||||
bool closeLoop(MBasicBlock* loopHeader)
|
||||
bool closeLoop(MBasicBlock* loopHeader, MDefinition** loopResult)
|
||||
{
|
||||
MOZ_ASSERT(blockDepth_ >= 2);
|
||||
MOZ_ASSERT(loopDepth_);
|
||||
@@ -1157,7 +1162,7 @@ class FunctionCompiler
|
||||
// We're on the loop backedge block, created by bindBranches.
|
||||
MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_);
|
||||
curBlock_->end(MGoto::New(alloc(), loopHeader));
|
||||
if (!setLoopBackedge(loopHeader, loopBody, curBlock_))
|
||||
if (!setLoopBackedge(loopHeader, loopBody, curBlock_, loopResult))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1456,23 +1461,15 @@ EmitHeapAddress(FunctionCompiler& f, MDefinition** base, MAsmJSHeapAccess* acces
|
||||
if (endOffset < offset)
|
||||
return false;
|
||||
bool accessNeedsBoundsCheck = true;
|
||||
if (endOffset > f.mirGen().foldableOffsetRange(accessNeedsBoundsCheck)) {
|
||||
// Assume worst case.
|
||||
bool atomicAccess = true;
|
||||
if (endOffset > f.mirGen().foldableOffsetRange(accessNeedsBoundsCheck, atomicAccess)) {
|
||||
MDefinition* rhs = f.constant(Int32Value(offset), MIRType_Int32);
|
||||
*base = f.binary<MAdd>(*base, rhs, MIRType_Int32);
|
||||
offset = 0;
|
||||
access->setOffset(offset);
|
||||
}
|
||||
|
||||
// TODO Remove this after implementing unaligned loads/stores.
|
||||
int32_t maskVal = ~(Scalar::byteSize(access->accessType()) - 1);
|
||||
if (maskVal == -1)
|
||||
return true;
|
||||
|
||||
offset &= maskVal;
|
||||
access->setOffset(offset);
|
||||
|
||||
MDefinition* mask = f.constant(Int32Value(maskVal), MIRType_Int32);
|
||||
*base = f.bitwise<MBitAnd>(*base, mask, MIRType_Int32);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2553,7 +2550,7 @@ EmitLoop(FunctionCompiler& f, MDefinition** def)
|
||||
*def = nullptr;
|
||||
}
|
||||
|
||||
return f.closeLoop(loopHeader);
|
||||
return f.closeLoop(loopHeader, def);
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -2625,6 +2622,8 @@ EmitBrTable(FunctionCompiler& f, MDefinition** def)
|
||||
if (!EmitExpr(f, &index))
|
||||
return false;
|
||||
|
||||
*def = nullptr;
|
||||
|
||||
// Empty table
|
||||
if (!numCases)
|
||||
return f.br(defaultDepth);
|
||||
@@ -2656,7 +2655,6 @@ EmitBrTable(FunctionCompiler& f, MDefinition** def)
|
||||
if (!f.joinSwitch(switchBlock, cases, defaultBlock))
|
||||
return false;
|
||||
|
||||
*def = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -730,6 +730,33 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre
|
||||
return end;
|
||||
}
|
||||
|
||||
#elif defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED)
|
||||
|
||||
MOZ_COLD static uint8_t*
|
||||
EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
|
||||
const HeapAccess* heapAccess, const Module& module)
|
||||
{
|
||||
// TODO: Implement unaligned accesses.
|
||||
return module.outOfBounds();
|
||||
}
|
||||
|
||||
#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED)
|
||||
|
||||
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
|
||||
MOZ_COLD static bool
|
||||
IsHeapAccessAddress(const Module &module, uint8_t* faultingAddress)
|
||||
{
|
||||
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
size_t accessLimit = MappedSize;
|
||||
#elif defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED)
|
||||
size_t accessLimit = module.heapLength();
|
||||
#endif
|
||||
return module.usesHeap() &&
|
||||
faultingAddress >= module.heap() &&
|
||||
faultingAddress < module.heap() + accessLimit;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
||||
static bool
|
||||
@@ -759,15 +786,12 @@ HandleFault(PEXCEPTION_POINTERS exception)
|
||||
|
||||
const Module& module = activation->module();
|
||||
|
||||
// These checks aren't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(record->ExceptionInformation[1]);
|
||||
if (!module.usesHeap() ||
|
||||
faultingAddress < module.heap() ||
|
||||
faultingAddress >= module.heap() + MappedSize)
|
||||
{
|
||||
|
||||
// This check isn't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
if (!IsHeapAccessAddress(module, faultingAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module.containsFunctionPC(pc)) {
|
||||
// On Windows, it is possible for InterruptRunningCode to execute
|
||||
@@ -904,15 +928,12 @@ HandleMachException(JSRuntime* rt, const ExceptionRequest& request)
|
||||
if (!module.containsFunctionPC(pc))
|
||||
return false;
|
||||
|
||||
// These checks aren't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(request.body.code[1]);
|
||||
if (!module.usesHeap() ||
|
||||
faultingAddress < module.heap() ||
|
||||
faultingAddress >= module.heap() + MappedSize)
|
||||
{
|
||||
|
||||
// This check isn't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
if (!IsHeapAccessAddress(module, faultingAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
const HeapAccess* heapAccess = module.lookupHeapAccess(pc);
|
||||
if (!heapAccess)
|
||||
@@ -1114,15 +1135,12 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
|
||||
if (!module.containsFunctionPC(pc))
|
||||
return false;
|
||||
|
||||
// These checks aren't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
uint8_t* faultingAddress = reinterpret_cast<uint8_t*>(info->si_addr);
|
||||
if (!module.usesHeap() ||
|
||||
faultingAddress < module.heap() ||
|
||||
faultingAddress >= module.heap() + MappedSize)
|
||||
{
|
||||
|
||||
// This check isn't necessary, but, since we can, check anyway to make
|
||||
// sure we aren't covering up a real bug.
|
||||
if (!IsHeapAccessAddress(module, faultingAddress))
|
||||
return false;
|
||||
}
|
||||
|
||||
const HeapAccess* heapAccess = module.lookupHeapAccess(pc);
|
||||
if (!heapAccess)
|
||||
@@ -1162,7 +1180,7 @@ AsmJSFaultHandler(int signum, siginfo_t* info, void* context)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
|
||||
static void
|
||||
RedirectIonBackedgesToInterruptCheck(JSRuntime* rt)
|
||||
@@ -1223,7 +1241,7 @@ JitInterruptHandler(int signum, siginfo_t* info, void* context)
|
||||
bool
|
||||
wasm::EnsureSignalHandlersInstalled(JSRuntime* rt)
|
||||
{
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
// On OSX, each JSRuntime gets its own handler thread.
|
||||
if (!rt->wasmMachExceptionHandler.installed() && !rt->wasmMachExceptionHandler.install(rt))
|
||||
return false;
|
||||
@@ -1280,9 +1298,9 @@ wasm::EnsureSignalHandlersInstalled(JSRuntime* rt)
|
||||
}
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
// Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap
|
||||
// access.
|
||||
// access and/or unaligned accesses.
|
||||
# if defined(XP_WIN)
|
||||
if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, AsmJSFaultHandler))
|
||||
return false;
|
||||
@@ -1300,7 +1318,7 @@ wasm::EnsureSignalHandlersInstalled(JSRuntime* rt)
|
||||
if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler))
|
||||
MOZ_CRASH("unable to install segv handler");
|
||||
# endif
|
||||
#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#endif // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
|
||||
sResult = true;
|
||||
return true;
|
||||
@@ -1363,3 +1381,20 @@ js::InterruptRunningJitCode(JSRuntime* rt)
|
||||
pthread_kill(thread, sInterruptSignal);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOZ_COLD bool
|
||||
js::wasm::IsPCInWasmCode(void *pc)
|
||||
{
|
||||
JSRuntime* rt = RuntimeForCurrentThread();
|
||||
if (!rt)
|
||||
return false;
|
||||
|
||||
MOZ_RELEASE_ASSERT(!rt->handlingSegFault);
|
||||
|
||||
WasmActivation* activation = rt->wasmActivationStack();
|
||||
if (!activation)
|
||||
return false;
|
||||
|
||||
const Module& module = activation->module();
|
||||
return module.containsFunctionPC(pc);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef wasm_signal_handlers_h
|
||||
#define wasm_signal_handlers_h
|
||||
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
# include <mach/mach.h>
|
||||
# include "jslock.h"
|
||||
#endif
|
||||
@@ -41,7 +41,7 @@ namespace wasm {
|
||||
bool
|
||||
EnsureSignalHandlersInstalled(JSRuntime* rt);
|
||||
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
// On OSX we are forced to use the lower-level Mach exception mechanism instead
|
||||
// of Unix signals. Mach exceptions are not handled on the victim's stack but
|
||||
// rather require an extra thread. For simplicity, we create one such thread
|
||||
@@ -65,6 +65,10 @@ class MachExceptionHandler
|
||||
};
|
||||
#endif
|
||||
|
||||
// Test whether the given PC is within the innermost wasm activation. Return
|
||||
// false if it is not, or it cannot be determined.
|
||||
bool IsPCInWasmCode(void *pc);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
||||
@@ -951,13 +951,17 @@ wasm::GenerateInterruptStub(MacroAssembler& masm)
|
||||
masm.loadPtr(Address(IntArgReg0, WasmActivation::offsetOfResumePC()), IntArgReg1);
|
||||
masm.storePtr(IntArgReg1, Address(s0, masm.framePushed()));
|
||||
|
||||
# ifdef USES_O32_ABI
|
||||
// MIPS ABI requires rewserving stack for registes $a0 to $a3.
|
||||
masm.subFromStackPtr(Imm32(4 * sizeof(intptr_t)));
|
||||
# endif
|
||||
|
||||
masm.assertStackAlignment(ABIStackAlignment);
|
||||
masm.call(SymbolicAddress::HandleExecutionInterrupt);
|
||||
|
||||
# ifdef USES_O32_ABI
|
||||
masm.addToStackPtr(Imm32(4 * sizeof(intptr_t)));
|
||||
# endif
|
||||
|
||||
masm.branchIfFalseBool(ReturnReg, JumpTarget::Throw);
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ enum class WasmAstExprKind
|
||||
Const,
|
||||
ConversionOperator,
|
||||
GetLocal,
|
||||
IfElse,
|
||||
If,
|
||||
Load,
|
||||
Nop,
|
||||
Return,
|
||||
@@ -385,29 +385,25 @@ class WasmAstReturn : public WasmAstExpr
|
||||
WasmAstExpr* maybeExpr() const { return maybeExpr_; }
|
||||
};
|
||||
|
||||
class WasmAstIfElse : public WasmAstExpr
|
||||
class WasmAstIf : public WasmAstExpr
|
||||
{
|
||||
Expr expr_;
|
||||
WasmAstExpr* cond_;
|
||||
WasmAstExpr* ifBody_;
|
||||
WasmAstExpr* elseBody_;
|
||||
WasmAstExpr* thenBranch_;
|
||||
WasmAstExpr* elseBranch_;
|
||||
|
||||
public:
|
||||
static const WasmAstExprKind Kind = WasmAstExprKind::IfElse;
|
||||
WasmAstIfElse(Expr expr, WasmAstExpr* cond, WasmAstExpr* ifBody,
|
||||
WasmAstExpr* elseBody = nullptr)
|
||||
static const WasmAstExprKind Kind = WasmAstExprKind::If;
|
||||
WasmAstIf(WasmAstExpr* cond, WasmAstExpr* thenBranch, WasmAstExpr* elseBranch)
|
||||
: WasmAstExpr(Kind),
|
||||
expr_(expr),
|
||||
cond_(cond),
|
||||
ifBody_(ifBody),
|
||||
elseBody_(elseBody)
|
||||
thenBranch_(thenBranch),
|
||||
elseBranch_(elseBranch)
|
||||
{}
|
||||
|
||||
bool hasElse() const { return expr_ == Expr::IfElse; }
|
||||
Expr expr() const { return expr_; }
|
||||
WasmAstExpr& cond() const { return *cond_; }
|
||||
WasmAstExpr& ifBody() const { return *ifBody_; }
|
||||
WasmAstExpr& elseBody() const { return *elseBody_; }
|
||||
WasmAstExpr& thenBranch() const { return *thenBranch_; }
|
||||
bool hasElse() const { return !!elseBranch_; }
|
||||
WasmAstExpr& elseBranch() const { MOZ_ASSERT(hasElse()); return *elseBranch_; }
|
||||
};
|
||||
|
||||
class WasmAstLoadStoreAddress
|
||||
@@ -808,7 +804,6 @@ class WasmToken
|
||||
Func,
|
||||
GetLocal,
|
||||
If,
|
||||
IfElse,
|
||||
Import,
|
||||
Index,
|
||||
UnsignedInteger,
|
||||
@@ -1936,11 +1931,8 @@ WasmTokenStream::next()
|
||||
return WasmToken(WasmToken::Import, begin, cur_);
|
||||
if (consume(MOZ_UTF16("infinity")))
|
||||
return WasmToken(WasmToken::Infinity, begin, cur_);
|
||||
if (consume(MOZ_UTF16("if"))) {
|
||||
if (consume(MOZ_UTF16("_else")))
|
||||
return WasmToken(WasmToken::IfElse, begin, cur_);
|
||||
if (consume(MOZ_UTF16("if")))
|
||||
return WasmToken(WasmToken::If, begin, cur_);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
@@ -2570,25 +2562,27 @@ ParseConversionOperator(WasmParseContext& c, Expr expr)
|
||||
return new(c.lifo) WasmAstConversionOperator(expr, op);
|
||||
}
|
||||
|
||||
static WasmAstIfElse*
|
||||
ParseIfElse(WasmParseContext& c, Expr expr)
|
||||
static WasmAstIf*
|
||||
ParseIf(WasmParseContext& c)
|
||||
{
|
||||
WasmAstExpr* cond = ParseExpr(c);
|
||||
if (!cond)
|
||||
return nullptr;
|
||||
|
||||
WasmAstExpr* ifBody = ParseExpr(c);
|
||||
if (!ifBody)
|
||||
WasmAstExpr* thenBranch = ParseExpr(c);
|
||||
if (!thenBranch)
|
||||
return nullptr;
|
||||
|
||||
WasmAstExpr* elseBody = nullptr;
|
||||
if (expr == Expr::IfElse) {
|
||||
elseBody = ParseExpr(c);
|
||||
if (!elseBody)
|
||||
WasmAstExpr* elseBranch = nullptr;
|
||||
if (c.ts.getIf(WasmToken::OpenParen)) {
|
||||
elseBranch = ParseExprInsideParens(c);
|
||||
if (!elseBranch)
|
||||
return nullptr;
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new(c.lifo) WasmAstIfElse(expr, cond, ifBody, elseBody);
|
||||
return new(c.lifo) WasmAstIf(cond, thenBranch, elseBranch);
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -2721,47 +2715,25 @@ ParseStore(WasmParseContext& c, Expr expr)
|
||||
}
|
||||
|
||||
static WasmAstBranchTable*
|
||||
ParseBranchTable(WasmParseContext& c)
|
||||
ParseBranchTable(WasmParseContext& c, WasmToken brTable)
|
||||
{
|
||||
WasmAstExpr* index = ParseExpr(c);
|
||||
if (!index)
|
||||
return nullptr;
|
||||
|
||||
if (!c.ts.match(WasmToken::OpenParen, c.error))
|
||||
return nullptr;
|
||||
if (!c.ts.match(WasmToken::Table, c.error))
|
||||
return nullptr;
|
||||
|
||||
WasmRefVector table(c.lifo);
|
||||
|
||||
while (c.ts.getIf(WasmToken::OpenParen)) {
|
||||
if (!c.ts.match(WasmToken::Br, c.error))
|
||||
return nullptr;
|
||||
|
||||
WasmRef target;
|
||||
if (!c.ts.matchRef(&target, c.error))
|
||||
return nullptr;
|
||||
|
||||
WasmRef target;
|
||||
while (c.ts.getIfRef(&target)) {
|
||||
if (!table.append(target))
|
||||
return nullptr;
|
||||
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
if (table.empty()) {
|
||||
c.ts.generateError(brTable, c.error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!c.ts.match(WasmToken::OpenParen, c.error))
|
||||
return nullptr;
|
||||
if (!c.ts.match(WasmToken::Br, c.error))
|
||||
return nullptr;
|
||||
WasmRef def = table.popCopy();
|
||||
|
||||
WasmRef def;
|
||||
if (!c.ts.matchRef(&def, c.error))
|
||||
return nullptr;
|
||||
|
||||
if (!c.ts.match(WasmToken::CloseParen, c.error))
|
||||
WasmAstExpr* index = ParseExpr(c);
|
||||
if (!index)
|
||||
return nullptr;
|
||||
|
||||
return new(c.lifo) WasmAstBranchTable(*index, def, Move(table));
|
||||
@@ -2786,7 +2758,7 @@ ParseExprInsideParens(WasmParseContext& c)
|
||||
case WasmToken::BrIf:
|
||||
return ParseBranch(c, Expr::BrIf);
|
||||
case WasmToken::BrTable:
|
||||
return ParseBranchTable(c);
|
||||
return ParseBranchTable(c, token);
|
||||
case WasmToken::Call:
|
||||
return ParseCall(c, Expr::Call);
|
||||
case WasmToken::CallImport:
|
||||
@@ -2800,9 +2772,7 @@ ParseExprInsideParens(WasmParseContext& c)
|
||||
case WasmToken::ConversionOpcode:
|
||||
return ParseConversionOperator(c, token.expr());
|
||||
case WasmToken::If:
|
||||
return ParseIfElse(c, Expr::If);
|
||||
case WasmToken::IfElse:
|
||||
return ParseIfElse(c, Expr::IfElse);
|
||||
return ParseIf(c);
|
||||
case WasmToken::GetLocal:
|
||||
return ParseGetLocal(c);
|
||||
case WasmToken::Load:
|
||||
@@ -3442,11 +3412,11 @@ ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b)
|
||||
}
|
||||
|
||||
static bool
|
||||
ResolveIfElse(Resolver& r, WasmAstIfElse& ie)
|
||||
ResolveIfElse(Resolver& r, WasmAstIf& i)
|
||||
{
|
||||
return ResolveExpr(r, ie.cond()) &&
|
||||
ResolveExpr(r, ie.ifBody()) &&
|
||||
(!ie.hasElse() || ResolveExpr(r, ie.elseBody()));
|
||||
return ResolveExpr(r, i.cond()) &&
|
||||
ResolveExpr(r, i.thenBranch()) &&
|
||||
(!i.hasElse() || ResolveExpr(r, i.elseBranch()));
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -3513,8 +3483,8 @@ ResolveExpr(Resolver& r, WasmAstExpr& expr)
|
||||
return ResolveConversionOperator(r, expr.as<WasmAstConversionOperator>());
|
||||
case WasmAstExprKind::GetLocal:
|
||||
return ResolveGetLocal(r, expr.as<WasmAstGetLocal>());
|
||||
case WasmAstExprKind::IfElse:
|
||||
return ResolveIfElse(r, expr.as<WasmAstIfElse>());
|
||||
case WasmAstExprKind::If:
|
||||
return ResolveIfElse(r, expr.as<WasmAstIf>());
|
||||
case WasmAstExprKind::Load:
|
||||
return ResolveLoad(r, expr.as<WasmAstLoad>());
|
||||
case WasmAstExprKind::Return:
|
||||
@@ -3771,12 +3741,12 @@ EncodeConversionOperator(Encoder& e, WasmAstConversionOperator& b)
|
||||
}
|
||||
|
||||
static bool
|
||||
EncodeIfElse(Encoder& e, WasmAstIfElse& ie)
|
||||
EmitIf(Encoder& e, WasmAstIf& i)
|
||||
{
|
||||
return e.writeExpr(ie.expr()) &&
|
||||
EncodeExpr(e, ie.cond()) &&
|
||||
EncodeExpr(e, ie.ifBody()) &&
|
||||
(!ie.hasElse() || EncodeExpr(e, ie.elseBody()));
|
||||
return e.writeExpr(i.hasElse() ? Expr::IfElse : Expr::If) &&
|
||||
EncodeExpr(e, i.cond()) &&
|
||||
EncodeExpr(e, i.thenBranch()) &&
|
||||
(!i.hasElse() || EncodeExpr(e, i.elseBranch()));
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -3855,8 +3825,8 @@ EncodeExpr(Encoder& e, WasmAstExpr& expr)
|
||||
return EncodeConversionOperator(e, expr.as<WasmAstConversionOperator>());
|
||||
case WasmAstExprKind::GetLocal:
|
||||
return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
|
||||
case WasmAstExprKind::IfElse:
|
||||
return EncodeIfElse(e, expr.as<WasmAstIfElse>());
|
||||
case WasmAstExprKind::If:
|
||||
return EmitIf(e, expr.as<WasmAstIf>());
|
||||
case WasmAstExprKind::Load:
|
||||
return EncodeLoad(e, expr.as<WasmAstLoad>());
|
||||
case WasmAstExprKind::Return:
|
||||
|
||||
@@ -383,10 +383,6 @@ obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedObject setPrototypeOf(cx, &args.callee());
|
||||
if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, setPrototypeOf))
|
||||
return false;
|
||||
|
||||
if (args.length() < 2) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"Object.setPrototypeOf", "1", "");
|
||||
@@ -1055,13 +1051,6 @@ ProtoSetter(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Do this here, rather than after the this-check so even likely-buggy
|
||||
// use of the __proto__ setter on unacceptable values, where no subsequent
|
||||
// use occurs on an acceptable value, will trigger a warning.
|
||||
RootedObject callee(cx, &args.callee());
|
||||
if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, callee))
|
||||
return false;
|
||||
|
||||
HandleValue thisv = args.thisv();
|
||||
if (thisv.isNullOrUndefined()) {
|
||||
ReportIncompatible(cx, args);
|
||||
@@ -1097,7 +1086,7 @@ static const JSFunctionSpec object_methods[] = {
|
||||
JS_FN(js_toSource_str, obj_toSource, 0,0),
|
||||
#endif
|
||||
JS_FN(js_toString_str, obj_toString, 0,0),
|
||||
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0,JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0),
|
||||
JS_FN(js_valueOf_str, obj_valueOf, 0,0),
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
JS_FN(js_watch_str, obj_watch, 2,0),
|
||||
@@ -1107,10 +1096,10 @@ static const JSFunctionSpec object_methods[] = {
|
||||
JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,0),
|
||||
JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
|
||||
#if JS_OLD_GETTER_SETTER_METHODS
|
||||
JS_SELF_HOSTED_FN(js_defineGetter_str, "ObjectDefineGetter", 2,JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN(js_defineSetter_str, "ObjectDefineSetter", 2,JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN(js_lookupGetter_str, "ObjectLookupGetter", 1,JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN(js_lookupSetter_str, "ObjectLookupSetter", 1,JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN(js_defineGetter_str, "ObjectDefineGetter", 2,0),
|
||||
JS_SELF_HOSTED_FN(js_defineSetter_str, "ObjectDefineSetter", 2,0),
|
||||
JS_SELF_HOSTED_FN(js_lookupGetter_str, "ObjectLookupGetter", 1,0),
|
||||
JS_SELF_HOSTED_FN(js_lookupSetter_str, "ObjectLookupSetter", 1,0),
|
||||
#endif
|
||||
JS_FS_END
|
||||
};
|
||||
@@ -1123,8 +1112,8 @@ static const JSPropertySpec object_properties[] = {
|
||||
};
|
||||
|
||||
static const JSFunctionSpec object_static_methods[] = {
|
||||
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2, JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN("assign", "ObjectStaticAssign", 2, 0),
|
||||
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, 0),
|
||||
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0),
|
||||
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0),
|
||||
JS_FN("keys", obj_keys, 1, 0),
|
||||
@@ -1136,7 +1125,7 @@ static const JSFunctionSpec object_static_methods[] = {
|
||||
JS_INLINABLE_FN("create", obj_create, 2, 0, ObjectCreate),
|
||||
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1, 0),
|
||||
JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1, 0),
|
||||
JS_SELF_HOSTED_FN("isExtensible", "ObjectIsExtensible", 1, JSPROP_DEFINE_LATE),
|
||||
JS_SELF_HOSTED_FN("isExtensible", "ObjectIsExtensible", 1, 0),
|
||||
JS_FN("preventExtensions", obj_preventExtensions, 1, 0),
|
||||
JS_FN("freeze", obj_freeze, 1, 0),
|
||||
JS_FN("isFrozen", obj_isFrozen, 1, 0),
|
||||
@@ -1207,22 +1196,6 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
|
||||
if (!holder)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Define self-hosted functions on Object and Function after setting the
|
||||
* intrinsics holder (which is needed to define self-hosted functions).
|
||||
*/
|
||||
if (!cx->runtime()->isSelfHostingGlobal(global)) {
|
||||
if (!JS_DefineFunctions(cx, ctor, object_static_methods, OnlyDefineLateProperties))
|
||||
return false;
|
||||
if (!JS_DefineFunctions(cx, proto, object_methods, OnlyDefineLateProperties))
|
||||
return false;
|
||||
RootedObject funProto(cx, global->getOrCreateFunctionPrototype(cx));
|
||||
if (!funProto)
|
||||
return false;
|
||||
if (!JS_DefineFunctions(cx, funProto, function_methods, OnlyDefineLateProperties))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The global object should have |Object.prototype| as its [[Prototype]].
|
||||
* Eventually we'd like to have standard classes be there from the start,
|
||||
|
||||
@@ -3098,7 +3098,9 @@ elif test "$CPU_ARCH" = "x86_64"; then
|
||||
|
||||
dnl Signal-handler OOM checking requires large mprotected guard regions, so
|
||||
dnl currently it is only implemented on x64.
|
||||
AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
ASMJS_MAY_USE_SIGNAL_HANDLERS=1
|
||||
ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB=1
|
||||
elif test "$CPU_ARCH" = "arm"; then
|
||||
AC_DEFINE(JS_CODEGEN_ARM)
|
||||
@@ -3107,6 +3109,13 @@ elif test "$CPU_ARCH" = "arm"; then
|
||||
AC_DEFINE(JS_DISASM_ARM)
|
||||
JS_DISASM_ARM=1
|
||||
fi
|
||||
|
||||
dnl ARM platforms may trap on unalinged accesses; catch the signal and
|
||||
dnl recover.
|
||||
AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
AC_DEFINE(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED)
|
||||
ASMJS_MAY_USE_SIGNAL_HANDLERS=1
|
||||
ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED=1
|
||||
elif test "$CPU_ARCH" = "mips32"; then
|
||||
AC_DEFINE(JS_CODEGEN_MIPS32)
|
||||
JS_CODEGEN_MIPS32=1
|
||||
@@ -3128,7 +3137,9 @@ AC_SUBST(JS_CODEGEN_X86)
|
||||
AC_SUBST(JS_CODEGEN_X64)
|
||||
AC_SUBST(JS_CODEGEN_NONE)
|
||||
AC_SUBST(JS_DISASM_ARM)
|
||||
AC_SUBST(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
AC_SUBST(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
AC_SUBST(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_UNALIGNED)
|
||||
|
||||
dnl ========================================================
|
||||
dnl jprof
|
||||
|
||||
@@ -1842,6 +1842,21 @@ test_int32(heap);
|
||||
test_uint32(heap);
|
||||
test_misc(heap);
|
||||
|
||||
// Bug 1254167: Effective Address Analysis should be void on atomics accesses,
|
||||
var code = `
|
||||
"use asm";
|
||||
var HEAP32 = new stdlib.Int32Array(heap);
|
||||
var load = stdlib.Atomics.load;
|
||||
function f() {
|
||||
var i2 = 0;
|
||||
i2 = 305002 | 0;
|
||||
return load(HEAP32, i2 >> 2) | 0;
|
||||
}
|
||||
return f;
|
||||
`;
|
||||
var f = asmLink(asmCompile('stdlib', 'ffi', 'heap', code), this, {}, new SharedArrayBuffer(0x10000));
|
||||
assertErrorMessage(f, RangeError, /out-of-range index/);
|
||||
|
||||
// Test that ARM callouts compile.
|
||||
setARMHwCapFlags('vfp');
|
||||
|
||||
@@ -1858,3 +1873,4 @@ asmCompile('stdlib', 'ffi', 'heap',
|
||||
|
||||
return { xchg: do_xchg }
|
||||
`);
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
load(libdir + "wasm.js");
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// if_else
|
||||
// if
|
||||
|
||||
// Condition is an int32
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local f32) (if (get_local 0) (i32.const 1))))'), TypeError, mismatchError("f32", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local f32) (if_else (get_local 0) (i32.const 1) (i32.const 0))))'), TypeError, mismatchError("f32", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local f64) (if_else (get_local 0) (i32.const 1) (i32.const 0))))'), TypeError, mismatchError("f64", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local f32) (if (get_local 0) (i32.const 1) (i32.const 0))))'), TypeError, mismatchError("f32", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (local f64) (if (get_local 0) (i32.const 1) (i32.const 0))))'), TypeError, mismatchError("f64", "i32"));
|
||||
wasmEvalText('(module (func (local i32) (if (get_local 0) (nop))) (export "" 0))');
|
||||
wasmEvalText('(module (func (local i32) (if_else (get_local 0) (nop) (nop))) (export "" 0))');
|
||||
wasmEvalText('(module (func (local i32) (if (get_local 0) (nop) (nop))) (export "" 0))');
|
||||
|
||||
// Expression values types are consistent
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (local f32) (if_else (i32.const 42) (get_local 0) (i32.const 0))))'), TypeError, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (local f64) (if_else (i32.const 42) (i32.const 0) (get_local 0))))'), TypeError, mismatchError("void", "i32"));
|
||||
assertEq(wasmEvalText('(module (func (result i32) (if_else (i32.const 42) (i32.const 1) (i32.const 2))) (export "" 0))')(), 1);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (if_else (i32.const 0) (i32.const 1) (i32.const 2))) (export "" 0))')(), 2);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (local f32) (if (i32.const 42) (get_local 0) (i32.const 0))))'), TypeError, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (local f64) (if (i32.const 42) (i32.const 0) (get_local 0))))'), TypeError, mismatchError("void", "i32"));
|
||||
assertEq(wasmEvalText('(module (func (result i32) (if (i32.const 42) (i32.const 1) (i32.const 2))) (export "" 0))')(), 1);
|
||||
assertEq(wasmEvalText('(module (func (result i32) (if (i32.const 0) (i32.const 1) (i32.const 2))) (export "" 0))')(), 2);
|
||||
|
||||
// If we don't yield, sub expressions types don't have to match
|
||||
assertEq(wasmEvalText('(module (func (if_else (i32.const 42) (i32.const 1) (i32.const 0))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (param f32) (if_else (i32.const 42) (i32.const 1) (get_local 0))) (export "" 0))')(13.37), undefined);
|
||||
assertEq(wasmEvalText('(module (func (if (i32.const 42) (i32.const 1) (i32.const 0))) (export "" 0))')(), undefined);
|
||||
assertEq(wasmEvalText('(module (func (param f32) (if (i32.const 42) (i32.const 1) (get_local 0))) (export "" 0))')(13.37), undefined);
|
||||
|
||||
// Sub-expression values are returned
|
||||
assertEq(wasmEvalText(`(module
|
||||
(func
|
||||
(result i32)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 42)
|
||||
(block
|
||||
(
|
||||
if_else
|
||||
if
|
||||
(block
|
||||
(i32.const 3)
|
||||
(i32.const 5)
|
||||
@@ -51,7 +51,7 @@ assertEq(wasmEvalText(`(module
|
||||
(import "inc" "" (result i32))
|
||||
(func
|
||||
(result i32)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 42)
|
||||
(i32.const 1)
|
||||
(call_import 0)
|
||||
@@ -65,7 +65,7 @@ assertEq(wasmEvalText(`(module
|
||||
(import "inc" "" (result i32))
|
||||
(func
|
||||
(result i32)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 0)
|
||||
(call_import 0)
|
||||
(i32.const 1)
|
||||
@@ -99,19 +99,19 @@ assertEq(wasmEvalText(`(module
|
||||
)`, imports)(), undefined);
|
||||
assertEq(counter, 1);
|
||||
|
||||
// One can chain if_else with if/if_else
|
||||
// One can chain if with if/if
|
||||
counter = 0;
|
||||
assertEq(wasmEvalText(`(module
|
||||
(import "inc" "" (result i32))
|
||||
(func
|
||||
(result i32)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 1)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 2)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 3)
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 0)
|
||||
(call_import 0)
|
||||
(i32.const 42)
|
||||
@@ -129,8 +129,8 @@ assertEq(counter, 0);
|
||||
|
||||
// "if" doesn't return an expression value
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (if (i32.const 42) (i32.const 0))))'), TypeError, mismatchError("void", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (if_else (i32.const 1) (i32.const 0) (if (i32.const 1) (i32.const 1)))))'), TypeError, mismatchError("void", "i32"));
|
||||
wasmEvalText('(module (func (if_else (i32.const 1) (i32.const 0) (if (i32.const 1) (i32.const 1)))))');
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (if (i32.const 1) (i32.const 0) (if (i32.const 1) (i32.const 1)))))'), TypeError, mismatchError("void", "i32"));
|
||||
wasmEvalText('(module (func (if (i32.const 1) (i32.const 0) (if (i32.const 1) (i32.const 1)))))');
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// return
|
||||
@@ -164,7 +164,7 @@ assertErrorMessage(() => wasmEvalText('(module (func (loop (br_if 2 (i32.const 0
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(if_else
|
||||
(if
|
||||
(br 0)
|
||||
(i32.const 0)
|
||||
(i32.const 2)
|
||||
@@ -244,7 +244,7 @@ assertEq(wasmEvalText(`(module (func
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32)
|
||||
(block
|
||||
(if_else
|
||||
(if
|
||||
(i32.const 1)
|
||||
(br 0)
|
||||
(return (i32.const 0))
|
||||
@@ -353,15 +353,13 @@ assertEq(wasmEvalText(`(module (func (result i32) (local i32)
|
||||
// ----------------------------------------------------------------------------
|
||||
// br_table
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br_table (i32.const 0) (table) (br 0))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table (i32.const 0) (table (br 2)) (br 0)))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table (f32.const 0) (table) (br 0)))))'), TypeError, mismatchError("f32", "i32"));
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (br_table 0 (i32.const 0))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table 2 0 (i32.const 0)))))'), TypeError, DEPTH_OUT_OF_BOUNDS);
|
||||
assertErrorMessage(() => wasmEvalText('(module (func (block (br_table 0 (f32.const 0)))))'), TypeError, mismatchError("f32", "i32"));
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $default
|
||||
(br_table (get_local 0) (table) (br $default))
|
||||
(br_table $default (get_local 0))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
@@ -369,7 +367,7 @@ assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $default
|
||||
(br_table (return (i32.const 1)) (table) (br $default))
|
||||
(br_table $default (return (i32.const 1)))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 2))
|
||||
@@ -378,7 +376,7 @@ assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
assertEq(wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $outer
|
||||
(block $inner
|
||||
(br_table (get_local 0) (table) (br $inner))
|
||||
(br_table $inner (get_local 0))
|
||||
(return (i32.const 0))
|
||||
)
|
||||
(return (i32.const 1))
|
||||
@@ -391,11 +389,7 @@ var f = wasmEvalText(`(module (func (result i32) (param i32)
|
||||
(block $1
|
||||
(block $2
|
||||
(block $default
|
||||
(br_table
|
||||
(get_local 0)
|
||||
(table (br $0) (br $1) (br $2))
|
||||
(br $default)
|
||||
)
|
||||
(br_table $0 $1 $2 $default (get_local 0))
|
||||
)
|
||||
(return (i32.const -1))
|
||||
)
|
||||
|
||||
@@ -27,10 +27,10 @@ function testComparison(type, opcode, lhs, rhs, expect) {
|
||||
(func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
|
||||
(func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
|
||||
(export "" 1))`)(), expect);
|
||||
// Also test if_else, for the compare-and-branch path.
|
||||
// Also test if, for the compare-and-branch path.
|
||||
assertEq(wasmEvalText(`(module
|
||||
(func (param i64) (param i64) (result i32)
|
||||
(if_else (i64.${opcode} (get_local 0) (get_local 1))
|
||||
(if (i64.${opcode} (get_local 0) (get_local 1))
|
||||
(i32.const 1)
|
||||
(i32.const 0)))
|
||||
(func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
|
||||
|
||||
@@ -71,24 +71,21 @@ function testStoreError(type, ext, base, offset, align, errorMsg) {
|
||||
}
|
||||
|
||||
testLoad('i32', '', 0, 0, 0, 0x03020100);
|
||||
|
||||
testLoad('i32', '', 1, 0, 0, 0x03020100); // TODO: unaligned NYI
|
||||
//testLoad('i32', '', 1, 0, 0, 0x04030201); // TODO: unaligned NYI
|
||||
|
||||
testLoad('i32', '', 1, 0, 0, 0x04030201);
|
||||
testLoad('i32', '', 0, 4, 0, 0x07060504);
|
||||
//testLoad('i32', '', 1, 3, 4, 0x07060504); // TODO: unaligned base NYI
|
||||
testLoad('i32', '', 1, 3, 4, 0x07060504);
|
||||
//testLoad('i64', '', 0, 0, 0, 0x0001020304050607); // TODO: i64 NYI
|
||||
//testLoad('i64', '', 1, 0, 0, 0x0102030405060708); // TODO: i64 NYI
|
||||
//testLoad('i64', '', 0, 1, 0, 0x0102030405060708); // TODO: i64 NYI
|
||||
//testLoad('i64', '', 1, 1, 4, 0x0203040506070809); // TODO: i64 NYI
|
||||
testLoad('f32', '', 0, 0, 0, 3.820471434542632e-37);
|
||||
//testLoad('f32', '', 1, 0, 0, 1.539989614439558e-36); // TODO: unaligned NYI
|
||||
testLoad('f32', '', 1, 0, 0, 1.539989614439558e-36);
|
||||
testLoad('f32', '', 0, 4, 0, 1.0082513512365273e-34);
|
||||
//testLoad('f32', '', 1, 3, 4, 1.0082513512365273e-34); // TODO: unaligned base NYI
|
||||
testLoad('f32', '', 1, 3, 4, 1.0082513512365273e-34);
|
||||
testLoad('f64', '', 0, 0, 0, 7.949928895127363e-275);
|
||||
//testLoad('f64', '', 1, 0, 0, 5.447603722011605e-270); // TODO: unaligned NYI
|
||||
testLoad('f64', '', 1, 0, 0, 5.447603722011605e-270);
|
||||
testLoad('f64', '', 0, 8, 0, 3.6919162048650923e-236);
|
||||
//testLoad('f64', '', 1, 7, 4, 3.6919162048650923e-236); // TODO: unaligned base NYI
|
||||
testLoad('f64', '', 1, 7, 4, 3.6919162048650923e-236);
|
||||
|
||||
testLoad('i32', '8_s', 16, 0, 0, -0x10);
|
||||
testLoad('i32', '8_u', 16, 0, 0, 0xf0);
|
||||
@@ -114,9 +111,9 @@ testLoadNYI('32_u');
|
||||
//testLoad('i64', '32_u', 16, 0, 0, 0x8f9fafb); // TODO: i64 NYI
|
||||
|
||||
testStore('i32', '', 0, 0, 0, -0x3f3e2c2c);
|
||||
//testStore('i32', '', 1, 0, 0, -0x3f3e2c2c); // TODO: unaligned NYI
|
||||
//testStore('i32', '', 0, 1, 0, 0xc0c1d3d4); // TODO: offset NYI
|
||||
//testStore('i32', '', 1, 1, 4, 0xc0c1d3d4); // TODO: offset NYI
|
||||
testStore('i32', '', 1, 0, 0, -0x3f3e2c2c);
|
||||
testStore('i32', '', 0, 1, 0, -0x3f3e2c2c);
|
||||
testStore('i32', '', 1, 1, 4, -0x3f3e2c2c);
|
||||
|
||||
function testStoreNYI(ext) {
|
||||
assertErrorMessage(() => wasmEvalText(`(module (memory 1) (func (i64.store${ext} (i32.const 0) (i32.const 0))))`), TypeError, /NYI/);
|
||||
@@ -134,11 +131,11 @@ testStoreNYI('32');
|
||||
//testStore('i64', '32', 0, 0, 0, 0x23); // TODO: i64 NYI
|
||||
|
||||
testStore('f32', '', 0, 0, 0, 0.01234566979110241);
|
||||
//testStore('f32', '', 1, 0, 0, 0.01234566979110241); // TODO: unaligned NYI
|
||||
testStore('f32', '', 1, 0, 0, 0.01234566979110241);
|
||||
testStore('f32', '', 0, 4, 0, 0.01234566979110241);
|
||||
//testStore('f32', '', 1, 3, 4, 0.01234566979110241); // TODO: unaligned base NYI
|
||||
testStore('f32', '', 1, 3, 4, 0.01234566979110241);
|
||||
testStore('f64', '', 0, 0, 0, 0.89012345);
|
||||
//testStore('f64', '', 1, 0, 0, 0.89012345); // TODO: unaligned NYI
|
||||
testStore('f64', '', 1, 0, 0, 0.89012345);
|
||||
testStore('f64', '', 0, 8, 0, 0.89012345);
|
||||
testStore('f64', '', 1, 7, 4, 0.89012345);
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
load(libdir + "wasm.js");
|
||||
|
||||
assertEq(wasmEvalText(`(module
|
||||
(func (result i32) (param i32)
|
||||
(loop (if (i32.const 0) (br 0)) (get_local 0)))
|
||||
(export "" 0)
|
||||
)`)(42), 42);
|
||||
|
||||
wasmEvalText(`(module (func $func$0
|
||||
(block (if (i32.const 1) (loop (br_table 0 (br 0)))))
|
||||
)
|
||||
)`);
|
||||
@@ -190,7 +190,8 @@ EffectiveAddressAnalysis::analyze()
|
||||
for (MInstructionIterator i = block->begin(); i != block->end(); i++) {
|
||||
// Note that we don't check for MAsmJSCompareExchangeHeap
|
||||
// or MAsmJSAtomicBinopHeap, because the backend and the OOB
|
||||
// mechanism don't support non-zero offsets for them yet.
|
||||
// mechanism don't support non-zero offsets for them yet
|
||||
// (TODO bug 1254935).
|
||||
if (i->isLsh())
|
||||
AnalyzeLsh(graph_.alloc(), i->toLsh());
|
||||
else if (i->isAsmJSLoadHeap())
|
||||
|
||||
@@ -229,7 +229,7 @@ class MIRGenerator
|
||||
|
||||
bool needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* access) const;
|
||||
size_t foldableOffsetRange(const MAsmJSHeapAccess* access) const;
|
||||
size_t foldableOffsetRange(bool accessNeedsBoundsCheck) const;
|
||||
size_t foldableOffsetRange(bool accessNeedsBoundsCheck, bool atomic) const;
|
||||
|
||||
private:
|
||||
GraphSpewer gs_;
|
||||
|
||||
@@ -126,11 +126,11 @@ MIRGenerator::needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* access) const
|
||||
size_t
|
||||
MIRGenerator::foldableOffsetRange(const MAsmJSHeapAccess* access) const
|
||||
{
|
||||
return foldableOffsetRange(access->needsBoundsCheck());
|
||||
return foldableOffsetRange(access->needsBoundsCheck(), access->isAtomicAccess());
|
||||
}
|
||||
|
||||
size_t
|
||||
MIRGenerator::foldableOffsetRange(bool accessNeedsBoundsCheck) const
|
||||
MIRGenerator::foldableOffsetRange(bool accessNeedsBoundsCheck, bool atomic) const
|
||||
{
|
||||
// This determines whether it's ok to fold up to WasmImmediateSize
|
||||
// offsets, instead of just WasmCheckedImmediateSize.
|
||||
@@ -147,7 +147,8 @@ MIRGenerator::foldableOffsetRange(bool accessNeedsBoundsCheck) const
|
||||
"spill over, so ensure a space at the end.");
|
||||
|
||||
// Signal-handling can be dynamically disabled by OS bugs or flags.
|
||||
if (usesSignalHandlersForAsmJSOOB_)
|
||||
// Bug 1254935: Atomic accesses can't be handled with signal handlers yet.
|
||||
if (usesSignalHandlersForAsmJSOOB_ && !atomic)
|
||||
return WasmImmediateRange;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
|
||||
#include "asmjs/WasmSignalHandlers.h"
|
||||
#include "jit/arm/Assembler-arm.h"
|
||||
#include "jit/arm/disasm/Constants-arm.h"
|
||||
#include "jit/AtomicOperations.h"
|
||||
@@ -1510,10 +1511,21 @@ Simulator::readW(int32_t addr, SimInstruction* instr)
|
||||
if ((addr & 3) == 0 || !HasAlignmentFault()) {
|
||||
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
return *ptr;
|
||||
} else {
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// In WebAssembly, we want unaligned accesses to either raise a signal or
|
||||
// do the right thing. Making this simulator properly emulate the behavior
|
||||
// of raising a signal is complex, so as a special-case, when in wasm code,
|
||||
// we just do the right thing.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
int value;
|
||||
memcpy(&value, ptr, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1522,10 +1534,18 @@ Simulator::writeW(int32_t addr, int value, SimInstruction* instr)
|
||||
if ((addr & 3) == 0) {
|
||||
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
|
||||
*ptr = value;
|
||||
} else {
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
return;
|
||||
}
|
||||
|
||||
// See the comments above in readW.
|
||||
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
|
||||
char* ptr = reinterpret_cast<char*>(addr);
|
||||
memcpy(ptr, &value, sizeof(value));
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// For the time being, define Relaxed operations in terms of SeqCst
|
||||
|
||||
@@ -455,7 +455,7 @@ CodeGeneratorX86Shared::maybeEmitAsmJSLoadBoundsCheck(const MAsmJSLoadHeap* mir,
|
||||
return wasm::HeapAccess::NoLengthCheck;
|
||||
|
||||
if (mir->isAtomicAccess())
|
||||
return maybeEmitThrowingAsmJSBoundsCheck(mir, mir, ins->ptr());
|
||||
return emitAsmJSBoundsCheckBranch(mir, mir, ToRegister(ins->ptr()), nullptr);
|
||||
|
||||
*ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(ins->output()),
|
||||
mir->accessType());
|
||||
@@ -475,7 +475,7 @@ CodeGeneratorX86Shared::maybeEmitAsmJSStoreBoundsCheck(const MAsmJSStoreHeap* mi
|
||||
return wasm::HeapAccess::NoLengthCheck;
|
||||
|
||||
if (mir->isAtomicAccess())
|
||||
return maybeEmitThrowingAsmJSBoundsCheck(mir, mir, ins->ptr());
|
||||
return emitAsmJSBoundsCheckBranch(mir, mir, ToRegister(ins->ptr()), nullptr);
|
||||
|
||||
*rejoin = alloc().lifoAlloc()->newInfallible<Label>();
|
||||
return emitAsmJSBoundsCheckBranch(mir, mir, ToRegister(ins->ptr()), *rejoin);
|
||||
|
||||
@@ -76,7 +76,6 @@ MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate characte
|
||||
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
|
||||
MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
|
||||
MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
|
||||
MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
|
||||
MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}")
|
||||
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
|
||||
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}")
|
||||
@@ -382,7 +381,6 @@ MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 0, JSEXN_TYPEERR, "proxy must report same
|
||||
MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
|
||||
MSG_DEF(JSMSG_PROXY_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
|
||||
MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy")
|
||||
MSG_DEF(JSMSG_DEPRECATED_PROXY_CREATE, 0, JSEXN_NONE, "Proxy.create and Proxy.createFunction are deprecated, use new Proxy instead")
|
||||
|
||||
// Structured cloning
|
||||
MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clone version")
|
||||
|
||||
+2
-3
@@ -3682,15 +3682,14 @@ JS_IsConstructor(JSFunction* fun)
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
PropertyDefinitionBehavior behavior)
|
||||
JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs)
|
||||
{
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
return DefineFunctions(cx, obj, fs, NotIntrinsic, behavior);
|
||||
return DefineFunctions(cx, obj, fs, NotIntrinsic);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSFunction*)
|
||||
|
||||
+2
-17
@@ -827,10 +827,7 @@ class MOZ_STACK_CLASS SourceBufferHolder final
|
||||
object that delegates to a prototype
|
||||
containing this property */
|
||||
#define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */
|
||||
#define JSPROP_DEFINE_LATE 0x100 /* Don't define property when initially creating
|
||||
the constructor. Some objects like Function/Object
|
||||
have self-hosted functions that can only be defined
|
||||
after the initialization is already finished. */
|
||||
// 0x100 /* Unused */
|
||||
#define JSFUN_STUB_GSOPS 0x200 /* use JS_PropertyStub getter/setter
|
||||
instead of defaulting to class gsops
|
||||
for property holding function */
|
||||
@@ -3589,20 +3586,8 @@ JS_IsNativeFunction(JSObject* funobj, JSNative call);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsConstructor(JSFunction* fun);
|
||||
|
||||
/**
|
||||
* This enum is used to select if properties with JSPROP_DEFINE_LATE flag
|
||||
* should be defined on the object.
|
||||
* Normal JSAPI consumers probably always want DefineAllProperties here.
|
||||
*/
|
||||
enum PropertyDefinitionBehavior {
|
||||
DefineAllProperties,
|
||||
OnlyDefineLateProperties,
|
||||
DontDefineLateProperties
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineFunctions(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* fs,
|
||||
PropertyDefinitionBehavior behavior = DefineAllProperties);
|
||||
JS_DefineFunctions(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* fs);
|
||||
|
||||
extern JS_PUBLIC_API(JSFunction*)
|
||||
JS_DefineFunction(JSContext* cx, JS::Handle<JSObject*> obj, const char* name, JSNative call,
|
||||
|
||||
+1
-1
@@ -1653,7 +1653,7 @@ const JSFunctionSpec js::function_methods[] = {
|
||||
JS_FN(js_apply_str, fun_apply, 2,0),
|
||||
JS_FN(js_call_str, fun_call, 1,0),
|
||||
JS_FN("isGenerator", fun_isGenerator,0,0),
|
||||
JS_SELF_HOSTED_FN("bind", "FunctionBind", 2,JSPROP_DEFINE_LATE|JSFUN_HAS_REST),
|
||||
JS_SELF_HOSTED_FN("bind", "FunctionBind", 2,JSFUN_HAS_REST),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
||||
+2
-16
@@ -2908,24 +2908,10 @@ DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs
|
||||
|
||||
bool
|
||||
js::DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
DefineAsIntrinsic intrinsic, PropertyDefinitionBehavior behavior)
|
||||
DefineAsIntrinsic intrinsic)
|
||||
{
|
||||
for (; fs->name; fs++) {
|
||||
unsigned flags = fs->flags;
|
||||
switch (behavior) {
|
||||
case DefineAllProperties:
|
||||
break;
|
||||
case OnlyDefineLateProperties:
|
||||
if (!(flags & JSPROP_DEFINE_LATE))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(behavior == DontDefineLateProperties);
|
||||
if (flags & JSPROP_DEFINE_LATE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE, intrinsic))
|
||||
if (!DefineFunctionFromSpec(cx, obj, fs, fs->flags, intrinsic))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
+1
-2
@@ -992,8 +992,7 @@ enum DefineAsIntrinsic {
|
||||
|
||||
extern bool
|
||||
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
DefineAsIntrinsic intrinsic,
|
||||
PropertyDefinitionBehavior behavior = DefineAllProperties);
|
||||
DefineAsIntrinsic intrinsic);
|
||||
|
||||
/*
|
||||
* Set a watchpoint: a synchronous callback when the given property of the
|
||||
|
||||
@@ -299,7 +299,6 @@ UNIFIED_SOURCES += [
|
||||
'proxy/OpaqueCrossCompartmentWrapper.cpp',
|
||||
'proxy/Proxy.cpp',
|
||||
'proxy/ScriptedDirectProxyHandler.cpp',
|
||||
'proxy/ScriptedIndirectProxyHandler.cpp',
|
||||
'proxy/SecurityWrapper.cpp',
|
||||
'proxy/Wrapper.cpp',
|
||||
'vm/ArgumentsObject.cpp',
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "gc/Marking.h"
|
||||
#include "proxy/DeadObjectProxy.h"
|
||||
#include "proxy/ScriptedDirectProxyHandler.h"
|
||||
#include "proxy/ScriptedIndirectProxyHandler.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
@@ -752,8 +751,6 @@ JS_FRIEND_API(JSObject*)
|
||||
js::InitProxyClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
static const JSFunctionSpec static_methods[] = {
|
||||
JS_FN("create", proxy_create, 2, 0),
|
||||
JS_FN("createFunction", proxy_createFunction, 3, 0),
|
||||
JS_FN("revocable", proxy_revocable, 2, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@@ -1,611 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#include "proxy/ScriptedIndirectProxyHandler.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
static bool
|
||||
GetFundamentalTrap(JSContext* cx, HandleObject handler, HandlePropertyName name,
|
||||
MutableHandleValue fvalp)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
return GetProperty(cx, handler, handler, name, fvalp);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetDerivedTrap(JSContext* cx, HandleObject handler, HandlePropertyName name,
|
||||
MutableHandleValue fvalp)
|
||||
{
|
||||
MOZ_ASSERT(name == cx->names().has ||
|
||||
name == cx->names().hasOwn ||
|
||||
name == cx->names().get ||
|
||||
name == cx->names().set ||
|
||||
name == cx->names().keys ||
|
||||
name == cx->names().iterate);
|
||||
|
||||
return GetProperty(cx, handler, handler, name, fvalp);
|
||||
}
|
||||
|
||||
static bool
|
||||
Trap(JSContext* cx, HandleObject handler, HandleValue fval, unsigned argc, Value* argv,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
static bool
|
||||
Trap1(JSContext* cx, HandleObject handler, HandleValue fval, HandleId id, MutableHandleValue rval)
|
||||
{
|
||||
if (!IdToStringOrSymbol(cx, id, rval))
|
||||
return false;
|
||||
return Trap(cx, handler, fval, 1, rval.address(), rval);
|
||||
}
|
||||
|
||||
static bool
|
||||
Trap2(JSContext* cx, HandleObject handler, HandleValue fval, HandleId id, Value v_,
|
||||
MutableHandleValue rval)
|
||||
{
|
||||
RootedValue v(cx, v_);
|
||||
if (!IdToStringOrSymbol(cx, id, rval))
|
||||
return false;
|
||||
JS::AutoValueArray<2> argv(cx);
|
||||
argv[0].set(rval);
|
||||
argv[1].set(v);
|
||||
return Trap(cx, handler, fval, 2, argv.begin(), rval);
|
||||
}
|
||||
|
||||
static bool
|
||||
IndicatePropertyNotFound(MutableHandle<PropertyDescriptor> desc)
|
||||
{
|
||||
desc.object().set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueToBool(HandleValue v, bool* bp)
|
||||
{
|
||||
*bp = ToBoolean(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ArrayToIdVector(JSContext* cx, const Value& array, AutoIdVector& props)
|
||||
{
|
||||
MOZ_ASSERT(props.length() == 0);
|
||||
|
||||
if (array.isPrimitive())
|
||||
return true;
|
||||
|
||||
RootedObject obj(cx, &array.toObject());
|
||||
uint32_t length;
|
||||
if (!GetLengthProperty(cx, obj, &length))
|
||||
return false;
|
||||
|
||||
RootedValue v(cx);
|
||||
for (uint32_t n = 0; n < length; ++n) {
|
||||
if (!CheckForInterrupt(cx))
|
||||
return false;
|
||||
if (!GetElement(cx, obj, obj, n, &v))
|
||||
return false;
|
||||
RootedId id(cx);
|
||||
if (!ValueToId<CanGC>(cx, v, &id))
|
||||
return false;
|
||||
if (!props.append(id))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* Old-style indirect proxies allow callers to specify distinct scripted
|
||||
* [[Call]] and [[Construct]] traps. We use an intermediate object so that we
|
||||
* can stash this information in a single reserved slot on the proxy object.
|
||||
*
|
||||
* Note - Currently this is slightly unnecesary, because we actually have 2
|
||||
* extra slots, neither of which are used for ScriptedIndirectProxy. But we're
|
||||
* eventually moving towards eliminating one of those slots, and so we don't
|
||||
* want to add a dependency here.
|
||||
*/
|
||||
static const Class CallConstructHolder = {
|
||||
"CallConstructHolder",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
// This variable exists solely to provide a unique address for use as an identifier.
|
||||
const char ScriptedIndirectProxyHandler::family = 0;
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
// Scripted indirect proxies don't support extensibility changes.
|
||||
return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::isExtensible(JSContext* cx, HandleObject proxy,
|
||||
bool* extensible) const
|
||||
{
|
||||
// Scripted indirect proxies don't support extensibility changes.
|
||||
*extensible = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReturnedValueMustNotBePrimitive(JSContext* cx, HandleObject proxy, JSAtom* atom, const Value& v)
|
||||
{
|
||||
if (v.isPrimitive()) {
|
||||
JSAutoByteString bytes;
|
||||
if (AtomToPrintableString(cx, atom, &bytes)) {
|
||||
RootedValue val(cx, ObjectOrNullValue(proxy));
|
||||
ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
|
||||
JSDVG_SEARCH_STACK, val, nullptr, bytes.ptr());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
GetIndirectProxyHandlerObject(JSObject* proxy)
|
||||
{
|
||||
return proxy->as<ProxyObject>().private_().toObjectOrNull();
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
return GetFundamentalTrap(cx, handler, cx->names().getPropertyDescriptor, &fval) &&
|
||||
Trap1(cx, handler, fval, id, &value) &&
|
||||
((value.isUndefined() && IndicatePropertyNotFound(desc)) ||
|
||||
(ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
|
||||
ObjectToCompletePropertyDescriptor(cx, proxy, value, desc)));
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
return GetFundamentalTrap(cx, handler, cx->names().getOwnPropertyDescriptor, &fval) &&
|
||||
Trap1(cx, handler, fval, id, &value) &&
|
||||
((value.isUndefined() && IndicatePropertyNotFound(desc)) ||
|
||||
(ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
|
||||
ObjectToCompletePropertyDescriptor(cx, proxy, value, desc)));
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
return GetFundamentalTrap(cx, handler, cx->names().defineProperty, &fval) &&
|
||||
FromPropertyDescriptorToObject(cx, desc, &value) &&
|
||||
Trap2(cx, handler, fval, id, value, &value) &&
|
||||
result.succeed();
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
return GetFundamentalTrap(cx, handler, cx->names().getOwnPropertyNames, &fval) &&
|
||||
Trap(cx, handler, fval, 0, nullptr, &value) &&
|
||||
ArrayToIdVector(cx, value, props);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
if (!GetFundamentalTrap(cx, handler, cx->names().delete_, &fval))
|
||||
return false;
|
||||
if (!Trap1(cx, handler, fval, id, &value))
|
||||
return false;
|
||||
|
||||
if (ToBoolean(value))
|
||||
result.succeed();
|
||||
else
|
||||
result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::enumerate(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject objp) const
|
||||
{
|
||||
// The hook that is called "enumerate" in the spec, used to be "iterate"
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue value(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().iterate, &value))
|
||||
return false;
|
||||
if (!IsCallable(value))
|
||||
return BaseProxyHandler::enumerate(cx, proxy, objp);
|
||||
|
||||
RootedValue rval(cx);
|
||||
if (!Trap(cx, handler, value, 0, nullptr, &rval))
|
||||
return false;
|
||||
if (!ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, rval))
|
||||
return false;
|
||||
objp.set(&rval.toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().has, &fval))
|
||||
return false;
|
||||
if (!IsCallable(fval))
|
||||
return BaseProxyHandler::has(cx, proxy, id, bp);
|
||||
return Trap1(cx, handler, fval, id, &value) &&
|
||||
ValueToBool(value, bp);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue fval(cx), value(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().hasOwn, &fval))
|
||||
return false;
|
||||
if (!IsCallable(fval))
|
||||
return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
|
||||
return Trap1(cx, handler, fval, id, &value) &&
|
||||
ValueToBool(value, bp);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
|
||||
HandleId id, MutableHandleValue vp) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue idv(cx);
|
||||
if (!IdToStringOrSymbol(cx, id, &idv))
|
||||
return false;
|
||||
JS::AutoValueArray<2> argv(cx);
|
||||
argv[0].set(receiver);
|
||||
argv[1].set(idv);
|
||||
RootedValue fval(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))
|
||||
return false;
|
||||
if (!IsCallable(fval))
|
||||
return derivedGet(cx, proxy, receiver, id, vp);
|
||||
return Trap(cx, handler, fval, 2, argv.begin(), vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::derivedGet(JSContext* cx, HandleObject proxy, HandleValue receiver,
|
||||
HandleId id, MutableHandleValue vp) const
|
||||
{
|
||||
// This uses getPropertyDescriptor for backward compatibility reasons.
|
||||
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!getPropertyDescriptor(cx, proxy, id, &desc))
|
||||
return false;
|
||||
desc.assertCompleteIfFound();
|
||||
|
||||
if (!desc.object()) {
|
||||
vp.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (desc.isDataDescriptor()) {
|
||||
vp.set(desc.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(desc.isAccessorDescriptor());
|
||||
RootedObject getter(cx, desc.getterObject());
|
||||
|
||||
if (!getter) {
|
||||
vp.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
return InvokeGetter(cx, receiver, ObjectValue(*getter), vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue idv(cx);
|
||||
if (!IdToStringOrSymbol(cx, id, &idv))
|
||||
return false;
|
||||
JS::AutoValueArray<3> argv(cx);
|
||||
argv[0].set(receiver);
|
||||
argv[1].set(idv);
|
||||
argv[2].set(v);
|
||||
RootedValue fval(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
|
||||
return false;
|
||||
if (!IsCallable(fval))
|
||||
return derivedSet(cx, proxy, id, v, receiver, result);
|
||||
if (!Trap(cx, handler, fval, 3, argv.begin(), &idv))
|
||||
return false;
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
static bool
|
||||
CallSetter(JSContext* cx, HandleValue receiver, HandleId id, SetterOp op, unsigned attrs,
|
||||
HandleValue v, ObjectOpResult& result)
|
||||
{
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
RootedValue fval(cx, CastAsObjectJsval(op));
|
||||
if (!InvokeSetter(cx, receiver, fval, v))
|
||||
return false;
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
if (attrs & JSPROP_GETTER)
|
||||
return result.fail(JSMSG_GETTER_ONLY);
|
||||
|
||||
if (!receiver.isObject())
|
||||
return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
|
||||
RootedObject receiverObj(cx, &receiver.toObject());
|
||||
|
||||
if (!op)
|
||||
return result.succeed();
|
||||
|
||||
RootedValue valCopy(cx, v);
|
||||
return CallJSSetterOp(cx, op, receiverObj, id, &valCopy, result);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::derivedSet(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
HandleValue v, HandleValue receiver,
|
||||
ObjectOpResult& result) const
|
||||
{
|
||||
// Find an own or inherited property. The code here is strange for maximum
|
||||
// backward compatibility with earlier code written before ES6 and before
|
||||
// SetPropertyIgnoringNamedGetter.
|
||||
//
|
||||
// As of March 2015, testing/specialpowers/content/specialpowersAPI.js
|
||||
// depends on the call to getPropertyDescriptor below, because it does
|
||||
// support inherited setters but makes no attempt to provide a meaningful
|
||||
// prototype chain.
|
||||
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
|
||||
return false;
|
||||
bool descIsOwn = desc.object() != nullptr;
|
||||
if (!descIsOwn) {
|
||||
if (!getPropertyDescriptor(cx, proxy, id, &desc))
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(descIsOwn, desc.object());
|
||||
if (desc.object()) {
|
||||
MOZ_ASSERT(desc.getter() != JS_PropertyStub);
|
||||
MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub);
|
||||
|
||||
// Check for read-only properties.
|
||||
if (desc.isDataDescriptor() && !desc.writable())
|
||||
return result.fail(descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP);
|
||||
|
||||
if (desc.hasSetterObject() || desc.setter()) {
|
||||
if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), v, result))
|
||||
return false;
|
||||
if (!result)
|
||||
return true;
|
||||
if (!proxy->is<ProxyObject>() ||
|
||||
proxy->as<ProxyObject>().handler() != this ||
|
||||
desc.isShared())
|
||||
{
|
||||
return result.succeed();
|
||||
}
|
||||
}
|
||||
desc.value().set(v);
|
||||
|
||||
if (descIsOwn) {
|
||||
MOZ_ASSERT(desc.object() == proxy);
|
||||
return this->defineProperty(cx, proxy, id, desc, result);
|
||||
}
|
||||
} else {
|
||||
desc.setDataDescriptor(v, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
if (!receiver.isObject())
|
||||
return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
|
||||
RootedObject receiverObj(cx, &receiver.toObject());
|
||||
return DefineProperty(cx, receiverObj, id, desc, result);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const
|
||||
{
|
||||
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
|
||||
RootedValue value(cx);
|
||||
if (!GetDerivedTrap(cx, handler, cx->names().keys, &value))
|
||||
return false;
|
||||
if (!IsCallable(value))
|
||||
return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
|
||||
return Trap(cx, handler, value, 0, nullptr, &value) &&
|
||||
ArrayToIdVector(cx, value, props);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
|
||||
const CallArgs& args) const
|
||||
{
|
||||
return BaseProxyHandler::nativeCall(cx, test, impl, args);
|
||||
}
|
||||
|
||||
JSString*
|
||||
ScriptedIndirectProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
|
||||
if (!proxy->isCallable()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_INCOMPATIBLE_PROTO,
|
||||
js_Function_str, js_toString_str,
|
||||
"object");
|
||||
return nullptr;
|
||||
}
|
||||
RootedObject obj(cx, &proxy->as<ProxyObject>().extra(0).toObject().as<NativeObject>().getReservedSlot(0).toObject());
|
||||
return fun_toStringHelper(cx, obj, indent);
|
||||
}
|
||||
|
||||
const ScriptedIndirectProxyHandler ScriptedIndirectProxyHandler::singleton;
|
||||
|
||||
bool
|
||||
CallableScriptedIndirectProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
MOZ_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
RootedValue call(cx, ccHolder->as<NativeObject>().getReservedSlot(0));
|
||||
MOZ_ASSERT(call.isObject() && call.toObject().isCallable());
|
||||
return Invoke(cx, args.thisv(), call, args.length(), args.array(), args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
CallableScriptedIndirectProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
MOZ_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
|
||||
RootedValue construct(cx, ccHolder->as<NativeObject>().getReservedSlot(1));
|
||||
|
||||
// We could enforce this at proxy creation time, but lipstick on a pig.
|
||||
// Plus, let's delay in-the-field bustage as long as possible.
|
||||
if (!IsConstructor(construct)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, construct, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstructArgs cargs(cx);
|
||||
if (!FillArgumentsFromArraylike(cx, cargs, args))
|
||||
return false;
|
||||
|
||||
RootedObject obj(cx);
|
||||
if (!Construct(cx, construct, cargs, args.newTarget(), &obj))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
const CallableScriptedIndirectProxyHandler CallableScriptedIndirectProxyHandler::singleton;
|
||||
|
||||
bool
|
||||
js::proxy_create(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedObject create(cx, &args.callee());
|
||||
if (!GlobalObject::warnOnceAboutProxyCreate(cx, create))
|
||||
return false;
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"create", "0", "s");
|
||||
return false;
|
||||
}
|
||||
JSObject* handler = NonNullObject(cx, args[0]);
|
||||
if (!handler)
|
||||
return false;
|
||||
JSObject* proto;
|
||||
if (args.get(1).isObject()) {
|
||||
proto = &args[1].toObject();
|
||||
} else {
|
||||
MOZ_ASSERT(IsFunctionObject(&args.callee()));
|
||||
proto = nullptr;
|
||||
}
|
||||
RootedValue priv(cx, ObjectValue(*handler));
|
||||
JSObject* proxy = NewProxyObject(cx, &ScriptedIndirectProxyHandler::singleton,
|
||||
priv, proto);
|
||||
if (!proxy)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*proxy);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::proxy_createFunction(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
RootedObject createFunction(cx, &args.callee());
|
||||
if (!GlobalObject::warnOnceAboutProxyCreate(cx, createFunction))
|
||||
return false;
|
||||
|
||||
if (args.length() < 2) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"createFunction", "1", "");
|
||||
return false;
|
||||
}
|
||||
RootedObject handler(cx, NonNullObject(cx, args[0]));
|
||||
if (!handler)
|
||||
return false;
|
||||
RootedObject proto(cx, args.callee().global().getOrCreateFunctionPrototype(cx));
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
RootedObject call(cx, ValueToCallable(cx, args[1], args.length() - 2));
|
||||
if (!call)
|
||||
return false;
|
||||
RootedObject construct(cx, nullptr);
|
||||
if (args.length() > 2) {
|
||||
construct = ValueToCallable(cx, args[2], args.length() - 3);
|
||||
if (!construct)
|
||||
return false;
|
||||
} else {
|
||||
construct = call;
|
||||
}
|
||||
|
||||
// Stash the call and construct traps on a holder object that we can stick
|
||||
// in a slot on the proxy.
|
||||
RootedObject ccHolder(cx, JS_NewObjectWithGivenProto(cx, Jsvalify(&CallConstructHolder),
|
||||
nullptr));
|
||||
if (!ccHolder)
|
||||
return false;
|
||||
ccHolder->as<NativeObject>().setReservedSlot(0, ObjectValue(*call));
|
||||
ccHolder->as<NativeObject>().setReservedSlot(1, ObjectValue(*construct));
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*handler));
|
||||
JSObject* proxy =
|
||||
NewProxyObject(cx, &CallableScriptedIndirectProxyHandler::singleton,
|
||||
priv, proto);
|
||||
if (!proxy)
|
||||
return false;
|
||||
proxy->as<ProxyObject>().setExtra(0, ObjectValue(*ccHolder));
|
||||
|
||||
args.rval().setObject(*proxy);
|
||||
return true;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef proxy_ScriptedIndirectProxyHandler_h
|
||||
#define proxy_ScriptedIndirectProxyHandler_h
|
||||
|
||||
#include "js/Proxy.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Derived class for all scripted indirect proxy handlers. */
|
||||
class ScriptedIndirectProxyHandler : public BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
MOZ_CONSTEXPR ScriptedIndirectProxyHandler()
|
||||
: BaseProxyHandler(&family)
|
||||
{ }
|
||||
|
||||
/* Standard internal methods. */
|
||||
virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const override;
|
||||
virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool enumerate(JSContext* cx, HandleObject proxy,
|
||||
MutableHandleObject objp) const override;
|
||||
virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
|
||||
ObjectOpResult& result) const override;
|
||||
virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
|
||||
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
|
||||
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
|
||||
MutableHandleValue vp) const override;
|
||||
virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result) const override;
|
||||
|
||||
/* SpiderMonkey extensions. */
|
||||
virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const override;
|
||||
virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
|
||||
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
|
||||
AutoIdVector& props) const override;
|
||||
virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
|
||||
const CallArgs& args) const override;
|
||||
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
|
||||
virtual bool isScripted() const override { return true; }
|
||||
|
||||
static const char family;
|
||||
static const ScriptedIndirectProxyHandler singleton;
|
||||
|
||||
private:
|
||||
bool derivedGet(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
|
||||
MutableHandleValue vp) const;
|
||||
bool derivedSet(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult& result) const;
|
||||
};
|
||||
|
||||
/* Derived class to handle Proxy.createFunction() */
|
||||
class CallableScriptedIndirectProxyHandler : public ScriptedIndirectProxyHandler
|
||||
{
|
||||
public:
|
||||
CallableScriptedIndirectProxyHandler() : ScriptedIndirectProxyHandler() { }
|
||||
virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
|
||||
virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
|
||||
|
||||
virtual bool isCallable(JSObject* obj) const override {
|
||||
return true;
|
||||
}
|
||||
virtual bool isConstructor(JSObject* obj) const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
static const CallableScriptedIndirectProxyHandler singleton;
|
||||
};
|
||||
|
||||
bool
|
||||
proxy_create(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
bool
|
||||
proxy_createFunction(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* proxy_ScriptedIndirectProxyHandler_h */
|
||||
@@ -9,14 +9,15 @@ print(BUGNUMBER + ": " + summary);
|
||||
|
||||
enableLastWarning();
|
||||
|
||||
eval(`({}).__proto__ = {};`);
|
||||
let line0 = new Error().lineNumber;
|
||||
assertEq("foo".contains("bar"), false);
|
||||
|
||||
var warning = getLastWarning();
|
||||
assertEq(warning !== null, true);
|
||||
assertEq(warning.name, "None");
|
||||
assertEq(warning.message.includes("mutating"), true);
|
||||
assertEq(warning.lineNumber, 1);
|
||||
assertEq(warning.columnNumber, 2);
|
||||
assertEq(warning.message.includes("deprecated"), true);
|
||||
assertEq(warning.lineNumber, line0 + 1);
|
||||
assertEq(warning.columnNumber, 10);
|
||||
|
||||
// Clear last warning.
|
||||
|
||||
|
||||
@@ -201,10 +201,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
||||
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
|
||||
|
||||
// Define any specified functions and properties, unless we're a dependent
|
||||
// standard class (in which case they live on the prototype).
|
||||
if (!StandardClassIsDependent(key)) {
|
||||
// standard class (in which case they live on the prototype), or we're
|
||||
// operating on the self-hosting global, in which case we don't want any
|
||||
// functions and properties on the builtins and their prototypes.
|
||||
if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
|
||||
if (const JSFunctionSpec* funs = clasp->spec.prototypeFunctions()) {
|
||||
if (!JS_DefineFunctions(cx, proto, funs, DontDefineLateProperties))
|
||||
if (!JS_DefineFunctions(cx, proto, funs))
|
||||
return false;
|
||||
}
|
||||
if (const JSPropertySpec* props = clasp->spec.prototypeProperties()) {
|
||||
@@ -212,7 +214,7 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
||||
return false;
|
||||
}
|
||||
if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions()) {
|
||||
if (!JS_DefineFunctions(cx, ctor, funs, DontDefineLateProperties))
|
||||
if (!JS_DefineFunctions(cx, ctor, funs))
|
||||
return false;
|
||||
}
|
||||
if (const JSPropertySpec* props = clasp->spec.constructorProperties()) {
|
||||
|
||||
@@ -135,9 +135,7 @@ class GlobalObject : public NativeObject
|
||||
|
||||
enum WarnOnceFlag : int32_t {
|
||||
WARN_WATCH_DEPRECATED = 1 << 0,
|
||||
WARN_PROTO_SETTING_SLOW = 1 << 1,
|
||||
WARN_STRING_CONTAINS_DEPRECATED = 1 << 2,
|
||||
WARN_PROXY_CREATE_DEPRECATED = 1 << 3,
|
||||
WARN_STRING_CONTAINS_DEPRECATED = 1 << 1,
|
||||
};
|
||||
|
||||
// Emit the specified warning if the given slot in |obj|'s global isn't
|
||||
@@ -700,24 +698,12 @@ class GlobalObject : public NativeObject
|
||||
return true;
|
||||
}
|
||||
|
||||
// Warn about use of the given __proto__ setter to attempt to mutate an
|
||||
// object's [[Prototype]], if no prior warning was given.
|
||||
static bool warnOnceAboutPrototypeMutation(JSContext* cx, HandleObject protoSetter) {
|
||||
return warnOnceAbout(cx, protoSetter, WARN_PROTO_SETTING_SLOW, JSMSG_PROTO_SETTING_SLOW);
|
||||
}
|
||||
|
||||
// Warn about use of the deprecated String.prototype.contains method
|
||||
static bool warnOnceAboutStringContains(JSContext* cx, HandleObject strContains) {
|
||||
return warnOnceAbout(cx, strContains, WARN_STRING_CONTAINS_DEPRECATED,
|
||||
JSMSG_DEPRECATED_STRING_CONTAINS);
|
||||
}
|
||||
|
||||
// Warn about uses of Proxy.create and Proxy.createFunction
|
||||
static bool warnOnceAboutProxyCreate(JSContext* cx, HandleObject create) {
|
||||
return warnOnceAbout(cx, create, WARN_PROXY_CREATE_DEPRECATED,
|
||||
JSMSG_DEPRECATED_PROXY_CREATE);
|
||||
}
|
||||
|
||||
static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
|
||||
MutableHandleObject eval);
|
||||
|
||||
|
||||
+1
-1
@@ -1196,7 +1196,7 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
/* Client opaque pointers */
|
||||
void* data;
|
||||
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
|
||||
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
|
||||
js::wasm::MachExceptionHandler wasmMachExceptionHandler;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -417,11 +417,9 @@ AutoStopwatch::getCPU() const
|
||||
|
||||
cpuid_t result(proc.Group, proc.Number);
|
||||
return result;
|
||||
#elif defined(XP_LINUX)
|
||||
return sched_getcpu();
|
||||
#else
|
||||
return {};
|
||||
#endif // defined(XP_WIN) || defined(XP_LINUX)
|
||||
#endif // defined(XP_WIN)
|
||||
}
|
||||
|
||||
bool inline
|
||||
@@ -429,8 +427,6 @@ AutoStopwatch::isSameCPU(const cpuid_t& a, const cpuid_t& b) const
|
||||
{
|
||||
#if defined(XP_WIN) && WINVER >= _WIN32_WINNT_VISTA
|
||||
return a.group_ == b.group_ && a.number_ == b.number_;
|
||||
#elif defined(XP_LINUX)
|
||||
return a == b;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@@ -314,11 +314,9 @@ struct cpuid_t {
|
||||
number_(0)
|
||||
{ }
|
||||
};
|
||||
#elif defined(__linux__)
|
||||
typedef int cpuid_t;
|
||||
#else
|
||||
typedef struct {} cpuid_t;
|
||||
#endif // defined(WINVER >= 0x0600) || defined(__linux__)
|
||||
#endif // defined(WINVER >= 0x0600)
|
||||
|
||||
/**
|
||||
* RAII class to start/stop measuring performance when
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1021258
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1021258</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for proto mutation warnings. **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var gLoads = 0;
|
||||
function loaded() {
|
||||
switch (++gLoads) {
|
||||
case 1:
|
||||
info("First load");
|
||||
SimpleTest.monitorConsole(function() { window[0].location.reload(true); },
|
||||
[ { message: /mutating/ } ], /* forbidUnexpectedMessages = */ true);
|
||||
window[0].eval('var foo = {}; Object.setPrototypeOf(foo, {});' +
|
||||
'var bar = {}; Object.getPrototypeOf(bar, {});');
|
||||
SimpleTest.endMonitorConsole();
|
||||
break;
|
||||
case 2:
|
||||
info("Second load");
|
||||
SimpleTest.monitorConsole(SimpleTest.finish.bind(SimpleTest),
|
||||
[ { message: /mutating/ } ], /* forbidUnexpectedMessages = */ true);
|
||||
window[0].eval('var foo = {}; foo.__proto__ = {};' +
|
||||
'var bar = {}; bar.__proto__ = {};');
|
||||
SimpleTest.endMonitorConsole();
|
||||
break;
|
||||
case 3:
|
||||
ok(false, "Shouldn't have 3 loads!");
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1021258">Mozilla Bug 1021258</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<iframe id="ifr" src="file_empty.html" onload="loaded();"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2817,7 +2817,9 @@ nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer,
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()->GetCurrentSize();
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const LayoutDevicePoint p = mImageLayerDestRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
@@ -3438,12 +3440,16 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
// are the event targets for any regions viewport frames may cover.
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pointerEvents = aFrame->StyleVisibility()->GetEffectivePointerEvents(aFrame);
|
||||
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
|
||||
return;
|
||||
}
|
||||
if (!aFrame->StyleVisibility()->IsVisible()) {
|
||||
return;
|
||||
bool simpleRegions = aFrame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
||||
if (!simpleRegions) {
|
||||
if (!aFrame->StyleVisibility()->IsVisible()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// XXX handle other pointerEvents values for SVG
|
||||
|
||||
@@ -3462,15 +3468,23 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
borderBox += aBuilder->ToReferenceFrame(aFrame);
|
||||
|
||||
bool borderBoxHasRoundedCorners = false;
|
||||
if (!simpleRegions) {
|
||||
if (nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius)) {
|
||||
borderBoxHasRoundedCorners = true;
|
||||
} else {
|
||||
aFrame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
||||
}
|
||||
}
|
||||
|
||||
const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
|
||||
bool borderBoxHasRoundedCorners =
|
||||
nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius);
|
||||
if (clip) {
|
||||
borderBox = clip->ApplyNonRoundedIntersection(borderBox);
|
||||
if (clip->GetRoundedRectCount() > 0) {
|
||||
borderBoxHasRoundedCorners = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (borderBoxHasRoundedCorners ||
|
||||
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
|
||||
|
||||
@@ -1411,40 +1411,6 @@ public:
|
||||
static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
|
||||
const nsStyleCoord& aCoord);
|
||||
|
||||
/*
|
||||
* Convert nsStyleCoord to nscoord when percentages depend on the
|
||||
* containing block width, and enumerated values are for width,
|
||||
* min-width, or max-width. Returns the content-box width value based
|
||||
* on aContentEdgeToBoxSizing and aBoxSizingToMarginEdge (which are
|
||||
* also used for the enumerated values for width. This function does
|
||||
* not handle 'auto'. It ensures that the result is nonnegative.
|
||||
*
|
||||
* @param aRenderingContext Rendering context for font measurement/metrics.
|
||||
* @param aFrame Frame whose (min-/max-/)width is being computed.
|
||||
* @param aContainingBlockWidth Width of aFrame's containing block.
|
||||
* @param aContentEdgeToBoxSizing The sum of any left/right padding and
|
||||
* border that goes inside the rect chosen by box-sizing.
|
||||
* @param aBoxSizingToMarginEdge The sum of any left/right padding, border,
|
||||
* and margin that goes outside the rect chosen by box-sizing.
|
||||
* @param aCoord The width value to compute.
|
||||
*/
|
||||
// XXX to be removed
|
||||
static nscoord ComputeWidthValue(
|
||||
nsRenderingContext* aRenderingContext,
|
||||
nsIFrame* aFrame,
|
||||
nscoord aContainingBlockWidth,
|
||||
nscoord aContentEdgeToBoxSizing,
|
||||
nscoord aBoxSizingToMarginEdge,
|
||||
const nsStyleCoord& aCoord)
|
||||
{
|
||||
return ComputeISizeValue(aRenderingContext,
|
||||
aFrame,
|
||||
aContainingBlockWidth,
|
||||
aContentEdgeToBoxSizing,
|
||||
aBoxSizingToMarginEdge,
|
||||
aCoord);
|
||||
}
|
||||
|
||||
static nscoord ComputeISizeValue(
|
||||
nsRenderingContext* aRenderingContext,
|
||||
nsIFrame* aFrame,
|
||||
@@ -1453,35 +1419,10 @@ public:
|
||||
nscoord aBoxSizingToMarginEdge,
|
||||
const nsStyleCoord& aCoord);
|
||||
|
||||
/*
|
||||
* Convert nsStyleCoord to nscoord when percentages depend on the
|
||||
* containing block height.
|
||||
*/
|
||||
// XXX to be removed
|
||||
static nscoord ComputeHeightDependentValue(
|
||||
nscoord aContainingBlockHeight,
|
||||
const nsStyleCoord& aCoord)
|
||||
{
|
||||
return ComputeBSizeDependentValue(aContainingBlockHeight, aCoord);
|
||||
}
|
||||
|
||||
static nscoord ComputeBSizeDependentValue(
|
||||
nscoord aContainingBlockBSize,
|
||||
const nsStyleCoord& aCoord);
|
||||
|
||||
/*
|
||||
* Likewise, but for 'height', 'min-height', or 'max-height'.
|
||||
*/
|
||||
// XXX to be removed
|
||||
static nscoord ComputeHeightValue(nscoord aContainingBlockHeight,
|
||||
nscoord aContentEdgeToBoxSizingBoxEdge,
|
||||
const nsStyleCoord& aCoord)
|
||||
{
|
||||
return ComputeBSizeValue(aContainingBlockHeight,
|
||||
aContentEdgeToBoxSizingBoxEdge,
|
||||
aCoord);
|
||||
}
|
||||
|
||||
static nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
|
||||
nscoord aContentEdgeToBoxSizingBoxEdge,
|
||||
const nsStyleCoord& aCoord)
|
||||
|
||||
@@ -1203,9 +1203,14 @@ nsPresContext::SetShell(nsIPresShell* aShell)
|
||||
}
|
||||
|
||||
if (IsRoot()) {
|
||||
nsRootPresContext* thisRoot = static_cast<nsRootPresContext*>(this);
|
||||
|
||||
// Have to cancel our plugin geometry timer, because the
|
||||
// callback for that depends on a non-null presshell.
|
||||
static_cast<nsRootPresContext*>(this)->CancelApplyPluginGeometryTimer();
|
||||
thisRoot->CancelApplyPluginGeometryTimer();
|
||||
|
||||
// The did-paint timer also depends on a non-null pres shell.
|
||||
thisRoot->CancelDidPaintTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
, mScaleToResolution(false)
|
||||
, mDisabledSet(false)
|
||||
, mDisabled(false)
|
||||
, mDroppedDown(false)
|
||||
{}
|
||||
|
||||
void SetScrollState(const nsPoint& aState)
|
||||
@@ -89,6 +90,16 @@ public:
|
||||
mContentData = aProperty;
|
||||
}
|
||||
|
||||
void SetDroppedDown(bool aDroppedDown)
|
||||
{
|
||||
mDroppedDown = aDroppedDown;
|
||||
}
|
||||
|
||||
bool GetDroppedDown() const
|
||||
{
|
||||
return mDroppedDown;
|
||||
}
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mContentData;
|
||||
@@ -97,6 +108,7 @@ protected:
|
||||
bool mScaleToResolution;
|
||||
bool mDisabledSet;
|
||||
bool mDisabled;
|
||||
bool mDroppedDown;
|
||||
};
|
||||
|
||||
#endif /* nsPresState_h_ */
|
||||
|
||||
@@ -912,6 +912,8 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
|
||||
PresContext()->SetBidiEnabled();
|
||||
}
|
||||
|
||||
RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
||||
}
|
||||
|
||||
// MSVC fails with link error "one or more multiply defined symbols found",
|
||||
|
||||
@@ -180,6 +180,12 @@ FRAME_STATE_BIT(Generic, 33, NS_FRAME_DRAWING_AS_PAINTSERVER)
|
||||
// situation (possibly the frame itself).
|
||||
FRAME_STATE_BIT(Generic, 34, NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)
|
||||
|
||||
// A flag that tells us we can take the common path with respect to style
|
||||
// properties for this frame when building event regions. This flag is cleared
|
||||
// when any styles are changed and then we recompute it on the next build
|
||||
// of the event regions.
|
||||
FRAME_STATE_BIT(Generic, 35, NS_FRAME_SIMPLE_EVENT_REGIONS)
|
||||
|
||||
// Frame is a display root and the retained layer tree needs to be updated
|
||||
// at the next paint via display list construction.
|
||||
// Only meaningful for display roots, so we don't really need a global state
|
||||
|
||||
@@ -1710,7 +1710,9 @@ nsDisplayImage::ConfigureLayer(ImageLayer* aLayer,
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()->GetCurrentSize();
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const LayoutDevicePoint p = destRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
|
||||
@@ -17257,27 +17257,6 @@ nsCSSParser::Shutdown()
|
||||
|
||||
// Wrapper methods
|
||||
|
||||
nsresult
|
||||
nsCSSParser::SetStyleSheet(CSSStyleSheet* aSheet)
|
||||
{
|
||||
return static_cast<CSSParserImpl*>(mImpl)->
|
||||
SetStyleSheet(aSheet);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSParser::SetQuirkMode(bool aQuirkMode)
|
||||
{
|
||||
return static_cast<CSSParserImpl*>(mImpl)->
|
||||
SetQuirkMode(aQuirkMode);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSParser::SetChildLoader(mozilla::css::Loader* aChildLoader)
|
||||
{
|
||||
return static_cast<CSSParserImpl*>(mImpl)->
|
||||
SetChildLoader(aChildLoader);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSParser::ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aSheetURI,
|
||||
|
||||
@@ -53,29 +53,19 @@ private:
|
||||
nsCSSParser& operator=(nsCSSParser const&) = delete;
|
||||
|
||||
public:
|
||||
// Set a style sheet for the parser to fill in. The style sheet must
|
||||
// implement the CSSStyleSheet interface. Null can be passed in to clear
|
||||
// out an existing stylesheet reference.
|
||||
nsresult SetStyleSheet(mozilla::CSSStyleSheet* aSheet);
|
||||
|
||||
// Set whether or not to emulate Nav quirks
|
||||
nsresult SetQuirkMode(bool aQuirkMode);
|
||||
|
||||
// Set loader to use for child sheets
|
||||
nsresult SetChildLoader(mozilla::css::Loader* aChildLoader);
|
||||
|
||||
/**
|
||||
* Parse aInput into the stylesheet that was previously set by calling
|
||||
* SetStyleSheet. Calling this method without calling SetStyleSheet first is
|
||||
* an error.
|
||||
* Parse aInput into the stylesheet that was previously passed to the
|
||||
* constructor. Calling this method on an nsCSSParser that had nullptr
|
||||
* passed in as the style sheet is an error.
|
||||
*
|
||||
* @param aInput the data to parse
|
||||
* @param aSheetURL the URI to use as the sheet URI (for error reporting).
|
||||
* This must match the URI of the sheet passed to
|
||||
* SetStyleSheet.
|
||||
* the constructor.
|
||||
* @param aBaseURI the URI to use for relative URI resolution
|
||||
* @param aSheetPrincipal the principal of the stylesheet. This must match
|
||||
* the principal of the sheet passed to SetStyleSheet.
|
||||
* the principal of the sheet passed to the
|
||||
* constructor.
|
||||
* @param aLineNumber the line number of the first line of the sheet.
|
||||
* @param aParsingMode see SheetParsingMode in css/Loader.h
|
||||
* @param aReusableSheets style sheets that can be reused by an @import.
|
||||
|
||||
@@ -481,7 +481,9 @@ nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer,
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()->GetCurrentSize();
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const LayoutDevicePoint p = destRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
|
||||
@@ -41,10 +41,7 @@ DECLARE_ALIGNED(32, static const uint8_t, filt4_global_avx2[32]) = {
|
||||
|
||||
#if defined(__clang__)
|
||||
# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ <= 3) || \
|
||||
(defined(__APPLE__) && \
|
||||
(__clang_major__ == 4 && __clang_minor__ >= 0 && \
|
||||
__clang_minor__ <= 2) || \
|
||||
(__clang_major__ == 5 && __clang_minor__ == 0))
|
||||
(defined(__APPLE__) && __clang_major__ == 5 && __clang_minor__ == 0)
|
||||
# define MM256_BROADCASTSI128_SI256(x) \
|
||||
_mm_broadcastsi128_si256((__m128i const *)&(x))
|
||||
# else // clang > 3.3, and not 5.0 on macosx.
|
||||
|
||||
@@ -185,6 +185,7 @@ nsHttpConnectionMgr::Shutdown()
|
||||
|
||||
// wait for shutdown event to complete
|
||||
while (!shutdownWrapper->mBool) {
|
||||
fprintf(stderr, "nsHttpConnectionMgr::Shutdown() ProcessNextEvent\n");
|
||||
NS_ProcessNextEvent(NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ interface nsICertVerificationListener;
|
||||
|
||||
/**
|
||||
* This represents a X.509 certificate.
|
||||
*
|
||||
* NOTE: Service workers persist x.509 certs in object form on disk. If you
|
||||
* change this uuid you probably need a hack in nsBinaryInputStream to
|
||||
* read the old uuid. If you change the format of the object
|
||||
* serialization then more complex changes will be needed.
|
||||
*/
|
||||
[scriptable, uuid(bdc3979a-5422-4cd5-8589-696b6e96ea83)]
|
||||
interface nsIX509Cert : nsISupports {
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
|
||||
// These tests verify that we can still deserialize old binary strings
|
||||
// generated for security info. This is necessary because service workers
|
||||
// stores these strings on disk.
|
||||
//
|
||||
// If you make a change and start breaking these tests, you will need to
|
||||
// add a compat fix for loading the old versions. For things that affect
|
||||
// the UUID, but do not break the rest of the format you can simply add
|
||||
// another hack condition in nsBinaryInputStream::ReadObject(). If you
|
||||
// change the overall format of the serialization then we will need more
|
||||
// complex handling in the security info concrete classes.
|
||||
//
|
||||
// We would like to move away from this binary compatibility requirement
|
||||
// in service workers. See bug 1248628.
|
||||
|
||||
TEST(DeserializeCert, gecko33)
|
||||
{
|
||||
// Gecko 33+ vintage Security info serialized with UUIDs:
|
||||
// - nsISupports 00000000-0000-0000-c000-000000000046
|
||||
// - nsISSLStatus fa9ba95b-ca3b-498a-b889-7c79cf28fee8
|
||||
// - nsIX509Cert f8ed8364-ced9-4c6e-86ba-48af53c393e6
|
||||
nsCString base64Serialization(
|
||||
"FnhllAKWRHGAlo+ESXykKAAAAAAAAAAAwAAAAAAAAEaphjojH6pBabDSgSnsfLHeAAQAAgAAAAAAAAAAAAAAAAAAAAA"
|
||||
"B4vFIJp5wRkeyPxAQ9RJGKPqbqVvKO0mKuIl8ec8o/uhmCjImkVxP+7sgiYWmMt8F+O2DZM7ZTG6GukivU8OT5gAAAAIAAAWpMII"
|
||||
"FpTCCBI2gAwIBAgIQD4svsaKEC+QtqtsU2TF8ITANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUN"
|
||||
"lcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFN"
|
||||
"lcnZlciBDQTAeFw0xNTAyMjMwMDAwMDBaFw0xNjAzMDIxMjAwMDBaMGoxCzAJBgNVBAYTAlVTMRYwFAYDVQQHEw1TYW4gRnJhbmN"
|
||||
"pc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRUwEwYDVQQKEwxGYXN0bHksIEluYy4xFzAVBgNVBAMTDnd3dy5naXRodWIuY29tMII"
|
||||
"BIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+9WUCgrgUNwP/JC3cUefLAXeDpq8Ko/U8p8IRvny0Ri0I6Uq0t+RP/nF0LJ"
|
||||
"Avda8QHYujdgeDTePepBX7+OiwBFhA0YO+rM3C2Z8IRaN/i9eLln+Yyc68+1z+E10s1EXdZrtDGvN6MHqygGsdfkXKfBLUJ1BZEh"
|
||||
"s9sBnfcjq3kh5gZdBArdG9l5NpdmQhtceaFGsPiWuJxGxRzS4i95veUHWkhMpEYDEEBdcDGxqArvQCvzSlngdttQCfx8OUkBTb3B"
|
||||
"A2okpTwwJfqPsxVetA6qR7UNc+fVb6KHwvm0bzi2rQ3xw3D/syRHwdMkpoVDQPCk43H9WufgfBKRen87dFwIDAQABo4ICPzCCAjs"
|
||||
"wHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFGS/RLNGCZvPWh1xSaIEcouINIQjMHsGA1UdEQR0MHK"
|
||||
"CDnd3dy5naXRodWIuY29tggpnaXRodWIuY29tggwqLmdpdGh1Yi5jb22CCyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHV"
|
||||
"idXNlcmNvbnRlbnQuY29tghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwM"
|
||||
"BBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3J"
|
||||
"sMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb"
|
||||
"9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQc"
|
||||
"wAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUN"
|
||||
"lcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAc4dbVmuKvyI7"
|
||||
"KZ4Txk+ZqcAYToJGKUIVaPL94e5SZGweUisjaCbplAOihnf6Mxt8n6vnuH2IsCaz2NRHqhdcosjT3CwAiJpJNkXPKWVL/txgdSTV"
|
||||
"2cqB1GG4esFOalvI52dzn+J4fTIYZvNF+AtGyHSLm2XRXYZCw455laUKf6Sk9RDShDgUvzhOKL4GXfTwKXv12MyMknJybH8UCpjC"
|
||||
"HZmFBVHMcUN/87HsQo20PdOekeEvkjrrMIxW+gxw22Yb67yF/qKgwrWr+43bLN709iyw+LWiU7sQcHL2xk9SYiWQDj2tYz2soObV"
|
||||
"QYTJm0VUZMEVFhtALq46cx92Zu4vFwC8AAwAAAAABAQAA");
|
||||
|
||||
nsCOMPtr<nsISupports> cert;
|
||||
nsresult rv = NS_DeserializeObject(base64Serialization, getter_AddRefs(cert));
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_TRUE(cert);
|
||||
}
|
||||
|
||||
TEST(DeserializeCert, gecko46)
|
||||
{
|
||||
// Gecko 46+ vintage Security info serialized with UUIDs:
|
||||
// - nsISupports 00000000-0000-0000-c000-000000000046
|
||||
// - nsISSLStatus fa9ba95b-ca3b-498a-b889-7c79cf28fee8
|
||||
// - nsIX509Cert bdc3979a-5422-4cd5-8589-696b6e96ea83
|
||||
nsCString base64Serialization(
|
||||
"FnhllAKWRHGAlo+ESXykKAAAAAAAAAAAwAAAAAAAAEaphjojH6pBabDSgSnsfLHeAAQAAgAAAAAAAAAAAAAAAAAAAAA"
|
||||
"B4vFIJp5wRkeyPxAQ9RJGKPqbqVvKO0mKuIl8ec8o/uhmCjImkVxP+7sgiYWmMt8FvcOXmlQiTNWFiWlrbpbqgwAAAAIAAAWzMII"
|
||||
"FrzCCBJegAwIBAgIQB3pdwzYjAfmJ/lT3+G8+ZDANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUN"
|
||||
"lcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFN"
|
||||
"lcnZlciBDQTAeFw0xNjAxMjAwMDAwMDBaFw0xNzA0MDYxMjAwMDBaMGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybml"
|
||||
"hMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxGYXN0bHksIEluYy4xFzAVBgNVBAMTDnd3dy5naXRodWIuY29tMII"
|
||||
"BIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+9WUCgrgUNwP/JC3cUefLAXeDpq8Ko/U8p8IRvny0Ri0I6Uq0t+RP/nF0LJ"
|
||||
"Avda8QHYujdgeDTePepBX7+OiwBFhA0YO+rM3C2Z8IRaN/i9eLln+Yyc68+1z+E10s1EXdZrtDGvN6MHqygGsdfkXKfBLUJ1BZEh"
|
||||
"s9sBnfcjq3kh5gZdBArdG9l5NpdmQhtceaFGsPiWuJxGxRzS4i95veUHWkhMpEYDEEBdcDGxqArvQCvzSlngdttQCfx8OUkBTb3B"
|
||||
"A2okpTwwJfqPsxVetA6qR7UNc+fVb6KHwvm0bzi2rQ3xw3D/syRHwdMkpoVDQPCk43H9WufgfBKRen87dFwIDAQABo4ICSTCCAkU"
|
||||
"wHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFGS/RLNGCZvPWh1xSaIEcouINIQjMHsGA1UdEQR0MHK"
|
||||
"CDnd3dy5naXRodWIuY29tggwqLmdpdGh1Yi5jb22CCmdpdGh1Yi5jb22CCyouZ2l0aHViLmlvgglnaXRodWIuaW+CFyouZ2l0aHV"
|
||||
"idXNlcmNvbnRlbnQuY29tghVnaXRodWJ1c2VyY29udGVudC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwM"
|
||||
"BBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3J"
|
||||
"sMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb"
|
||||
"9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHU"
|
||||
"wJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQ"
|
||||
"uY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQE"
|
||||
"ATxbRdPg+o49+96/P+rbdp4ie+CGtfCgUubT/Z9C54k+BfQO0nbxVgCSM5WZQuLgo2Q+0lcxisod8zxZeU0j5wviQINwOln/iN89"
|
||||
"Bx3VmDRynTe4CqhsAwOoO1ERmCAmsAJBwY/rNr4mK22p8erBrqMW0nYXYU5NFynI+pNTjojhKD4II8PNV8G2yMWwYOb/u4+WPzUA"
|
||||
"HC9DpZdrWTEH/W69Cr/KxRqGsWPwpgMv2Wqav8jaT35JxqTXjOlhQqzo6fNn3eYOeCf4PkCxZKwckWjy10qDaRbjhwAMHAGj2TPr"
|
||||
"idlvOj/7QyyX5m8up/1US8z1fRW4yoCSOt6V2bwuH6cAvAAMAAAAAAQEAAA==");
|
||||
|
||||
nsCOMPtr<nsISupports> cert;
|
||||
nsresult rv = NS_DeserializeObject(base64Serialization, getter_AddRefs(cert));
|
||||
ASSERT_EQ(NS_OK, rv);
|
||||
ASSERT_TRUE(cert);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
SOURCES += [
|
||||
'DataStorageTest.cpp',
|
||||
'DeserializeCertTest.cpp',
|
||||
'OCSPCacheTest.cpp',
|
||||
'TLSIntoleranceTest.cpp',
|
||||
]
|
||||
|
||||
@@ -12,53 +12,22 @@ const { Cc, Ci } = require('chrome');
|
||||
const { get, set, exists } = Cc['@mozilla.org/process/environment;1'].
|
||||
getService(Ci.nsIEnvironment);
|
||||
|
||||
exports.env = Proxy.create({
|
||||
// XPCOM does not provides a way to enumerate environment variables, so we
|
||||
// just don't support enumeration.
|
||||
getPropertyNames: () => [],
|
||||
getOwnPropertyNames: () => [],
|
||||
enumerate: () => [],
|
||||
keys: () => [],
|
||||
// We do not support freezing, cause it would make it impossible to set new
|
||||
// environment variables.
|
||||
fix: () => undefined,
|
||||
// We present all environment variables as own properties of this object,
|
||||
// so we just delegate this call to `getOwnPropertyDescriptor`.
|
||||
getPropertyDescriptor: function(name) {
|
||||
return this.getOwnPropertyDescriptor(name);
|
||||
},
|
||||
// If environment variable with this name is defined, we generate proprety
|
||||
// descriptor for it, otherwise fall back to `undefined` so that for consumer
|
||||
// this property does not exists.
|
||||
getOwnPropertyDescriptor: function(name) {
|
||||
return !exists(name) ? undefined : {
|
||||
value: get(name),
|
||||
enumerable: false, // Non-enumerable as we don't support enumeration.
|
||||
configurable: true, // Configurable as it may be deleted.
|
||||
writable: true // Writable as we do support set.
|
||||
}
|
||||
},
|
||||
|
||||
// New environment variables can be defined just by defining properties
|
||||
// on this object.
|
||||
defineProperty: (name, { value }) => set(name, value),
|
||||
delete: function(name) {
|
||||
set(name, null);
|
||||
exports.env = new Proxy({}, {
|
||||
deleteProperty(target, property) {
|
||||
set(property, null);
|
||||
return true;
|
||||
},
|
||||
|
||||
// We present all properties as own, there for we just delegate to `hasOwn`.
|
||||
has: function(name) {
|
||||
return this.hasOwn(name);
|
||||
get(target, property, receiver) {
|
||||
return get(property) || undefined;
|
||||
},
|
||||
// We do support checks for existence of an environment variable, via `in`
|
||||
// operator on this object.
|
||||
hasOwn: name => exists(name),
|
||||
|
||||
// On property get / set we do read / write appropriate environment variables,
|
||||
// please note though, that variables with names of standard object properties
|
||||
// intentionally (so that this behaves as normal object) can not be
|
||||
// read / set.
|
||||
get: (proxy, name) => Object.prototype[name] || get(name) || undefined,
|
||||
set: (proxy, name, value) => Object.prototype[name] || set(name, value)
|
||||
has(target, property) {
|
||||
return exists(property);
|
||||
},
|
||||
|
||||
set(target, property, value, receiver) {
|
||||
set(property, value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -194,12 +194,16 @@ PromiseSet.prototype = {
|
||||
* console. We therefore use dump() rather than Cu.reportError().
|
||||
*/
|
||||
function log(msg, prefix = "", error = null) {
|
||||
dump(prefix + msg + "\n");
|
||||
if (error) {
|
||||
dump(prefix + error + "\n");
|
||||
if (typeof error == "object" && "stack" in error) {
|
||||
dump(prefix + error.stack + "\n");
|
||||
try {
|
||||
dump(prefix + msg + "\n");
|
||||
if (error) {
|
||||
dump(prefix + error + "\n");
|
||||
if (typeof error == "object" && "stack" in error) {
|
||||
dump(prefix + error.stack + "\n");
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
dump("INTERNAL ERROR in AsyncShutdown: cannot log message.\n");
|
||||
}
|
||||
}
|
||||
const PREF_DEBUG_LOG = "toolkit.asyncshutdown.log";
|
||||
@@ -305,35 +309,43 @@ function looseTimer(delay) {
|
||||
* @return object
|
||||
*/
|
||||
function getOrigin(topFrame, filename = null, lineNumber = null, stack = null) {
|
||||
// Determine the filename and line number of the caller.
|
||||
let frame = topFrame;
|
||||
try {
|
||||
// Determine the filename and line number of the caller.
|
||||
let frame = topFrame;
|
||||
|
||||
for (; frame && frame.filename == topFrame.filename; frame = frame.caller) {
|
||||
// Climb up the stack
|
||||
}
|
||||
|
||||
if (filename == null) {
|
||||
filename = frame ? frame.filename : "?";
|
||||
}
|
||||
if (lineNumber == null) {
|
||||
lineNumber = frame ? frame.lineNumber : 0;
|
||||
}
|
||||
if (stack == null) {
|
||||
// Now build the rest of the stack as a string, using Task.jsm's rewriting
|
||||
// to ensure that we do not lose information at each call to `Task.spawn`.
|
||||
let frames = [];
|
||||
while (frame != null) {
|
||||
frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
|
||||
frame = frame.caller;
|
||||
for (; frame && frame.filename == topFrame.filename; frame = frame.caller) {
|
||||
// Climb up the stack
|
||||
}
|
||||
stack = Task.Debugging.generateReadableStack(frames.join("\n")).split("\n");
|
||||
}
|
||||
|
||||
return {
|
||||
filename: filename,
|
||||
lineNumber: lineNumber,
|
||||
stack: stack,
|
||||
};
|
||||
if (filename == null) {
|
||||
filename = frame ? frame.filename : "?";
|
||||
}
|
||||
if (lineNumber == null) {
|
||||
lineNumber = frame ? frame.lineNumber : 0;
|
||||
}
|
||||
if (stack == null) {
|
||||
// Now build the rest of the stack as a string, using Task.jsm's rewriting
|
||||
// to ensure that we do not lose information at each call to `Task.spawn`.
|
||||
let frames = [];
|
||||
while (frame != null) {
|
||||
frames.push(frame.filename + ":" + frame.name + ":" + frame.lineNumber);
|
||||
frame = frame.caller;
|
||||
}
|
||||
stack = Task.Debugging.generateReadableStack(frames.join("\n")).split("\n");
|
||||
}
|
||||
|
||||
return {
|
||||
filename: filename,
|
||||
lineNumber: lineNumber,
|
||||
stack: stack,
|
||||
};
|
||||
} catch (ex) {
|
||||
return {
|
||||
filename: "<internal error: could not get origin>",
|
||||
lineNumber: -1,
|
||||
stack: "<internal error: could not get origin>",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["AsyncShutdown"];
|
||||
@@ -512,16 +524,26 @@ Spinner.prototype = {
|
||||
// nsIObserver.observe
|
||||
observe: function() {
|
||||
let topic = this._topic;
|
||||
debug(`Starting phase ${ topic }`);
|
||||
let barrier = this._barrier;
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
let satisfied = false; // |true| once we have satisfied all conditions
|
||||
let promise = this._barrier.wait({
|
||||
warnAfterMS: DELAY_WARNING_MS,
|
||||
crashAfterMS: DELAY_CRASH_MS
|
||||
});
|
||||
let promise;
|
||||
try {
|
||||
promise = this._barrier.wait({
|
||||
warnAfterMS: DELAY_WARNING_MS,
|
||||
crashAfterMS: DELAY_CRASH_MS
|
||||
}).catch(
|
||||
// Additional precaution to be entirely sure that we cannot reject.
|
||||
);
|
||||
} catch (ex) {
|
||||
debug("Error waiting for notification");
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// Now, spin the event loop
|
||||
debug("Spinning the event loop");
|
||||
promise.then(() => satisfied = true); // This promise cannot reject
|
||||
let thread = Services.tm.mainThread;
|
||||
while (!satisfied) {
|
||||
@@ -597,6 +619,9 @@ function Barrier(name) {
|
||||
/**
|
||||
* The name of the barrier.
|
||||
*/
|
||||
if (typeof name != "string") {
|
||||
throw new TypeError("The name of the barrier must be a string");
|
||||
}
|
||||
this._name = name;
|
||||
|
||||
/**
|
||||
@@ -665,13 +690,16 @@ function Barrier(name) {
|
||||
throw new TypeError("Expected an object as third argument to `addBlocker`, got " + details);
|
||||
}
|
||||
if (!this._waitForMe) {
|
||||
throw new Error(`Phase "${ this._name } is finished, it is too late to register completion condition "${ name }"`);
|
||||
throw new Error(`Phase "${ this._name }" is finished, it is too late to register completion condition "${ name }"`);
|
||||
}
|
||||
debug(`Adding blocker ${ name } for phase ${ this._name }`);
|
||||
|
||||
// Normalize the details
|
||||
|
||||
let fetchState = details.fetchState || null;
|
||||
if (fetchState != null && typeof fetchState != "function") {
|
||||
throw new TypeError("Expected a function for option `fetchState`");
|
||||
}
|
||||
let filename = details.filename || null;
|
||||
let lineNumber = details.lineNumber || null;
|
||||
let stack = details.stack || null;
|
||||
@@ -713,7 +741,10 @@ function Barrier(name) {
|
||||
// The error should remain uncaught, to ensure that it
|
||||
// still causes tests to fail.
|
||||
Promise.reject(error);
|
||||
});
|
||||
}).catch(
|
||||
// Added as a last line of defense, in case `warn`, `this._name` or
|
||||
// `safeGetState` somehow throws an error.
|
||||
);
|
||||
|
||||
let topFrame = null;
|
||||
if (filename == null || lineNumber == null || stack == null) {
|
||||
|
||||
@@ -532,7 +532,8 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
|
||||
}
|
||||
|
||||
if (child != 0) {
|
||||
char *clonedMsg = "ExceptionHandler::GenerateDump cloned child ";
|
||||
static const char clonedMsg[] =
|
||||
"ExceptionHandler::GenerateDump cloned child ";
|
||||
char pidMsg[32];
|
||||
|
||||
unsigned int pidLen = my_uint_len(child);
|
||||
@@ -542,7 +543,8 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) {
|
||||
logger::write(pidMsg, pidLen);
|
||||
logger::write("\n", 1);
|
||||
} else {
|
||||
char *childMsg = "ExceptionHandler::GenerateDump I'm the child\n";
|
||||
static const char childMsg[] =
|
||||
"ExceptionHandler::GenerateDump I'm the child\n";
|
||||
logger::write(childMsg, my_strlen(childMsg));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
var dir = Services.dirsvc.get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var file = dir.clone();
|
||||
file = file.parent;
|
||||
file.append(ctypes.libraryName("testcrasher"));
|
||||
var lib = ctypes.open(file.path);
|
||||
CrashTestUtils.crash = lib.declare("Crash",
|
||||
|
||||
@@ -71,7 +71,7 @@ exports.lookup = function(key) {
|
||||
};
|
||||
|
||||
/** @see propertyLookup in lib/gcli/util/l10n.js */
|
||||
exports.propertyLookup = Proxy.create({
|
||||
exports.propertyLookup = new Proxy({}, {
|
||||
get: function(rcvr, name) {
|
||||
return exports.lookup(name);
|
||||
}
|
||||
|
||||
@@ -650,53 +650,6 @@ var AddonManagerInternal = {
|
||||
// Store telemetry details per addon provider
|
||||
telemetryDetails: {},
|
||||
|
||||
// A read-only wrapper around the types dictionary
|
||||
typesProxy: Proxy.create({
|
||||
getOwnPropertyDescriptor: function typesProxy_getOwnPropertyDescriptor(aName) {
|
||||
if (!(aName in AddonManagerInternal.types))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
value: AddonManagerInternal.types[aName].type,
|
||||
writable: false,
|
||||
configurable: false,
|
||||
enumerable: true
|
||||
}
|
||||
},
|
||||
|
||||
getPropertyDescriptor: function typesProxy_getPropertyDescriptor(aName) {
|
||||
return this.getOwnPropertyDescriptor(aName);
|
||||
},
|
||||
|
||||
getOwnPropertyNames: function typesProxy_getOwnPropertyNames() {
|
||||
return Object.keys(AddonManagerInternal.types);
|
||||
},
|
||||
|
||||
getPropertyNames: function typesProxy_getPropertyNames() {
|
||||
return this.getOwnPropertyNames();
|
||||
},
|
||||
|
||||
delete: function typesProxy_delete(aName) {
|
||||
// Not allowed to delete properties
|
||||
return false;
|
||||
},
|
||||
|
||||
defineProperty: function typesProxy_defineProperty(aName, aProperty) {
|
||||
// Ignore attempts to define properties
|
||||
},
|
||||
|
||||
fix: function typesProxy_fix(){
|
||||
return undefined;
|
||||
},
|
||||
|
||||
// Despite MDC's claims to the contrary, it is required that this trap
|
||||
// be defined
|
||||
enumerate: function typesProxy_enumerate() {
|
||||
// All properties are enumerable
|
||||
return this.getPropertyNames();
|
||||
}
|
||||
}),
|
||||
|
||||
recordTimestamp: function AMI_recordTimestamp(name, value) {
|
||||
this.TelemetryTimestamps.add(name, value);
|
||||
},
|
||||
@@ -2458,7 +2411,53 @@ var AddonManagerInternal = {
|
||||
},
|
||||
|
||||
get addonTypes() {
|
||||
return this.typesProxy;
|
||||
// A read-only wrapper around the types dictionary
|
||||
return new Proxy(this.types, {
|
||||
defineProperty(target, property, descriptor) {
|
||||
// Not allowed to define properties
|
||||
return false;
|
||||
},
|
||||
|
||||
deleteProperty(target, property) {
|
||||
// Not allowed to delete properties
|
||||
return false;
|
||||
},
|
||||
|
||||
get(target, property, receiver) {
|
||||
if (!target.hasOwnProperty(property))
|
||||
return undefined;
|
||||
|
||||
return target[property].type;
|
||||
},
|
||||
|
||||
getOwnPropertyDescriptor(target, property) {
|
||||
if (!target.hasOwnProperty(property))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
value: target[property].type,
|
||||
writable: false,
|
||||
// Claim configurability to maintain the proxy invariants.
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
}
|
||||
},
|
||||
|
||||
preventExtensions(target) {
|
||||
// Not allowed to prevent adding new properties
|
||||
return false;
|
||||
},
|
||||
|
||||
set(target, property, value, receiver) {
|
||||
// Not allowed to set properties
|
||||
return false;
|
||||
},
|
||||
|
||||
setPrototypeOf(target, prototype) {
|
||||
// Not allowed to change prototype
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
get autoUpdateDefault() {
|
||||
|
||||
@@ -396,6 +396,14 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
|
||||
bool unused;
|
||||
rv = dirsvc->GetFile("XCurProcD", &unused, getter_AddRefs(file));
|
||||
}
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
else if (!strcmp(aProperty, NS_APP_CONTENT_PROCESS_TEMP_DIR)) {
|
||||
if (!mContentTempDir && NS_FAILED((rv = LoadContentProcessTempDir()))) {
|
||||
return rv;
|
||||
}
|
||||
rv = mContentTempDir->Clone(getter_AddRefs(file));
|
||||
}
|
||||
#endif // defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
|
||||
// We need to allow component, xpt, and chrome registration to
|
||||
// occur prior to the profile-after-change notification.
|
||||
@@ -621,6 +629,50 @@ LoadExtensionDirectories(nsINIParser &parser,
|
||||
while (true);
|
||||
}
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
static const char*
|
||||
GetContentProcessTempBaseDirKey()
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
|
||||
#else
|
||||
return NS_OS_TEMP_DIR;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXREDirProvider::LoadContentProcessTempDir()
|
||||
{
|
||||
nsCOMPtr<nsIFile> localFile;
|
||||
|
||||
nsresult rv = NS_GetSpecialDirectory(GetContentProcessTempBaseDirKey(),
|
||||
getter_AddRefs(localFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoString tempDirSuffix;
|
||||
rv = Preferences::GetString("security.sandbox.content.tempDirSuffix",
|
||||
&tempDirSuffix);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (tempDirSuffix.IsEmpty()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
rv = localFile->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
localFile.swap(mContentTempDir);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#endif // defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
void
|
||||
nsXREDirProvider::LoadExtensionBundleDirectories()
|
||||
{
|
||||
@@ -861,6 +913,7 @@ nsXREDirProvider::DoStartup()
|
||||
|
||||
static const char16_t kStartup[] = {'s','t','a','r','t','u','p','\0'};
|
||||
obsSvc->NotifyObservers(nullptr, "profile-do-change", kStartup);
|
||||
|
||||
// Init the Extension Manager
|
||||
nsCOMPtr<nsIObserver> em = do_GetService("@mozilla.org/addons/integration;1");
|
||||
if (em) {
|
||||
|
||||
@@ -124,6 +124,11 @@ protected:
|
||||
// delimiters.
|
||||
static inline nsresult AppendProfileString(nsIFile* aFile, const char* aPath);
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
// Load the temp directory for sandboxed content processes
|
||||
nsresult LoadContentProcessTempDir();
|
||||
#endif
|
||||
|
||||
// Calculate and register extension and theme bundle directories.
|
||||
void LoadExtensionBundleDirectories();
|
||||
|
||||
@@ -144,6 +149,9 @@ protected:
|
||||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
nsCOMPtr<nsIFile> mProfileLocalDir;
|
||||
bool mProfileNotified;
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
nsCOMPtr<nsIFile> mContentTempDir;
|
||||
#endif
|
||||
nsCOMArray<nsIFile> mAppBundleDirectories;
|
||||
nsCOMArray<nsIFile> mExtensionDirectories;
|
||||
nsCOMArray<nsIFile> mThemeDirectories;
|
||||
|
||||
@@ -515,6 +515,7 @@ void GeckoSampler::StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime)
|
||||
if (TaskTracer()) {
|
||||
aWriter.StartObjectProperty("tasktracer");
|
||||
StreamTaskTracer(aWriter);
|
||||
aWriter.EndObject();
|
||||
}
|
||||
|
||||
// Lists the samples for each ThreadProfile
|
||||
@@ -951,7 +952,9 @@ void GeckoSampler::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSampl
|
||||
StackWalkCallback(/* frameNumber */ 0, aSample->pc, aSample->sp, &nativeStack);
|
||||
|
||||
uint32_t maxFrames = uint32_t(nativeStack.size - nativeStack.count);
|
||||
#if defined(XP_MACOSX) || defined(XP_WIN)
|
||||
// win X64 doesn't support disabling frame pointers emission so we need
|
||||
// to fallback to using StackWalk64 which is slower.
|
||||
#if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(V8_HOST_ARCH_X64))
|
||||
void *stackEnd = aSample->threadProfile->GetStackTop();
|
||||
bool rv = true;
|
||||
if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
|
||||
|
||||
@@ -63,7 +63,8 @@ int dl_iterate_phdr(
|
||||
void *data);
|
||||
#endif
|
||||
|
||||
int dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
|
||||
static int
|
||||
dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
|
||||
{
|
||||
SharedLibraryInfo& info = *reinterpret_cast<SharedLibraryInfo*>(data);
|
||||
|
||||
@@ -90,7 +91,8 @@ int dl_iterate_callback(struct dl_phdr_info *dl_info, size_t size, void *data)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !MOZ_WIDGET_GONK
|
||||
|
||||
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
{
|
||||
@@ -105,13 +107,12 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
// not call it.
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
dl_iterate_phdr(dl_iterate_callback, &info);
|
||||
#ifndef ANDROID
|
||||
return info;
|
||||
#endif
|
||||
#endif
|
||||
#endif // ANDROID
|
||||
|
||||
dl_iterate_phdr(dl_iterate_callback, &info);
|
||||
#endif // !MOZ_WIDGET_GONK
|
||||
|
||||
#if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
|
||||
pid_t pid = getpid();
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
|
||||
@@ -158,5 +159,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
|
||||
}
|
||||
count++;
|
||||
}
|
||||
#endif // ANDROID || MOZ_WIDGET_GONK
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ enum TracingMetadata {
|
||||
TRACING_TIMESTAMP
|
||||
};
|
||||
|
||||
#if !defined(MOZ_ENABLE_PROFILER_SPS) || defined(MOZILLA_XPCOMRT_API)
|
||||
#if !defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -30,21 +30,37 @@ class ProfilerMarkerPayload;
|
||||
|
||||
// Returns a handle to pass on exit. This can check that we are popping the
|
||||
// correct callstack.
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL, bool aCopy = false, uint32_t line = 0);
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo, js::ProfileEntry::Category aCategory,
|
||||
void *aFrameAddress = nullptr, bool aCopy = false,
|
||||
uint32_t line = 0);
|
||||
|
||||
inline void mozilla_sampler_call_exit(void* handle);
|
||||
|
||||
void mozilla_sampler_add_marker(const char *aInfo,
|
||||
ProfilerMarkerPayload *aPayload = nullptr);
|
||||
|
||||
void mozilla_sampler_start(int aEntries, int aInterval, const char** aFeatures, uint32_t aFeatureCount);
|
||||
void mozilla_sampler_start(int aEntries, double aInterval,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
const char** aThreadNameFilters, uint32_t aFilterCount);
|
||||
|
||||
void mozilla_sampler_stop();
|
||||
|
||||
bool mozilla_sampler_is_paused();
|
||||
void mozilla_sampler_pause();
|
||||
void mozilla_sampler_resume();
|
||||
|
||||
ProfilerBacktrace* mozilla_sampler_get_backtrace();
|
||||
void mozilla_sampler_free_backtrace(ProfilerBacktrace* aBacktrace);
|
||||
void mozilla_sampler_get_backtrace_noalloc(char *output, size_t outputSize);
|
||||
|
||||
bool mozilla_sampler_is_active();
|
||||
void mozilla_sampler_responsiveness(TimeStamp time);
|
||||
|
||||
bool mozilla_sampler_feature_active(const char* aName);
|
||||
|
||||
void mozilla_sampler_responsiveness(const mozilla::TimeStamp& time);
|
||||
|
||||
void mozilla_sampler_frame_number(int frameNumber);
|
||||
|
||||
const double* mozilla_sampler_get_responsiveness();
|
||||
|
||||
void mozilla_sampler_save();
|
||||
@@ -73,9 +89,9 @@ const char** mozilla_sampler_get_features();
|
||||
void mozilla_sampler_get_buffer_info(uint32_t *aCurrentPosition, uint32_t *aTotalSize,
|
||||
uint32_t *aGeneration);
|
||||
|
||||
void mozilla_sampler_init();
|
||||
void mozilla_sampler_init(void* stackTop);
|
||||
|
||||
void mozilla_sampler_shutdown();
|
||||
void mozilla_sampler_print_location();
|
||||
|
||||
// Lock the profiler. When locked the profiler is (1) stopped,
|
||||
// (2) profile data is cleared, (3) profiler-locked is fired.
|
||||
@@ -95,5 +111,14 @@ void mozilla_sampler_sleep_end();
|
||||
double mozilla_sampler_time();
|
||||
double mozilla_sampler_time(const mozilla::TimeStamp& aTime);
|
||||
|
||||
void mozilla_sampler_tracing(const char* aCategory, const char* aInfo,
|
||||
TracingMetadata aMetaData);
|
||||
|
||||
void mozilla_sampler_tracing(const char* aCategory, const char* aInfo,
|
||||
ProfilerBacktrace* aCause,
|
||||
TracingMetadata aMetaData);
|
||||
|
||||
void mozilla_sampler_log(const char *fmt, va_list args);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -411,23 +411,26 @@ protected:
|
||||
const char* mInfo;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS SamplerStackFrameRAII {
|
||||
class MOZ_RAII SamplerStackFrameRAII {
|
||||
public:
|
||||
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
|
||||
SamplerStackFrameRAII(const char *aInfo,
|
||||
js::ProfileEntry::Category aCategory, uint32_t line)
|
||||
js::ProfileEntry::Category aCategory, uint32_t line
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
mHandle = mozilla_sampler_call_enter(aInfo, aCategory, this, false, line);
|
||||
}
|
||||
~SamplerStackFrameRAII() {
|
||||
mozilla_sampler_call_exit(mHandle);
|
||||
}
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
void* mHandle;
|
||||
};
|
||||
|
||||
static const int SAMPLER_MAX_STRING = 128;
|
||||
class MOZ_STACK_CLASS SamplerStackFramePrintfRAII {
|
||||
class MOZ_RAII SamplerStackFramePrintfRAII {
|
||||
public:
|
||||
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
|
||||
SamplerStackFramePrintfRAII(const char *aInfo,
|
||||
|
||||
+2
-5
@@ -295,16 +295,13 @@ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \
|
||||
if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \
|
||||
return NS_ERROR_INVALID_ARG; \
|
||||
\
|
||||
_InstanceClass* inst = new _InstanceClass(aOuter); \
|
||||
RefPtr<_InstanceClass> inst = new _InstanceClass(aOuter); \
|
||||
if (!inst) { \
|
||||
return NS_ERROR_OUT_OF_MEMORY; \
|
||||
} \
|
||||
\
|
||||
nsISupports* inner = inst->InnerObject(); \
|
||||
nsresult rv = inner->QueryInterface(aIID, aResult); \
|
||||
if (NS_FAILED(rv)) { \
|
||||
delete inst; \
|
||||
} \
|
||||
\
|
||||
return rv; \
|
||||
} \
|
||||
@@ -318,7 +315,7 @@ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \
|
||||
if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \
|
||||
return NS_ERROR_INVALID_ARG; \
|
||||
\
|
||||
_InstanceClass* inst = new _InstanceClass(aOuter); \
|
||||
RefPtr<_InstanceClass> inst = new _InstanceClass(aOuter); \
|
||||
if (!inst) { \
|
||||
return NS_ERROR_OUT_OF_MEMORY; \
|
||||
} \
|
||||
|
||||
@@ -2461,8 +2461,9 @@ CCGraphBuilder::NoteWeakMapping(JSObject* aMap, JS::GCCellPtr aKey,
|
||||
mapping->mVal = aVal ? AddWeakMapNode(aVal) : nullptr;
|
||||
|
||||
if (mLogger) {
|
||||
mLogger->NoteWeakMapEntry((uint64_t)aMap, aKey.unsafeAsInteger(),
|
||||
(uint64_t)aKdelegate, aVal.unsafeAsInteger());
|
||||
mLogger->NoteWeakMapEntry((uint64_t)aMap, aKey ? aKey.unsafeAsInteger() : 0,
|
||||
(uint64_t)aKdelegate,
|
||||
aVal ? aVal.unsafeAsInteger() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3271,6 +3272,7 @@ nsCycleCollector::CollectWhite()
|
||||
PtrInfo* pinfo = etor.GetNext();
|
||||
if (pinfo->mColor == white && pinfo->mParticipant) {
|
||||
if (pinfo->IsGrayJS()) {
|
||||
MOZ_ASSERT(mJSRuntime);
|
||||
++numWhiteGCed;
|
||||
JS::Zone* zone;
|
||||
if (MOZ_UNLIKELY(pinfo->mParticipant == zoneParticipant)) {
|
||||
|
||||
@@ -89,4 +89,9 @@
|
||||
#define NS_APP_INDEXEDDB_PARENT_DIR "indexedDBPDir"
|
||||
|
||||
#define NS_APP_PERMISSION_PARENT_DIR "permissionDBPDir"
|
||||
#endif
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#define NS_APP_CONTENT_PROCESS_TEMP_DIR "ContentTmpD"
|
||||
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
#endif // nsAppDirectoryServiceDefs_h___
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIURI.h" // for NS_IURI_IID
|
||||
#include "nsIX509Cert.h" // for NS_IX509CERT_IID
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
@@ -934,6 +935,23 @@ nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports** aObject)
|
||||
}
|
||||
// END HACK
|
||||
|
||||
// HACK: Service workers store resource security info on disk in the dom
|
||||
// Cache API. When the uuid of the nsIX509Cert interface changes
|
||||
// these serialized objects cannot be loaded any more. This hack
|
||||
// works around this issue.
|
||||
|
||||
// hackaround for bug 1247580 (FF45 to FF46 transition)
|
||||
static const nsIID oldCertIID = {
|
||||
0xf8ed8364, 0xced9, 0x4c6e,
|
||||
{ 0x86, 0xba, 0x48, 0xaf, 0x53, 0xc3, 0x93, 0xe6 }
|
||||
};
|
||||
|
||||
if (iid.Equals(oldCertIID)) {
|
||||
const nsIID newCertIID = NS_IX509CERT_IID;
|
||||
iid = newCertIID;
|
||||
}
|
||||
// END HACK
|
||||
|
||||
nsCOMPtr<nsISupports> object = do_CreateInstance(cid, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
||||
@@ -481,6 +481,7 @@ ConvertWinError(DWORD aWinErr)
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_DRIVE:
|
||||
case ERROR_NOT_READY:
|
||||
rv = NS_ERROR_FILE_NOT_FOUND;
|
||||
break;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
@@ -807,7 +808,6 @@ ReadDir(nsDir* aDir, PRDirFlags aFlags, nsString& aName)
|
||||
}
|
||||
|
||||
const wchar_t* fileName;
|
||||
nsString tmp;
|
||||
fileName = (aDir)->data.cFileName;
|
||||
|
||||
if ((aFlags & PR_SKIP_DOT) &&
|
||||
@@ -825,11 +825,7 @@ ReadDir(nsDir* aDir, PRDirFlags aFlags, nsString& aName)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileName == tmp.get()) {
|
||||
aName = tmp;
|
||||
} else {
|
||||
aName = fileName;
|
||||
}
|
||||
aName = fileName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,11 @@ nsScriptableInputStream::ReadBytes(uint32_t aCount, nsACString& aResult)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
aResult.SetLength(aCount);
|
||||
if (aResult.Length() != aCount) {
|
||||
if (!aResult.SetLength(aCount, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aResult.Length() == aCount);
|
||||
char* ptr = aResult.BeginWriting();
|
||||
nsresult rv = ReadHelper(ptr, aCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
||||
@@ -31,7 +31,6 @@ if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_DEBUG']:
|
||||
|
||||
TEST_DIRS += [
|
||||
'tests',
|
||||
'typelib/xpt/tests',
|
||||
]
|
||||
|
||||
# Can't build internal xptcall tests that use symbols which are not exported.
|
||||
|
||||
@@ -24,7 +24,7 @@ if CONFIG['OS_ARCH'] == 'GNU':
|
||||
'xptcstubs_gcc_x86_unix.cpp'
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] in ('Linux', 'FreeBSD', 'NetBSD', 'OpenBSD') or \
|
||||
if CONFIG['OS_ARCH'] in ('Linux', 'Bitrig', 'DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD') or \
|
||||
CONFIG['OS_ARCH'].startswith('GNU_'):
|
||||
if CONFIG['OS_TEST'] == 'x86_64':
|
||||
SOURCES += [
|
||||
@@ -98,7 +98,7 @@ if CONFIG['CPU_ARCH'] == 'arm' or CONFIG['OS_TEST'] == 'sa110':
|
||||
'xptcstubs_arm_netbsd.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['OS_ARCH'] == 'OpenBSD':
|
||||
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['OS_ARCH'] in ('Bitrig', 'OpenBSD'):
|
||||
SOURCES += [
|
||||
'xptcinvoke_arm_openbsd.cpp',
|
||||
'xptcstubs_arm_openbsd.cpp',
|
||||
|
||||
@@ -113,6 +113,12 @@ invoke_copy_to_stack(uint32_t* stk, uint32_t *end,
|
||||
|
||||
typedef nsresult (*vtable_func)(nsISupports *, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
// Avoid AddressSanitizer instrumentation for the next function because it
|
||||
// depends on __builtin_alloca behavior and alignment that cannot be relied on
|
||||
// once the function is compiled with a version of ASan that has dynamic-alloca
|
||||
// instrumentation enabled.
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant* params)
|
||||
|
||||
@@ -170,6 +170,12 @@ invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint32_t* d_ov, uint
|
||||
|
||||
typedef nsresult (*vtable_func)(nsISupports *, uint32_t, uint32_t, uint32_t, uint32_t, double, double);
|
||||
|
||||
// Avoid AddressSanitizer instrumentation for the next function because it
|
||||
// depends on __builtin_alloca behavior and alignment that cannot be relied on
|
||||
// once the function is compiled with a version of ASan that has dynamic-alloca
|
||||
// instrumentation enabled.
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant* params)
|
||||
|
||||
@@ -164,6 +164,12 @@ invoke_copy_to_stack(uint32_t paramCount, nsXPTCVariant* s, uint64_t* d_ov, uint
|
||||
|
||||
typedef nsresult (*vtable_func)(nsISupports *, uint64_t, uint64_t, uint64_t, uint64_t, double, double, double, double);
|
||||
|
||||
// Avoid AddressSanitizer instrumentation for the next function because it
|
||||
// depends on __builtin_alloca behavior and alignment that cannot be relied on
|
||||
// once the function is compiled with a version of ASan that has dynamic-alloca
|
||||
// instrumentation enabled.
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant* params)
|
||||
|
||||
@@ -100,6 +100,12 @@ invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s,
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid AddressSanitizer instrumentation for the next function because it
|
||||
// depends on __builtin_alloca behavior and alignment that cannot be relied on
|
||||
// once the function is compiled with a version of ASan that has dynamic-alloca
|
||||
// instrumentation enabled.
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant * params)
|
||||
|
||||
@@ -47,9 +47,9 @@ static void
|
||||
invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s,
|
||||
uint64_t * gpregs, double * fpregs)
|
||||
{
|
||||
uint32_t nr_gpr = 1; // skip one GP register for 'that'
|
||||
uint32_t nr_fpr = 0;
|
||||
uint64_t value;
|
||||
uint32_t nr_gpr = 1u; // skip one GP register for 'that'
|
||||
uint32_t nr_fpr = 0u;
|
||||
uint64_t value = 0u;
|
||||
|
||||
for (uint32_t i = 0; i < paramCount; i++, s++) {
|
||||
if (s->IsPtrData())
|
||||
@@ -113,6 +113,12 @@ invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s,
|
||||
#pragma GCC target ("no-avx")
|
||||
#endif
|
||||
|
||||
// Avoid AddressSanitizer instrumentation for the next function because it
|
||||
// depends on __builtin_alloca behavior and alignment that cannot be relied on
|
||||
// once the function is compiled with a version of ASan that has dynamic-alloca
|
||||
// instrumentation enabled.
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant * params)
|
||||
|
||||
@@ -31,9 +31,11 @@ else:
|
||||
else:
|
||||
SOURCES += [
|
||||
'xptcinvoke.cpp',
|
||||
'xptcinvoke_asm_x86_msvc.asm',
|
||||
'xptcstubs.cpp',
|
||||
]
|
||||
SOURCES['xptcinvoke.cpp'].no_pgo = True
|
||||
SOURCES['xptcinvoke_asm_x86_msvc.asm'].flags += ['-safeseh']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#error "This code is for Win32 only"
|
||||
#endif
|
||||
|
||||
static void __fastcall
|
||||
extern "C" void __fastcall
|
||||
invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPTCVariant* s)
|
||||
{
|
||||
for(; paramCount > 0; paramCount--, d++, s++)
|
||||
@@ -43,40 +43,3 @@ invoke_copy_to_stack(uint32_t* d, uint32_t paramCount, nsXPTCVariant* s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(disable : 4035) // OK to have no return value
|
||||
// Tell the PDB file this function has a standard frame pointer, and not to use
|
||||
// a custom FPO program.
|
||||
#pragma optimize( "y", off )
|
||||
extern "C" NS_EXPORT nsresult NS_FROZENCALL
|
||||
NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
||||
uint32_t paramCount, nsXPTCVariant* params)
|
||||
{
|
||||
__asm {
|
||||
mov edx,paramCount // Save paramCount for later
|
||||
test edx,edx // maybe we don't have any params to copy
|
||||
jz noparams
|
||||
mov eax,edx
|
||||
shl eax,3 // *= 8 (max possible param size)
|
||||
sub esp,eax // make space for params
|
||||
mov ecx,esp
|
||||
push params
|
||||
call invoke_copy_to_stack // fastcall, ecx = d, edx = paramCount, params is on the stack
|
||||
noparams:
|
||||
mov ecx,that // instance in ecx
|
||||
push ecx // push this
|
||||
mov edx,[ecx] // vtable in edx
|
||||
mov eax,methodIndex
|
||||
call dword ptr[edx+eax*4] // stdcall, i.e. callee cleans up stack.
|
||||
mov esp,ebp
|
||||
#ifdef __clang__
|
||||
// clang-cl doesn't emit the pop and ret instructions because it doesn't realize
|
||||
// that the call instruction sets a return value in eax. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1028613 and
|
||||
// http://llvm.org/bugs/show_bug.cgi?id=17201.
|
||||
pop ebp
|
||||
ret
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#pragma warning(default : 4035) // restore default
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TITLE xptcinvoke_asm_x86_msvc.asm
|
||||
.686P
|
||||
.model flat
|
||||
|
||||
PUBLIC _NS_InvokeByIndex
|
||||
EXTRN @invoke_copy_to_stack@12:PROC
|
||||
|
||||
;
|
||||
; extern "C" nsresult __cdecl
|
||||
; NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
||||
; uint32_t paramCount, nsXPTCVariant* params)
|
||||
;
|
||||
|
||||
_TEXT SEGMENT
|
||||
_NS_InvokeByIndex PROC
|
||||
|
||||
; Build frame
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
; Save paramCount for later
|
||||
mov edx, dword ptr [ebp+16]
|
||||
|
||||
; Do we have any parameters?
|
||||
test edx, edx
|
||||
jz noparams
|
||||
|
||||
; Build call for copy_to_stack, which is __fastcall
|
||||
|
||||
; Allocate space for parameters. 8 is the biggest size
|
||||
; any parameter can be, so assume that all our parameters
|
||||
; are that large.
|
||||
mov eax, edx
|
||||
shl eax, 3
|
||||
sub esp, eax
|
||||
|
||||
mov ecx, esp
|
||||
push dword ptr [ebp+20]
|
||||
call @invoke_copy_to_stack@12
|
||||
noparams:
|
||||
; Push the `this' parameter for the call.
|
||||
mov ecx, dword ptr [ebp+8]
|
||||
push ecx
|
||||
|
||||
; Load the vtable.
|
||||
mov edx, dword ptr [ecx]
|
||||
|
||||
; Call the vtable index at `methodIndex'.
|
||||
mov eax, dword ptr [ebp+12]
|
||||
call dword ptr [edx+eax*4]
|
||||
|
||||
; Reset and return.
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
_NS_InvokeByIndex ENDP
|
||||
_TEXT ENDS
|
||||
|
||||
END
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
@@ -278,9 +278,14 @@
|
||||
using namespace mozilla;
|
||||
|
||||
struct ComponentsInterfaceShimEntry {
|
||||
MOZ_CONSTEXPR
|
||||
ComponentsInterfaceShimEntry(const char* aName, const nsIID& aIID,
|
||||
const dom::NativePropertyHooks* aNativePropHooks)
|
||||
: geckoName(aName), iid(aIID), nativePropHooks(aNativePropHooks) {}
|
||||
|
||||
const char *geckoName;
|
||||
nsIID iid;
|
||||
const mozilla::dom::NativePropertyHooks* nativePropHooks;
|
||||
const nsIID& iid;
|
||||
const dom::NativePropertyHooks* nativePropHooks;
|
||||
};
|
||||
|
||||
#define DEFINE_SHIM_WITH_CUSTOM_INTERFACE(geckoName, domName) \
|
||||
|
||||
@@ -48,9 +48,10 @@ xptiInterfaceEntry::Create(const char* name, const nsID& iid,
|
||||
xptiTypelibGuts* aTypelib)
|
||||
{
|
||||
int namelen = strlen(name);
|
||||
return new (XPT_MALLOC(gXPTIStructArena,
|
||||
sizeof(xptiInterfaceEntry) + namelen))
|
||||
xptiInterfaceEntry(name, namelen, iid, aDescriptor, aTypelib);
|
||||
void* place =
|
||||
XPT_CALLOC8(gXPTIStructArena, sizeof(xptiInterfaceEntry) + namelen);
|
||||
return new (place) xptiInterfaceEntry(name, namelen, iid, aDescriptor,
|
||||
aTypelib);
|
||||
}
|
||||
|
||||
xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
|
||||
@@ -60,11 +61,11 @@ xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
|
||||
xptiTypelibGuts* aTypelib)
|
||||
: mIID(iid)
|
||||
, mDescriptor(aDescriptor)
|
||||
, mMethodBaseIndex(0)
|
||||
, mConstantBaseIndex(0)
|
||||
, mTypelib(aTypelib)
|
||||
, mParent(nullptr)
|
||||
, mInfo(nullptr)
|
||||
, mMethodBaseIndex(0)
|
||||
, mConstantBaseIndex(0)
|
||||
, mFlags(0)
|
||||
{
|
||||
memcpy(mName, name, nameLength);
|
||||
@@ -343,7 +344,7 @@ xptiInterfaceEntry::GetInterfaceIndexForParam(uint16_t methodIndex,
|
||||
const XPTTypeDescriptor *td = ¶m->type;
|
||||
|
||||
while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
|
||||
td = &mDescriptor->additional_types[td->type.additional_type];
|
||||
td = &mDescriptor->additional_types[td->u.array.additional_type];
|
||||
}
|
||||
|
||||
if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
|
||||
@@ -351,7 +352,7 @@ xptiInterfaceEntry::GetInterfaceIndexForParam(uint16_t methodIndex,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*interfaceIndex = td->type.iface;
|
||||
*interfaceIndex = (td->u.iface.iface_hi8 << 8) | td->u.iface.iface_lo8;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -482,7 +483,7 @@ xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
|
||||
NS_ERROR("bad dimension");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
td = &additional_types[td->type.additional_type];
|
||||
td = &additional_types[td->u.array.additional_type];
|
||||
}
|
||||
|
||||
*type = td;
|
||||
@@ -556,15 +557,17 @@ xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16_t methodIndex,
|
||||
// verify that this is a type that has size_is
|
||||
switch (XPT_TDP_TAG(td->prefix)) {
|
||||
case TD_ARRAY:
|
||||
*argnum = td->u.array.argnum;
|
||||
break;
|
||||
case TD_PSTRING_SIZE_IS:
|
||||
case TD_PWSTRING_SIZE_IS:
|
||||
*argnum = td->u.pstring_is.argnum;
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("not a size_is");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*argnum = td->argnum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -590,8 +593,7 @@ xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
|
||||
const XPTTypeDescriptor *td = ¶m->type;
|
||||
|
||||
while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
|
||||
td = &mDescriptor->
|
||||
additional_types[td->type.additional_type];
|
||||
td = &mDescriptor->additional_types[td->u.array.additional_type];
|
||||
}
|
||||
|
||||
if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) {
|
||||
@@ -599,7 +601,7 @@ xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*argnum = td->argnum;
|
||||
*argnum = td->u.interface_is.argnum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
// Measure gXPTIStructArena here, too. This is a bit grotty because it
|
||||
// doesn't belong to the XPTIInterfaceInfoManager, but there's no
|
||||
// obviously better place to measure it.
|
||||
amount += XPT_SizeOfArena(gXPTIStructArena, XPTIMallocSizeOf);
|
||||
amount += XPT_SizeOfArenaIncludingThis(gXPTIStructArena, XPTIMallocSizeOf);
|
||||
|
||||
return MOZ_COLLECT_REPORT(
|
||||
"explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount,
|
||||
@@ -99,13 +99,11 @@ XPTInterfaceInfoManager::InitMemoryReporter()
|
||||
void
|
||||
XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
|
||||
{
|
||||
XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length);
|
||||
if (!state)
|
||||
return;
|
||||
XPTState state;
|
||||
XPT_InitXDRState(&state, buf, length);
|
||||
|
||||
XPTCursor cursor;
|
||||
if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) {
|
||||
XPT_DestroyXDRState(state);
|
||||
if (!XPT_MakeCursor(&state, XPT_HEADER, 0, &cursor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,8 +111,6 @@ XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
|
||||
if (XPT_DoHeader(gXPTIStructArena, &cursor, &header)) {
|
||||
RegisterXPTHeader(header);
|
||||
}
|
||||
|
||||
XPT_DestroyXDRState(state);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -22,11 +22,10 @@ xptiTypelibGuts*
|
||||
xptiTypelibGuts::Create(XPTHeader* aHeader)
|
||||
{
|
||||
NS_ASSERTION(aHeader, "bad param");
|
||||
void* place = XPT_MALLOC(gXPTIStructArena,
|
||||
sizeof(xptiTypelibGuts) +
|
||||
(sizeof(xptiInterfaceEntry*) *
|
||||
(aHeader->num_interfaces - 1)));
|
||||
if(!place)
|
||||
size_t n = sizeof(xptiTypelibGuts) +
|
||||
sizeof(xptiInterfaceEntry*) * (aHeader->num_interfaces - 1);
|
||||
void* place = XPT_CALLOC8(gXPTIStructArena, n);
|
||||
if (!place)
|
||||
return nullptr;
|
||||
return new(place) xptiTypelibGuts(aHeader);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 16)
|
||||
#define XPTI_HASHTABLE_LENGTH 1024
|
||||
static const size_t XPTI_ARENA8_BLOCK_SIZE = 16 * 1024;
|
||||
static const size_t XPTI_ARENA1_BLOCK_SIZE = 8 * 1024;
|
||||
|
||||
static const uint32_t XPTI_HASHTABLE_LENGTH = 1024;
|
||||
|
||||
XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet()
|
||||
: mTableReentrantMonitor("xptiWorkingSet::mTableReentrantMonitor")
|
||||
@@ -23,8 +25,8 @@ XPTInterfaceInfoManager::xptiWorkingSet::xptiWorkingSet()
|
||||
{
|
||||
MOZ_COUNT_CTOR(xptiWorkingSet);
|
||||
|
||||
gXPTIStructArena = XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double),
|
||||
"xptiWorkingSet structs");
|
||||
gXPTIStructArena = XPT_NewArena(XPTI_ARENA8_BLOCK_SIZE,
|
||||
XPTI_ARENA1_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -187,7 +187,6 @@ public:
|
||||
bool IsGetter() const {return 0 != (XPT_MD_IS_GETTER(flags) );}
|
||||
bool IsSetter() const {return 0 != (XPT_MD_IS_SETTER(flags) );}
|
||||
bool IsNotXPCOM() const {return 0 != (XPT_MD_IS_NOTXPCOM(flags));}
|
||||
bool IsConstructor() const {return 0 != (XPT_MD_IS_CTOR(flags) );}
|
||||
bool IsHidden() const {return 0 != (XPT_MD_IS_HIDDEN(flags) );}
|
||||
bool WantsOptArgc() const {return 0 != (XPT_MD_WANTS_OPT_ARGC(flags));}
|
||||
bool WantsContext() const {return 0 != (XPT_MD_WANTS_CONTEXT(flags));}
|
||||
|
||||
@@ -307,8 +307,6 @@ private:
|
||||
nsID mIID;
|
||||
XPTInterfaceDescriptor* mDescriptor;
|
||||
|
||||
uint16_t mMethodBaseIndex;
|
||||
uint16_t mConstantBaseIndex;
|
||||
xptiTypelibGuts* mTypelib;
|
||||
|
||||
xptiInterfaceEntry* mParent; // Valid only when fully resolved
|
||||
@@ -316,7 +314,12 @@ private:
|
||||
xptiInterfaceInfo* MOZ_UNSAFE_REF("The safety of this pointer is ensured "
|
||||
"by the semantics of xptiWorkingSet.")
|
||||
mInfo; // May come and go.
|
||||
|
||||
uint16_t mMethodBaseIndex;
|
||||
uint16_t mConstantBaseIndex;
|
||||
|
||||
xptiInfoFlags mFlags;
|
||||
|
||||
char mName[1]; // Always last. Sized to fit.
|
||||
};
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Test the xdr primitives from xpt_xdr.c */
|
||||
|
||||
#include "xpt_xdr.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* for memcpy */
|
||||
|
||||
#define PASS(msg) \
|
||||
fprintf(stderr, "PASSED : %s\n", msg);
|
||||
|
||||
#define FAIL(msg) \
|
||||
fprintf(stderr, "FAILURE: %s\n", msg);
|
||||
|
||||
#define TRY_(msg, cond, silent) \
|
||||
if ((cond) && !silent) { \
|
||||
PASS(msg); \
|
||||
} else { \
|
||||
FAIL(msg); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define TRY(msg, cond) TRY_(msg, cond, 0)
|
||||
#define TRY_Q(msg, cond) TRY_(msg, cond, 1);
|
||||
|
||||
static char bazz[] = "bazz";
|
||||
XPTString in_str = { 4, bazz };
|
||||
|
||||
static char foobar[] = "foobar";
|
||||
struct TestData {
|
||||
uint32_t bit32;
|
||||
uint16_t bit16;
|
||||
uint8_t bit8[2];
|
||||
char *cstr;
|
||||
XPTString *str;
|
||||
} input = { 0xdeadbeef, 0xcafe, {0xba, 0xbe}, foobar, &in_str},
|
||||
output = {0, 0, {0, 0}, NULL, NULL };
|
||||
|
||||
void
|
||||
dump_struct(const char *label, struct TestData *str)
|
||||
{
|
||||
fprintf(stderr, "%s: {%#08x, %#04x, {%#02x, %#02x}, %s, %d/%s}\n",
|
||||
label, str->bit32, str->bit16, str->bit8[0], str->bit8[1],
|
||||
str->cstr, str->str->length, str->str->bytes);
|
||||
}
|
||||
|
||||
PRBool
|
||||
XDR(XPTArena *arena, XPTCursor *cursor, struct TestData *str)
|
||||
{
|
||||
TRY("Do32", XPT_Do32(cursor, &str->bit32));
|
||||
TRY("Do16", XPT_Do16(cursor, &str->bit16));
|
||||
TRY("Do8", XPT_Do8 (cursor, &str->bit8[0]));
|
||||
TRY("Do8", XPT_Do8 (cursor, &str->bit8[1]));
|
||||
TRY("DoCString", XPT_DoCString(arena, cursor, &str->cstr));
|
||||
TRY("DoString", XPT_DoString(arena, cursor, &str->str));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
XPTArena *arena;
|
||||
XPTState *state;
|
||||
XPTCursor curs, *cursor = &curs;
|
||||
char *header, *data, *whole;
|
||||
uint32_t hlen, dlen, i;
|
||||
|
||||
TRY("XPT_NewArena", (arena = XPT_NewArena(1024, sizeof(double), "main")));
|
||||
|
||||
TRY("NewState (ENCODE)", (state = XPT_NewXDRState(XPT_ENCODE, NULL, 0)));
|
||||
|
||||
XPT_SetDataOffset(state, sizeof input);
|
||||
|
||||
TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor));
|
||||
|
||||
dump_struct("before", &input);
|
||||
|
||||
if (XDR(arena, cursor, &input))
|
||||
return 1;
|
||||
|
||||
fprintf(stderr, "ENCODE successful\n");
|
||||
XPT_GetXDRData(state, XPT_HEADER, &header, &hlen);
|
||||
fprintf(stderr, "XDR header %d bytes at %p:",
|
||||
hlen, header);
|
||||
for (i = 0; i < hlen; i++)
|
||||
fprintf(stderr, "%c%02x", i ? ',' : ' ', (uint8_t)header[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
XPT_GetXDRData(state, XPT_DATA, &data, &dlen);
|
||||
|
||||
fprintf(stderr, "XDR data %d bytes at %p:",
|
||||
dlen, data);
|
||||
for (i = 0; i < dlen; i++)
|
||||
fprintf(stderr, "%c%02x/%c", i ? ',' : ' ', (uint8_t)data[i],
|
||||
(uint8_t)data[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
whole = (char*)malloc(dlen + hlen);
|
||||
if (!whole) {
|
||||
fprintf(stderr, "malloc %d failed!\n", dlen + hlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TRY_Q("malloc", (data2 = malloc(len))); */
|
||||
memcpy(whole, header, hlen);
|
||||
memcpy(whole + hlen, data, dlen);
|
||||
XPT_DestroyXDRState(state);
|
||||
|
||||
TRY("NewState (DECODE)", (state = XPT_NewXDRState(XPT_DECODE, whole,
|
||||
hlen + dlen)));
|
||||
|
||||
TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor));
|
||||
XPT_SetDataOffset(state, sizeof input);
|
||||
|
||||
if (XDR(arena, cursor, &output))
|
||||
return 1;
|
||||
|
||||
dump_struct("after", &output);
|
||||
XPT_DestroyXDRState(state);
|
||||
XPT_DestroyArena(arena);
|
||||
free(whole);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Test the structure creation and serialization APIs from xpt_struct.c */
|
||||
#include <stdio.h>
|
||||
|
||||
#include "xpt_xdr.h"
|
||||
#include "xpt_struct.h"
|
||||
|
||||
#define PASS(msg) \
|
||||
fprintf(stderr, "PASSED : %s\n", msg);
|
||||
|
||||
#define FAIL(msg) \
|
||||
fprintf(stderr, "FAILURE: %s\n", msg);
|
||||
|
||||
#define TRY_(msg, cond, silent) \
|
||||
if ((cond) && !silent) { \
|
||||
PASS(msg); \
|
||||
} else { \
|
||||
FAIL(msg); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define TRY(msg, cond) TRY_(msg, cond, 0)
|
||||
#define TRY_Q(msg, cond) TRY_(msg, cond, 1);
|
||||
|
||||
struct nsID iid = {
|
||||
0x00112233,
|
||||
0x4455,
|
||||
0x6677,
|
||||
{0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
|
||||
};
|
||||
|
||||
XPTTypeDescriptor td_void;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
XPTArena *arena;
|
||||
XPTHeader *header;
|
||||
XPTAnnotation *ann;
|
||||
XPTInterfaceDescriptor *id;
|
||||
XPTMethodDescriptor *meth;
|
||||
|
||||
XPTState *state;
|
||||
XPTCursor curs, *cursor = &curs;
|
||||
char *data, *head;
|
||||
FILE *out;
|
||||
uint32_t len, header_sz;
|
||||
|
||||
PRBool ok;
|
||||
|
||||
td_void.prefix.flags = TD_VOID;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <filename.xpt>\n"
|
||||
" Creates a simple typelib file.\n", argv[0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
arena = XPT_NewArena(1024, sizeof(double), "main");
|
||||
TRY("XPT_NewArena", arena);
|
||||
|
||||
/* construct a header */
|
||||
header = XPT_NewHeader(arena, 1, XPT_MAJOR_VERSION, XPT_MINOR_VERSION);
|
||||
TRY("NewHeader", header);
|
||||
|
||||
|
||||
ann = XPT_NewAnnotation(arena, XPT_ANN_LAST | XPT_ANN_PRIVATE,
|
||||
XPT_NewStringZ(arena, "SimpleTypeLib 1.0"),
|
||||
XPT_NewStringZ(arena, "See You In Rome"));
|
||||
TRY("NewAnnotation", ann);
|
||||
header->annotations = ann;
|
||||
|
||||
header_sz = XPT_SizeOfHeaderBlock(header);
|
||||
|
||||
id = XPT_NewInterfaceDescriptor(arena, 0, 2, 2, 0);
|
||||
TRY("NewInterfaceDescriptor", id);
|
||||
|
||||
ok = XPT_FillInterfaceDirectoryEntry(arena, header->interface_directory, &iid,
|
||||
"Interface", "NS", id);
|
||||
TRY("FillInterfaceDirectoryEntry", ok);
|
||||
|
||||
/* void method1(void) */
|
||||
meth = &id->method_descriptors[0];
|
||||
ok = XPT_FillMethodDescriptor(arena, meth, 0, "method1", 0);
|
||||
TRY("FillMethodDescriptor", ok);
|
||||
meth->result.flags = 0;
|
||||
meth->result.type.prefix.flags = TD_VOID;
|
||||
|
||||
/* wstring method2(in uint32_t, in bool) */
|
||||
meth = &id->method_descriptors[1];
|
||||
ok = XPT_FillMethodDescriptor(arena, meth, 0, "method2", 2);
|
||||
TRY("FillMethodDescriptor", ok);
|
||||
|
||||
meth->result.flags = 0;
|
||||
meth->result.type.prefix.flags = TD_PSTRING | XPT_TDP_POINTER;
|
||||
meth->params[0].type.prefix.flags = TD_UINT32;
|
||||
meth->params[0].flags = XPT_PD_IN;
|
||||
meth->params[1].type.prefix.flags = TD_BOOL;
|
||||
meth->params[1].flags = XPT_PD_IN;
|
||||
|
||||
#if 0
|
||||
/* const one = 1; */
|
||||
id->const_descriptors[0].name = "one";
|
||||
id->const_descriptors[0].type.prefix.flags = TD_UINT16;
|
||||
id->const_descriptors[0].value.ui16 = 1;
|
||||
|
||||
/* const squeamish = "ossifrage"; */
|
||||
id->const_descriptors[1].name = "squeamish";
|
||||
id->const_descriptors[1].type.prefix.flags = TD_PBSTR | XPT_TDP_POINTER;
|
||||
id->const_descriptors[1].value.string = XPT_NewStringZ(arena, "ossifrage");
|
||||
#endif
|
||||
|
||||
/* serialize it */
|
||||
state = XPT_NewXDRState(XPT_ENCODE, NULL, 0);
|
||||
TRY("NewState (ENCODE)", state);
|
||||
|
||||
ok = XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor);
|
||||
TRY("MakeCursor", ok);
|
||||
|
||||
ok = XPT_DoHeader(arena, cursor, &header);
|
||||
TRY("DoHeader", ok);
|
||||
|
||||
out = fopen(argv[1], "wb");
|
||||
if (!out) {
|
||||
perror("FAILED: fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XPT_GetXDRData(state, XPT_HEADER, &head, &len);
|
||||
fwrite(head, len, 1, out);
|
||||
|
||||
XPT_GetXDRData(state, XPT_DATA, &data, &len);
|
||||
fwrite(data, len, 1, out);
|
||||
|
||||
if (ferror(out) != 0 || fclose(out) != 0) {
|
||||
fprintf(stderr, "\nError writing file: %s\n\n", argv[1]);
|
||||
} else {
|
||||
fprintf(stderr, "\nFile written: %s\n\n", argv[1]);
|
||||
}
|
||||
XPT_DestroyXDRState(state);
|
||||
|
||||
XPT_FreeHeader(arena, header);
|
||||
XPT_DestroyArena(arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
SimplePrograms([
|
||||
'PrimitiveTest',
|
||||
'SimpleTypeLib',
|
||||
])
|
||||
|
||||
USE_LIBS += [
|
||||
'xpt',
|
||||
]
|
||||
+82
-216
@@ -8,7 +8,6 @@
|
||||
/* XXX This exists because we don't want to drag in NSPR. It *seemed*
|
||||
* to make more sense to write a quick and dirty arena than to clone
|
||||
* plarena (like js/src did). This is not optimal, but it works.
|
||||
* Half of the code here is instrumentation.
|
||||
*/
|
||||
|
||||
#include "xpt_arena.h"
|
||||
@@ -17,64 +16,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*************************/
|
||||
/* logging stats support */
|
||||
|
||||
#if 0 && defined(DEBUG_jband)
|
||||
#define XPT_ARENA_LOGGING 1
|
||||
#endif
|
||||
|
||||
#ifdef XPT_ARENA_LOGGING
|
||||
|
||||
#define LOG_MALLOC(_a, _req, _used) \
|
||||
do{ \
|
||||
XPT_ASSERT((_a)); \
|
||||
++(_a)->LOG_MallocCallCount; \
|
||||
(_a)->LOG_MallocTotalBytesRequested += (_req); \
|
||||
(_a)->LOG_MallocTotalBytesUsed += (_used); \
|
||||
} while(0)
|
||||
|
||||
#define LOG_REAL_MALLOC(_a, _size) \
|
||||
do{ \
|
||||
XPT_ASSERT((_a)); \
|
||||
++(_a)->LOG_RealMallocCallCount; \
|
||||
(_a)->LOG_RealMallocTotalBytesRequested += (_size); \
|
||||
} while(0)
|
||||
|
||||
#define LOG_FREE(_a) \
|
||||
do{ \
|
||||
XPT_ASSERT((_a)); \
|
||||
++(_a)->LOG_FreeCallCount; \
|
||||
} while(0)
|
||||
|
||||
#define LOG_DONE_LOADING(_a) \
|
||||
do{ \
|
||||
XPT_ASSERT((_a)); \
|
||||
(_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount; \
|
||||
} while(0)
|
||||
|
||||
#define PRINT_STATS(_a) xpt_DebugPrintArenaStats((_a))
|
||||
static void xpt_DebugPrintArenaStats(XPTArena *arena);
|
||||
|
||||
#else /* !XPT_ARENA_LOGGING */
|
||||
|
||||
#define LOG_MALLOC(_a, _req, _used) ((void)0)
|
||||
#define LOG_REAL_MALLOC(_a, _size) ((void)0)
|
||||
#define LOG_FREE(_a) ((void)0)
|
||||
|
||||
#define LOG_DONE_LOADING(_a) ((void)0)
|
||||
#define PRINT_STATS(_a) ((void)0)
|
||||
|
||||
#endif /* XPT_ARENA_LOGGING */
|
||||
|
||||
/****************************************************/
|
||||
|
||||
/* Block header for each block in the arena */
|
||||
typedef struct BLK_HDR BLK_HDR;
|
||||
struct BLK_HDR
|
||||
{
|
||||
BLK_HDR *next;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#define XPT_MIN_BLOCK_SIZE 32
|
||||
@@ -82,91 +29,66 @@ struct BLK_HDR
|
||||
/* XXX this is lame. Should clone the code to do this bitwise */
|
||||
#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a)))
|
||||
|
||||
struct XPTArena
|
||||
struct XPTSubArena
|
||||
{
|
||||
BLK_HDR *first;
|
||||
uint8_t *next;
|
||||
size_t space;
|
||||
size_t alignment;
|
||||
size_t block_size;
|
||||
char *name;
|
||||
};
|
||||
|
||||
#ifdef XPT_ARENA_LOGGING
|
||||
uint32_t LOG_MallocCallCount;
|
||||
uint32_t LOG_MallocTotalBytesRequested;
|
||||
uint32_t LOG_MallocTotalBytesUsed;
|
||||
uint32_t LOG_FreeCallCount;
|
||||
uint32_t LOG_LoadingFreeCallCount;
|
||||
uint32_t LOG_RealMallocCallCount;
|
||||
uint32_t LOG_RealMallocTotalBytesRequested;
|
||||
#endif /* XPT_ARENA_LOGGING */
|
||||
struct XPTArena
|
||||
{
|
||||
// We have one sub-arena with 8-byte alignment for most allocations, and
|
||||
// one with 1-byte alignment for C string allocations. The latter sub-arena
|
||||
// avoids significant amounts of unnecessary padding between C strings.
|
||||
XPTSubArena subarena8;
|
||||
XPTSubArena subarena1;
|
||||
};
|
||||
|
||||
XPT_PUBLIC_API(XPTArena *)
|
||||
XPT_NewArena(uint32_t block_size, size_t alignment, const char* name)
|
||||
XPT_NewArena(size_t block_size8, size_t block_size1)
|
||||
{
|
||||
XPTArena *arena = (XPTArena*)calloc(1, sizeof(XPTArena));
|
||||
XPTArena *arena = static_cast<XPTArena*>(calloc(1, sizeof(XPTArena)));
|
||||
if (arena) {
|
||||
XPT_ASSERT(alignment);
|
||||
if (alignment > sizeof(double))
|
||||
alignment = sizeof(double);
|
||||
arena->alignment = alignment;
|
||||
if (block_size8 < XPT_MIN_BLOCK_SIZE)
|
||||
block_size8 = XPT_MIN_BLOCK_SIZE;
|
||||
arena->subarena8.block_size = ALIGN_RND(block_size8, 8);
|
||||
|
||||
if (block_size < XPT_MIN_BLOCK_SIZE)
|
||||
block_size = XPT_MIN_BLOCK_SIZE;
|
||||
arena->block_size = ALIGN_RND(block_size, alignment);
|
||||
|
||||
/* must have room for at least one item! */
|
||||
XPT_ASSERT(arena->block_size >=
|
||||
ALIGN_RND(sizeof(BLK_HDR), alignment) +
|
||||
ALIGN_RND(1, alignment));
|
||||
|
||||
if (name) {
|
||||
arena->name = XPT_STRDUP(arena, name);
|
||||
#ifdef XPT_ARENA_LOGGING
|
||||
/* fudge the stats since we are using space in the arena */
|
||||
arena->LOG_MallocCallCount = 0;
|
||||
arena->LOG_MallocTotalBytesRequested = 0;
|
||||
arena->LOG_MallocTotalBytesUsed = 0;
|
||||
#endif /* XPT_ARENA_LOGGING */
|
||||
}
|
||||
if (block_size1 < XPT_MIN_BLOCK_SIZE)
|
||||
block_size1 = XPT_MIN_BLOCK_SIZE;
|
||||
arena->subarena1.block_size = block_size1;
|
||||
}
|
||||
return arena;
|
||||
}
|
||||
|
||||
static void
|
||||
DestroySubArena(XPTSubArena *subarena)
|
||||
{
|
||||
BLK_HDR* cur = subarena->first;
|
||||
while (cur) {
|
||||
BLK_HDR* next = cur->next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
return arena;
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(void)
|
||||
XPT_DestroyArena(XPTArena *arena)
|
||||
{
|
||||
BLK_HDR* cur;
|
||||
BLK_HDR* next;
|
||||
|
||||
cur = arena->first;
|
||||
while (cur) {
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
DestroySubArena(&arena->subarena8);
|
||||
DestroySubArena(&arena->subarena1);
|
||||
free(arena);
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(void)
|
||||
XPT_DumpStats(XPTArena *arena)
|
||||
{
|
||||
PRINT_STATS(arena);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Our alignment rule is that we always round up the size of each allocation
|
||||
* so that the 'arena->next' pointer one will point to properly aligned space.
|
||||
*/
|
||||
|
||||
XPT_PUBLIC_API(void *)
|
||||
XPT_ArenaMalloc(XPTArena *arena, size_t size)
|
||||
XPT_ArenaCalloc(XPTArena *arena, size_t size, size_t alignment)
|
||||
{
|
||||
uint8_t *cur;
|
||||
size_t bytes;
|
||||
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
@@ -175,124 +97,67 @@ XPT_ArenaMalloc(XPTArena *arena, size_t size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes = ALIGN_RND(size, arena->alignment);
|
||||
|
||||
LOG_MALLOC(arena, size, bytes);
|
||||
XPTSubArena *subarena;
|
||||
if (alignment == 8) {
|
||||
subarena = &arena->subarena8;
|
||||
} else if (alignment == 1) {
|
||||
subarena = &arena->subarena1;
|
||||
} else {
|
||||
XPT_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bytes > arena->space) {
|
||||
size_t bytes = ALIGN_RND(size, alignment);
|
||||
|
||||
if (bytes > subarena->space) {
|
||||
BLK_HDR* new_block;
|
||||
size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment);
|
||||
size_t new_space = arena->block_size;
|
||||
|
||||
while (bytes > new_space - block_header_size)
|
||||
new_space += arena->block_size;
|
||||
size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), alignment);
|
||||
size_t new_space = subarena->block_size;
|
||||
|
||||
new_block = (BLK_HDR*) calloc(new_space/arena->alignment,
|
||||
arena->alignment);
|
||||
while (bytes > new_space - block_header_size)
|
||||
new_space += subarena->block_size;
|
||||
|
||||
new_block =
|
||||
static_cast<BLK_HDR*>(calloc(new_space / alignment, alignment));
|
||||
if (!new_block) {
|
||||
arena->next = NULL;
|
||||
arena->space = 0;
|
||||
subarena->next = NULL;
|
||||
subarena->space = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_REAL_MALLOC(arena, new_space);
|
||||
|
||||
/* link block into the list of blocks for use when we destroy */
|
||||
new_block->next = arena->first;
|
||||
arena->first = new_block;
|
||||
|
||||
/* save other block header info */
|
||||
new_block->size = new_space;
|
||||
new_block->next = subarena->first;
|
||||
subarena->first = new_block;
|
||||
|
||||
/* set info for current block */
|
||||
arena->next = ((uint8_t*)new_block) + block_header_size;
|
||||
arena->space = new_space - block_header_size;
|
||||
subarena->next =
|
||||
reinterpret_cast<uint8_t*>(new_block) + block_header_size;
|
||||
subarena->space = new_space - block_header_size;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* mark block for corruption check */
|
||||
memset(arena->next, 0xcd, arena->space);
|
||||
memset(subarena->next, 0xcd, subarena->space);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
/* do corruption check */
|
||||
size_t i;
|
||||
for (i = 0; i < bytes; ++i) {
|
||||
XPT_ASSERT(arena->next[i] == 0xcd);
|
||||
XPT_ASSERT(subarena->next[i] == 0xcd);
|
||||
}
|
||||
/* we guarantee that the block will be filled with zeros */
|
||||
memset(arena->next, 0, bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
cur = arena->next;
|
||||
arena->next += bytes;
|
||||
arena->space -= bytes;
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
XPT_PUBLIC_API(char *)
|
||||
XPT_ArenaStrDup(XPTArena *arena, const char * s)
|
||||
{
|
||||
size_t len;
|
||||
char* cur;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
len = strlen(s)+1;
|
||||
cur = (char*)XPT_ArenaMalloc(arena, len);
|
||||
memcpy(cur, s, len);
|
||||
return cur;
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(void)
|
||||
XPT_NotifyDoneLoading(XPTArena *arena)
|
||||
{
|
||||
#ifdef XPT_ARENA_LOGGING
|
||||
if (arena) {
|
||||
LOG_DONE_LOADING(arena);
|
||||
memset(subarena->next, 0, bytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(void)
|
||||
XPT_ArenaFree(XPTArena *arena, void *block)
|
||||
{
|
||||
LOG_FREE(arena);
|
||||
}
|
||||
uint8_t* p = subarena->next;
|
||||
subarena->next += bytes;
|
||||
subarena->space -= bytes;
|
||||
|
||||
#ifdef XPT_ARENA_LOGGING
|
||||
static void xpt_DebugPrintArenaStats(XPTArena *arena)
|
||||
{
|
||||
printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
|
||||
printf("Start xpt arena stats for \"%s\"\n",
|
||||
arena->name ? arena->name : "unnamed arena");
|
||||
printf("\n");
|
||||
printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount);
|
||||
printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested);
|
||||
printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
|
||||
printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0);
|
||||
printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0);
|
||||
printf("\n");
|
||||
printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount);
|
||||
printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0));
|
||||
printf("\n");
|
||||
printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount);
|
||||
printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 ));
|
||||
printf("\n");
|
||||
printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount);
|
||||
printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested);
|
||||
printf("%d byte block size specified at arena creation time\n", (int) arena->block_size);
|
||||
printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment);
|
||||
printf("\n");
|
||||
printf("End xpt arena stats\n");
|
||||
printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n");
|
||||
}
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
@@ -306,25 +171,26 @@ XPT_AssertFailed(const char *s, const char *file, uint32_t lineno)
|
||||
}
|
||||
#endif
|
||||
|
||||
XPT_PUBLIC_API(size_t)
|
||||
XPT_SizeOfArena(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
|
||||
static size_t
|
||||
SizeOfSubArenaExcludingThis(XPTSubArena *subarena, MozMallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = mallocSizeOf(arena);
|
||||
size_t n = 0;
|
||||
|
||||
/*
|
||||
* We don't measure arena->name separately because it's allocated out of
|
||||
* the arena itself.
|
||||
*/
|
||||
|
||||
BLK_HDR* cur;
|
||||
BLK_HDR* next;
|
||||
|
||||
cur = arena->first;
|
||||
BLK_HDR* cur = subarena->first;
|
||||
while (cur) {
|
||||
next = cur->next;
|
||||
BLK_HDR* next = cur->next;
|
||||
n += mallocSizeOf(cur);
|
||||
cur = next;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(size_t)
|
||||
XPT_SizeOfArenaIncludingThis(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = mallocSizeOf(arena);
|
||||
n += SizeOfSubArenaExcludingThis(&arena->subarena8, mallocSizeOf);
|
||||
n += SizeOfSubArenaExcludingThis(&arena->subarena1, mallocSizeOf);
|
||||
return n;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user