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:
2024-03-10 21:39:46 +08:00
parent c6ee756140
commit 9d253b796d
105 changed files with 1274 additions and 3439 deletions
+1 -1
View File
@@ -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()
{
+2 -2
View File
@@ -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>
-18
View File
@@ -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>
-1
View File
@@ -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
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<script>
HTMLElement.prototype.__proto__ = Proxy.create({}, {});
HTMLElement.prototype.__proto__ = new Proxy({}, {});
try {
window.Image;
} finally {
+10 -8
View File
@@ -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)
+28
View File
@@ -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);
}
+12 -2
View File
@@ -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)
+1 -71
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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());
+14 -16
View File
@@ -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;
}
+61 -26
View File
@@ -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);
}
+6 -2
View File
@@ -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
+4
View File
@@ -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);
+47 -77
View File
@@ -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:
+8 -35
View File
@@ -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,
+11
View File
@@ -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))
)
+2 -2
View File
@@ -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})))
+12 -15
View File
@@ -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)))))
)
)`);
+2 -1
View File
@@ -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())
+1 -1
View File
@@ -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_;
+4 -3
View File
@@ -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
+26 -6
View File
@@ -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);
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -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',
-3
View File
@@ -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 */
+5 -4
View File
@@ -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.
+6 -4
View File
@@ -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()) {
+1 -15
View File
@@ -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
View File
@@ -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
+1 -5
View File
@@ -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
+1 -3
View File
@@ -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>
+19 -5
View File
@@ -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);
-59
View File
@@ -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)
+6 -1
View File
@@ -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();
}
}
}
+12
View File
@@ -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_ */
+2
View File
@@ -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",
+6
View File
@@ -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
+3 -1
View File
@@ -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);
-21
View File
@@ -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,
+6 -16
View File
@@ -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.
+3 -1
View File
@@ -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());
}
+5
View File
@@ -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',
]
+13 -44
View File
@@ -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);
}
+47 -48
View File
@@ -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() {
+53
View File
@@ -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) {
+8
View File
@@ -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;
+4 -1
View File
@@ -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)
+11 -8
View File
@@ -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;
}
+1 -1
View File
@@ -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 -5
View File
@@ -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
+6 -3
View File
@@ -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
View File
@@ -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; \
} \
+4 -2
View File
@@ -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)) {
+6 -1
View File
@@ -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___
+18
View File
@@ -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;
+2 -6
View File
@@ -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;
}
+2 -2
View File
@@ -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)) {
-1
View File
@@ -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.
+2 -2
View File
@@ -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)
+2
View File
@@ -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'
+1 -38
View File
@@ -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
+8 -3
View File
@@ -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) \
+14 -12
View File
@@ -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 = &param->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 = &param->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
+4 -5
View File
@@ -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);
}
+6 -4
View File
@@ -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
-1
View File
@@ -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));}
+5 -2
View File
@@ -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.
};
-127
View File
@@ -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;
}
-152
View File
@@ -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;
}
-14
View File
@@ -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
View File
@@ -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