diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a9638b048f..d31cc79e12 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -42,6 +42,7 @@ #include "WindowNamedPropertiesHandler.h" #include "nsFrameSelection.h" #include "nsNetUtil.h" +#include "nsIConsoleService.h" // Helper Classes #include "nsJSUtils.h" @@ -1564,6 +1565,12 @@ nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen) { NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); + // Prune messages related to this window in the console cache + nsCOMPtr console(do_GetService("@mozilla.org/consoleservice;1")); + if (console) { + console->ClearMessagesForWindowID(mWindowID); + } + // Make sure that this is called before we null out the document and // other members that the window destroyed observers could // re-create. diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 177626a04b..ff709ca78a 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -424,7 +424,20 @@ public: } if (status != nsEventStatus_eConsumeNoDefault) { - mReport->LogToConsole(); + if (mError.isObject()) { + AutoJSAPI jsapi; + if (NS_WARN_IF(!jsapi.Init(mError.toObjectOrNull()))) { + mReport->LogToConsole(); + return NS_OK; + } + JSContext* cx = jsapi.cx(); + JS::Rooted exObj(cx, mError.toObjectOrNull()); + JS::RootedObject stack(cx, ExceptionStackOrNull(cx, exObj)); + mReport->LogToConsoleWithStack(stack); + } else { + mReport->LogToConsole(); + } + } return NS_OK; @@ -502,7 +515,14 @@ SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) if (!win || JSREPORT_IS_WARNING(xpcReport->mFlags) || report->errorNumber == JSMSG_OUT_OF_MEMORY) { - xpcReport->LogToConsole(); + if (exception.isObject()) { + JS::RootedObject exObj(cx, exception.toObjectOrNull()); + JSAutoCompartment ac(cx, exObj); + JS::RootedObject stackVal(cx, ExceptionStackOrNull(cx, exObj)); + xpcReport->LogToConsoleWithStack(stackVal); + } else { + xpcReport->LogToConsole(); + } return; } diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index 0c06b9e042..be5bef3b79 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -14,6 +14,7 @@ namespace js { class BaseShape; class LazyScript; class ObjectGroup; +class Shape; namespace jit { class JitCode; } // namespace jit diff --git a/js/public/TraceableVector.h b/js/public/TraceableVector.h index 14c5ff2d0c..2be4860ac0 100644 --- a/js/public/TraceableVector.h +++ b/js/public/TraceableVector.h @@ -67,9 +67,12 @@ class TraceableVectorOperations size_t capacity() const { return vec().capacity(); } const T* begin() const { return vec().begin(); } const T* end() const { return vec().end(); } - const T& operator[](size_t aIndex) const { return vec().operator[](aIndex); } const T& back() const { return vec().back(); } bool canAppendWithoutRealloc(size_t aNeeded) const { return vec().canAppendWithoutRealloc(); } + + JS::Handle operator[](size_t aIndex) const { + return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); + } }; template @@ -88,10 +91,13 @@ class MutableTraceableVectorOperations const T* end() const { return vec().end(); } T* end() { return vec().end(); } const T& operator[](size_t aIndex) const { return vec().operator[](aIndex); } - T& operator[](size_t aIndex) { return vec().operator[](aIndex); } const T& back() const { return vec().back(); } T& back() { return vec().back(); } + JS::MutableHandle operator[](size_t aIndex) { + return JS::MutableHandle::fromMarkedLocation(&vec().operator[](aIndex)); + } + bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); } bool reserve(size_t aRequest) { return vec().reserve(aRequest); } void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index a2e792cf23..71c8009043 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -13,6 +13,7 @@ // These includes are needed these for some typedefs (e.g. HandleValue) and // functions (e.g. NullValue())... #include "js/CallNonGenericMethod.h" +#include "js/TraceableVector.h" #include "js/TypeDecls.h" #include "js/Value.h" @@ -33,7 +34,6 @@ class AutoVectorRooter; typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoVector; class AutoIdArray; @@ -81,9 +81,12 @@ using JS::AutoVectorRooter; typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoScriptVector; +using ValueVector = TraceableVector; +using IdVector = TraceableVector; +using ScriptVector = TraceableVector; + using JS::AutoIdArray; using JS::AutoHashMapRooter; @@ -99,6 +102,7 @@ using JS::NativeImpl; using JS::OwningCompileOptions; using JS::ReadOnlyCompileOptions; using JS::SourceBufferHolder; +using JS::TransitiveCompileOptions; using JS::Rooted; using JS::RootedFunction; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index d34aa41f56..c4290ca0d0 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5942,13 +5942,13 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript); - // Inherit most things (principals, version, etc) from the parent. + // Inherit most things (principals, version, etc) from the + // parent. Use default values for the rest. Rooted parent(cx, script); - CompileOptions options(cx, parser->options()); - options.setMutedErrors(parent->mutedErrors()) - .setNoScriptRval(false) - .setForEval(false) - .setVersion(parent->getVersion()); + MOZ_ASSERT(parent->getVersion() == parser->options().version); + MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors()); + const TransitiveCompileOptions& transitiveOptions = parser->options(); + CompileOptions options(cx, transitiveOptions); Rooted enclosingScope(cx, enclosingStaticScope()); Rooted sourceObject(cx, script->sourceObject()); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 8e1bb4288d..aa690320f1 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -232,7 +232,7 @@ struct ParseContext : public GenericParseContext the same name. */ // All inner functions in this context. Only filled in when parsing syntax. - AutoFunctionVector innerFunctions; + Rooted> innerFunctions; // In a function context, points to a Directive struct that can be updated // to reflect new directives encountered in the Directive Prologue that @@ -273,7 +273,7 @@ struct ParseContext : public GenericParseContext oldpc(prs->pc), lexdeps(prs->context), funcStmts(nullptr), - innerFunctions(prs->context), + innerFunctions(prs->context, TraceableVector(prs->context)), newDirectives(newDirectives), inDeclDestructuring(false) { diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 6a3c966af1..511de719f3 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -140,14 +140,6 @@ AutoGCRooter::trace(JSTracer* trc) return; } - case DESCVECTOR: { - AutoPropertyDescriptorVector::VectorImpl &descriptors = - static_cast(this)->vector; - for (size_t i = 0, len = descriptors.length(); i < len; i++) - descriptors[i].trace(trc); - return; - } - case VALVECTOR: { AutoValueVector::VectorImpl& vector = static_cast(this)->vector; TraceRootRange(trc, vector.length(), vector.begin(), "JS::AutoValueVector.vector"); @@ -169,13 +161,6 @@ AutoGCRooter::trace(JSTracer* trc) return; } - case SHAPEVECTOR: { - AutoShapeVector::VectorImpl& vector = static_cast(this)->vector; - TraceRootRange(trc, vector.length(), const_cast(vector.begin()), - "js::AutoShapeVector.vector"); - return; - } - case OBJVECTOR: { AutoObjectVector::VectorImpl& vector = static_cast(this)->vector; TraceRootRange(trc, vector.length(), vector.begin(), "JS::AutoObjectVector.vector"); @@ -210,18 +195,6 @@ AutoGCRooter::trace(JSTracer* trc) return; } - case OBJU32HASHMAP: { - AutoObjectUnsigned32HashMap* self = static_cast(this); - AutoObjectUnsigned32HashMap::HashMapImpl& map = self->map; - for (AutoObjectUnsigned32HashMap::Enum e(map); !e.empty(); e.popFront()) { - JSObject* key = e.front().key(); - TraceRoot(trc, &key, "AutoObjectUnsignedHashMap key"); - if (key != e.front().key()) - e.rekeyFront(key); - } - return; - } - case HASHABLEVALUE: { AutoHashableValueRooter* rooter = static_cast(this); rooter->trace(trc); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index fc86757f94..ecf2fee77a 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -26,6 +26,7 @@ #include "jit/SharedICHelpers.h" #include "jit/VMFunctions.h" #include "js/Conversions.h" +#include "js/TraceableVector.h" #include "vm/Opcodes.h" #include "vm/TypedArrayCommon.h" @@ -4059,11 +4060,11 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm) } static bool -GetProtoShapes(JSObject* obj, size_t protoChainDepth, AutoShapeVector* shapes) +GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle shapes) { JSObject* curProto = obj->getProto(); for (size_t i = 0; i < protoChainDepth; i++) { - if (!shapes->append(curProto->as().lastProperty())) + if (!shapes.append(curProto->as().lastProperty())) return false; curProto = curProto->getProto(); } @@ -4078,7 +4079,7 @@ GetProtoShapes(JSObject* obj, size_t protoChainDepth, AutoShapeVector* shapes) ICUpdatedStub* ICSetElemDenseOrUnboxedArrayAddCompiler::getStub(ICStubSpace* space) { - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!shapes.append(obj_->maybeShape())) return nullptr; @@ -4089,11 +4090,11 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::getStub(ICStubSpace* space) ICUpdatedStub* stub = nullptr; switch (protoChainDepth_) { - case 0: stub = getStubSpecific<0>(space, &shapes); break; - case 1: stub = getStubSpecific<1>(space, &shapes); break; - case 2: stub = getStubSpecific<2>(space, &shapes); break; - case 3: stub = getStubSpecific<3>(space, &shapes); break; - case 4: stub = getStubSpecific<4>(space, &shapes); break; + case 0: stub = getStubSpecific<0>(space, shapes); break; + case 1: stub = getStubSpecific<1>(space, shapes); break; + case 2: stub = getStubSpecific<2>(space, shapes); break; + case 3: stub = getStubSpecific<3>(space, shapes); break; + case 4: stub = getStubSpecific<4>(space, shapes); break; default: MOZ_CRASH("ProtoChainDepth too high."); } if (!stub || !stub->initUpdatingChain(cx, space)) @@ -4672,7 +4673,7 @@ ICInNativeCompiler::generateStubCode(MacroAssembler &masm) ICStub* ICInNativeDoesNotExistCompiler::getStub(ICStubSpace* space) { - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!shapes.append(obj_->as().lastProperty())) return nullptr; @@ -4683,15 +4684,15 @@ ICInNativeDoesNotExistCompiler::getStub(ICStubSpace* space) ICStub* stub = nullptr; switch (protoChainDepth_) { - case 0: stub = getStubSpecific<0>(space, &shapes); break; - case 1: stub = getStubSpecific<1>(space, &shapes); break; - case 2: stub = getStubSpecific<2>(space, &shapes); break; - case 3: stub = getStubSpecific<3>(space, &shapes); break; - case 4: stub = getStubSpecific<4>(space, &shapes); break; - case 5: stub = getStubSpecific<5>(space, &shapes); break; - case 6: stub = getStubSpecific<6>(space, &shapes); break; - case 7: stub = getStubSpecific<7>(space, &shapes); break; - case 8: stub = getStubSpecific<8>(space, &shapes); break; + case 0: stub = getStubSpecific<0>(space, shapes); break; + case 1: stub = getStubSpecific<1>(space, shapes); break; + case 2: stub = getStubSpecific<2>(space, shapes); break; + case 3: stub = getStubSpecific<3>(space, shapes); break; + case 4: stub = getStubSpecific<4>(space, shapes); break; + case 5: stub = getStubSpecific<5>(space, shapes); break; + case 6: stub = getStubSpecific<6>(space, shapes); break; + case 7: stub = getStubSpecific<7>(space, shapes); break; + case 8: stub = getStubSpecific<8>(space, shapes); break; default: MOZ_CRASH("ProtoChainDepth too high."); } if (!stub) @@ -5030,7 +5031,7 @@ TryAttachScopeNameStub(JSContext* cx, HandleScript script, ICGetName_Fallback* s { MOZ_ASSERT(!*attached); - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); RootedId id(cx, NameToId(name)); RootedObject scopeChain(cx, initialScopeChain); @@ -5075,37 +5076,44 @@ TryAttachScopeNameStub(JSContext* cx, HandleScript script, ICGetName_Fallback* s switch (shapes.length()) { case 1: { - ICGetName_Scope<0>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<0>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 2: { - ICGetName_Scope<1>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<1>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 3: { - ICGetName_Scope<2>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<2>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 4: { - ICGetName_Scope<3>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<3>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 5: { - ICGetName_Scope<4>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<4>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 6: { - ICGetName_Scope<5>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<5>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } case 7: { - ICGetName_Scope<6>::Compiler compiler(cx, monitorStub, &shapes, isFixedSlot, offset); + ICGetName_Scope<6>::Compiler compiler(cx, monitorStub, Move(shapes.get()), isFixedSlot, + offset); newStub = compiler.getStub(compiler.getStubSpace(script)); break; } @@ -6504,7 +6512,7 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm) ICStub* ICGetPropNativeDoesNotExistCompiler::getStub(ICStubSpace* space) { - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!GetProtoShapes(obj_, protoChainDepth_, &shapes)) return nullptr; @@ -6513,15 +6521,15 @@ ICGetPropNativeDoesNotExistCompiler::getStub(ICStubSpace* space) ICStub* stub = nullptr; switch(protoChainDepth_) { - case 0: stub = getStubSpecific<0>(space, &shapes); break; - case 1: stub = getStubSpecific<1>(space, &shapes); break; - case 2: stub = getStubSpecific<2>(space, &shapes); break; - case 3: stub = getStubSpecific<3>(space, &shapes); break; - case 4: stub = getStubSpecific<4>(space, &shapes); break; - case 5: stub = getStubSpecific<5>(space, &shapes); break; - case 6: stub = getStubSpecific<6>(space, &shapes); break; - case 7: stub = getStubSpecific<7>(space, &shapes); break; - case 8: stub = getStubSpecific<8>(space, &shapes); break; + case 0: stub = getStubSpecific<0>(space, shapes); break; + case 1: stub = getStubSpecific<1>(space, shapes); break; + case 2: stub = getStubSpecific<2>(space, shapes); break; + case 3: stub = getStubSpecific<3>(space, shapes); break; + case 4: stub = getStubSpecific<4>(space, shapes); break; + case 5: stub = getStubSpecific<5>(space, shapes); break; + case 6: stub = getStubSpecific<6>(space, shapes); break; + case 7: stub = getStubSpecific<7>(space, shapes); break; + case 8: stub = getStubSpecific<8>(space, shapes); break; default: MOZ_CRASH("ProtoChainDepth too high."); } if (!stub) @@ -7757,7 +7765,7 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler& masm) ICUpdatedStub* ICSetPropNativeAddCompiler::getStub(ICStubSpace* space) { - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!shapes.append(oldShape_)) return nullptr; @@ -7768,11 +7776,11 @@ ICSetPropNativeAddCompiler::getStub(ICStubSpace* space) ICUpdatedStub* stub = nullptr; switch(protoChainDepth_) { - case 0: stub = getStubSpecific<0>(space, &shapes); break; - case 1: stub = getStubSpecific<1>(space, &shapes); break; - case 2: stub = getStubSpecific<2>(space, &shapes); break; - case 3: stub = getStubSpecific<3>(space, &shapes); break; - case 4: stub = getStubSpecific<4>(space, &shapes); break; + case 0: stub = getStubSpecific<0>(space, shapes); break; + case 1: stub = getStubSpecific<1>(space, shapes); break; + case 2: stub = getStubSpecific<2>(space, shapes); break; + case 3: stub = getStubSpecific<3>(space, shapes); break; + case 4: stub = getStubSpecific<4>(space, shapes); break; default: MOZ_CRASH("ProtoChainDepth too high."); } if (!stub || !stub->initUpdatingChain(cx, space)) @@ -11210,7 +11218,8 @@ ICSetElem_DenseOrUnboxedArrayAdd::ICSetElem_DenseOrUnboxedArrayAdd(JitCode* stub template ICUpdatedStub* -ICSetElemDenseOrUnboxedArrayAddCompiler::getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes) +ICSetElemDenseOrUnboxedArrayAddCompiler::getStubSpecific(ICStubSpace* space, + Handle shapes) { RootedObjectGroup group(cx, obj_->getGroup(cx)); if (!group) @@ -11264,12 +11273,12 @@ ICIn_NativeDoesNotExist::offsetOfShape(size_t idx) template ICIn_NativeDoesNotExistImpl::ICIn_NativeDoesNotExistImpl( - JitCode* stubCode, const AutoShapeVector* shapes, HandlePropertyName name) + JitCode* stubCode, Handle shapes, HandlePropertyName name) : ICIn_NativeDoesNotExist(stubCode, ProtoChainDepth, name) { - MOZ_ASSERT(shapes->length() == NumShapes); + MOZ_ASSERT(shapes.length() == NumShapes); for (size_t i = 0; i < NumShapes; i++) - shapes_[i].init((*shapes)[i]); + shapes_[i].init(shapes[i]); } ICInNativeDoesNotExistCompiler::ICInNativeDoesNotExistCompiler( @@ -11296,14 +11305,14 @@ ICGetName_Global::ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, template ICGetName_Scope::ICGetName_Scope(JitCode* stubCode, ICStub* firstMonitorStub, - AutoShapeVector* shapes, uint32_t offset) + Handle shapes, uint32_t offset) : ICMonitoredStub(GetStubKind(), stubCode, firstMonitorStub), offset_(offset) { JS_STATIC_ASSERT(NumHops <= MAX_HOPS); - MOZ_ASSERT(shapes->length() == NumHops + 1); + MOZ_ASSERT(shapes.length() == NumHops + 1); for (size_t i = 0; i < NumHops + 1; i++) - shapes_[i].init((*shapes)[i]); + shapes_[i].init(shapes[i]); } ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value) @@ -11380,14 +11389,14 @@ ICGetProp_NativeDoesNotExist::offsetOfShape(size_t idx) template ICGetProp_NativeDoesNotExistImpl::ICGetProp_NativeDoesNotExistImpl( JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, - const AutoShapeVector* shapes) + Handle shapes) : ICGetProp_NativeDoesNotExist(stubCode, firstMonitorStub, guard, ProtoChainDepth) { - MOZ_ASSERT(shapes->length() == NumShapes); + MOZ_ASSERT(shapes.length() == NumShapes); // Note: using int32_t here to avoid gcc warning. for (int32_t i = 0; i < int32_t(NumShapes); i++) - shapes_[i].init((*shapes)[i]); + shapes_[i].init(shapes[i]); } ICGetPropNativeDoesNotExistCompiler::ICGetPropNativeDoesNotExistCompiler( @@ -11484,15 +11493,15 @@ ICSetProp_NativeAdd::ICSetProp_NativeAdd(JitCode* stubCode, ObjectGroup* group, template ICSetProp_NativeAddImpl::ICSetProp_NativeAddImpl(JitCode* stubCode, ObjectGroup* group, - const AutoShapeVector* shapes, + Handle shapes, Shape* newShape, ObjectGroup* newGroup, uint32_t offset) : ICSetProp_NativeAdd(stubCode, group, ProtoChainDepth, newShape, newGroup, offset) { - MOZ_ASSERT(shapes->length() == NumShapes); + MOZ_ASSERT(shapes.length() == NumShapes); for (size_t i = 0; i < NumShapes; i++) - shapes_[i].init((*shapes)[i]); + shapes_[i].init(shapes[i]); } ICSetPropNativeAddCompiler::ICSetPropNativeAddCompiler(JSContext* cx, HandleObject obj, diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 77ef390a52..f5d3753ea6 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -19,6 +19,7 @@ #include "jit/BaselineJIT.h" #include "jit/SharedIC.h" #include "jit/SharedICRegisters.h" +#include "js/TraceableVector.h" #include "vm/ArrayObject.h" #include "vm/ReceiverGuard.h" #include "vm/TypedArrayCommon.h" @@ -1691,12 +1692,12 @@ class ICSetElem_DenseOrUnboxedArrayAddImpl : public ICSetElem_DenseOrUnboxedArra mozilla::Array shapes_; ICSetElem_DenseOrUnboxedArrayAddImpl(JitCode* stubCode, ObjectGroup* group, - const AutoShapeVector* shapes) + Handle shapes) : ICSetElem_DenseOrUnboxedArrayAdd(stubCode, group, ProtoChainDepth) { - MOZ_ASSERT(shapes->length() == NumShapes); + MOZ_ASSERT(shapes.length() == NumShapes); for (size_t i = 0; i < NumShapes; i++) - shapes_[i].init((*shapes)[i]); + shapes_[i].init(shapes[i]); } public: @@ -1741,7 +1742,7 @@ class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler { {} template - ICUpdatedStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes); + ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle shapes); ICUpdatedStub* getStub(ICStubSpace* space); @@ -1984,7 +1985,7 @@ class ICIn_NativeDoesNotExistImpl : public ICIn_NativeDoesNotExist private: mozilla::Array shapes_; - ICIn_NativeDoesNotExistImpl(JitCode* stubCode, const AutoShapeVector* shapes, + ICIn_NativeDoesNotExistImpl(JitCode* stubCode, Handle shapes, HandlePropertyName name); public: @@ -2018,7 +2019,7 @@ class ICInNativeDoesNotExistCompiler : public ICStubCompiler size_t protoChainDepth); template - ICStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes) { + ICStub* getStubSpecific(ICStubSpace* space, Handle shapes) { return newStub>(space, getStubCode(), shapes, name_);} @@ -2159,7 +2160,7 @@ class ICGetName_Scope : public ICMonitoredStub uint32_t offset_; ICGetName_Scope(JitCode* stubCode, ICStub* firstMonitorStub, - AutoShapeVector* shapes, uint32_t offset); + Handle shapes, uint32_t offset); static Kind GetStubKind() { return (Kind) (GetName_Scope0 + NumHops); @@ -2181,7 +2182,7 @@ class ICGetName_Scope : public ICMonitoredStub class Compiler : public ICStubCompiler { ICStub* firstMonitorStub_; - AutoShapeVector* shapes_; + Rooted shapes_; bool isFixedSlot_; uint32_t offset_; @@ -2197,10 +2198,10 @@ class ICGetName_Scope : public ICMonitoredStub public: Compiler(JSContext* cx, ICStub* firstMonitorStub, - AutoShapeVector* shapes, bool isFixedSlot, uint32_t offset) + ShapeVector&& shapes, bool isFixedSlot, uint32_t offset) : ICStubCompiler(cx, GetStubKind(), Engine::Baseline), firstMonitorStub_(firstMonitorStub), - shapes_(shapes), + shapes_(cx, mozilla::Forward(shapes)), isFixedSlot_(isFixedSlot), offset_(offset) { @@ -2707,7 +2708,7 @@ class ICGetProp_NativeDoesNotExistImpl : public ICGetProp_NativeDoesNotExist ICGetProp_NativeDoesNotExistImpl(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, - const AutoShapeVector* shapes); + Handle shapes); public: void traceShapes(JSTracer* trc) { @@ -2742,7 +2743,7 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler HandleObject obj, size_t protoChainDepth); template - ICStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes) { + ICStub* getStubSpecific(ICStubSpace* space, Handle shapes) { ReceiverGuard guard(obj_); return newStub> (space, getStubCode(), firstMonitorStub_, guard, shapes); @@ -3468,7 +3469,7 @@ class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd mozilla::Array shapes_; ICSetProp_NativeAddImpl(JitCode* stubCode, ObjectGroup* group, - const AutoShapeVector* shapes, + Handle shapes, Shape* newShape, ObjectGroup* newGroup, uint32_t offset); public: @@ -3508,7 +3509,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler size_t protoChainDepth, bool isFixedSlot, uint32_t offset); template - ICUpdatedStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes) + ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle shapes) { RootedObjectGroup newGroup(cx, obj_->getGroup(cx)); if (!newGroup) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f43c35cf8b..16d24df460 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3820,18 +3820,13 @@ AutoFile::open(JSContext* cx, const char* filename) return true; } -JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr; - void -JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs) +JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOptions& rhs) { + mutedErrors_ = rhs.mutedErrors_; version = rhs.version; versionSet = rhs.versionSet; utf8 = rhs.utf8; - lineno = rhs.lineno; - column = rhs.column; - forEval = rhs.forEval; - noScriptRval = rhs.noScriptRval; selfHostingMode = rhs.selfHostingMode; canLazilyParse = rhs.canLazilyParse; strictOption = rhs.strictOption; @@ -3845,6 +3840,17 @@ JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs) introductionLineno = rhs.introductionLineno; introductionOffset = rhs.introductionOffset; hasIntroductionInfo = rhs.hasIntroductionInfo; +}; + +void +JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs) +{ + copyPODTransitiveOptions(rhs); + lineno = rhs.lineno; + column = rhs.column; + isRunOnce = rhs.isRunOnce; + forEval = rhs.forEval; + noScriptRval = rhs.noScriptRval; } JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx) @@ -3869,7 +3875,6 @@ JS::OwningCompileOptions::copy(JSContext* cx, const ReadOnlyCompileOptions& rhs) { copyPODOptions(rhs); - setMutedErrors(rhs.mutedErrors()); setElement(rhs.element()); setElementAttributeName(rhs.elementAttributeName()); setIntroductionScript(rhs.introductionScript()); @@ -4277,8 +4282,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, MOZ_ASSERT_IF(!enclosingDynamicScope->is(), HasNonSyntacticStaticScopeChain(enclosingStaticScope)); - CompileOptions options(cx, optionsArg); - if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingStaticScope)) + if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingStaticScope)) return false; return true; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index a708191112..4c40fa2457 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -29,6 +29,7 @@ #include "js/Id.h" #include "js/Principals.h" #include "js/RootingAPI.h" +#include "js/TraceableVector.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Value.h" @@ -215,9 +216,12 @@ class MOZ_STACK_CLASS AutoVectorRooter : public AutoVectorRooterBase typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; -typedef AutoVectorRooter AutoFunctionVector; typedef AutoVectorRooter AutoScriptVector; +using ValueVector = js::TraceableVector; +using IdVector = js::TraceableVector; +using ScriptVector = js::TraceableVector; + template class AutoHashMapRooter : protected AutoGCRooter { @@ -3376,10 +3380,20 @@ namespace JS { * it doesn't care who owns them, or what's keeping them alive. It does its own * addrefs/copies/tracing/etc. * - * So, we have a class hierarchy that reflects these three use cases: + * Furthermore, in some cases compile options are propagated from one entity to + * another (e.g. from a scriipt to a function defined in that script). This + * involves copying over some, but not all, of the options. * - * - ReadOnlyCompileOptions is the common base class. It can be used by code - * that simply needs to access options set elsewhere, like the compiler. + * So, we have a class hierarchy that reflects these four use cases: + * + * - TransitiveCompileOptions is the common base class, representing options + * that should get propagated from a script to functions defined in that + * script. This is never instantiated directly. + * + * - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions, + * representing a full set of compile options. It can be used by code that + * simply needs to access options set elsewhere, like the compiler. This, + * again, is never instantiated directly. * * - The usual CompileOptions class must be stack-allocated, and holds * non-owning references to the filename, element, and so on. It's derived @@ -3393,15 +3407,11 @@ namespace JS { /* * The common base class for the CompileOptions hierarchy. * - * Use this in code that only needs to access compilation options created - * elsewhere, like the compiler. Don't instantiate this class (the constructor - * is protected anyway); instead, create instances only of the derived classes: - * CompileOptions and OwningCompileOptions. + * Use this in code that needs to propagate compile options from one compilation + * unit to another. */ -class JS_FRIEND_API(ReadOnlyCompileOptions) +class JS_FRIEND_API(TransitiveCompileOptions) { - friend class CompileOptions; - protected: // The Web Platform allows scripts to be loaded from arbitrary cross-origin // sources. This allows an attack by which a malicious website loads a @@ -3423,7 +3433,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) // is unusable until that's set to something more specific; the derived // classes' constructors take care of that, in ways appropriate to their // purpose. - ReadOnlyCompileOptions() + TransitiveCompileOptions() : mutedErrors_(false), filename_(nullptr), introducerFilename_(nullptr), @@ -3431,11 +3441,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) version(JSVERSION_UNKNOWN), versionSet(false), utf8(false), - lineno(1), - column(0), - isRunOnce(false), - forEval(false), - noScriptRval(false), selfHostingMode(false), canLazilyParse(true), strictOption(false), @@ -3453,7 +3458,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) // Set all POD options (those not requiring reference counts, copies, // rooting, or other hand-holding) to their values in |rhs|. - void copyPODOptions(const ReadOnlyCompileOptions& rhs); + void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); public: // Read-only accessors for non-POD options. The proper way to set these @@ -3470,12 +3475,6 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) JSVersion version; bool versionSet; bool utf8; - unsigned lineno; - unsigned column; - // isRunOnce only applies to non-function scripts. - bool isRunOnce; - bool forEval; - bool noScriptRval; bool selfHostingMode; bool canLazilyParse; bool strictOption; @@ -3494,7 +3493,55 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) bool hasIntroductionInfo; private: - static JSObject * const nullObjectPtr; + void operator=(const TransitiveCompileOptions&) = delete; +}; + +/* + * The class representing a full set of compile options. + * + * Use this in code that only needs to access compilation options created + * elsewhere, like the compiler. Don't instantiate this class (the constructor + * is protected anyway); instead, create instances only of the derived classes: + * CompileOptions and OwningCompileOptions. + */ +class JS_FRIEND_API(ReadOnlyCompileOptions) : public TransitiveCompileOptions +{ + friend class CompileOptions; + + protected: + ReadOnlyCompileOptions() + : TransitiveCompileOptions(), + lineno(1), + column(0), + isRunOnce(false), + forEval(false), + noScriptRval(false) + { } + + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODOptions(const ReadOnlyCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const = 0; + virtual JSString* elementAttributeName() const = 0; + virtual JSScript* introductionScript() const = 0; + + // POD options. + unsigned lineno; + unsigned column; + // isRunOnce only applies to non-function scripts. + bool isRunOnce; + bool forEval; + bool noScriptRval; + + private: void operator=(const ReadOnlyCompileOptions&) = delete; }; @@ -3609,8 +3656,22 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti { copyPODOptions(rhs); - mutedErrors_ = rhs.mutedErrors_; filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + } + + CompileOptions(js::ContextFriendFields* cx, const TransitiveCompileOptions& rhs) + : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), + introductionScriptRoot(cx) + { + copyPODTransitiveOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); sourceMapURL_ = rhs.sourceMapURL(); elementRoot = rhs.element(); elementAttributeNameRoot = rhs.elementAttributeName(); @@ -4917,6 +4978,9 @@ JS_DropExceptionState(JSContext* cx, JSExceptionState* state); extern JS_PUBLIC_API(JSErrorReport*) JS_ErrorFromException(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API(JSObject*) +ExceptionStackOrNull(JSContext* cx, JS::HandleObject obj); + /* * Throws a StopIteration exception on cx. */ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1e96b78159..333600f0b6 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -11,6 +11,7 @@ #include "mozilla/MemoryReporting.h" +#include "js/TraceableVector.h" #include "js/Vector.h" #include "vm/Runtime.h" @@ -664,20 +665,8 @@ CheckForInterrupt(JSContext* cx) typedef JS::AutoVectorRooter AutoStringVector; typedef JS::AutoVectorRooter AutoPropertyNameVector; -typedef JS::AutoVectorRooter AutoShapeVector; -class AutoObjectUnsigned32HashMap : public AutoHashMapRooter -{ - public: - explicit AutoObjectUnsigned32HashMap(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoHashMapRooter(cx, OBJU32HASHMAP) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; +using ShapeVector = js::TraceableVector; /* AutoArrayRooter roots an external array of Values. */ class AutoArrayRooter : private JS::AutoGCRooter diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 44ac51ce1b..27435a8f4d 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -323,6 +323,20 @@ js::ErrorFromException(JSContext* cx, HandleObject objArg) return obj->as().getOrCreateErrorReport(cx); } +JS_PUBLIC_API(JSObject*) +ExceptionStackOrNull(JSContext* cx, HandleObject objArg) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, objArg); + RootedObject obj(cx, CheckedUnwrap(objArg)); + if (!obj || !obj->is()) { + return nullptr; + } + + return obj->as().stack(); +} + bool Error(JSContext* cx, unsigned argc, Value* vp) { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 1ca71a3639..60ed799547 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -443,7 +443,7 @@ js::CompletePropertyDescriptor(MutableHandle desc) bool js::ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors, - AutoIdVector* ids, AutoPropertyDescriptorVector* descs) + AutoIdVector* ids, MutableHandle descs) { if (!GetPropertyKeys(cx, props, JSITER_OWNONLY | JSITER_SYMBOLS, ids)) return false; @@ -455,7 +455,7 @@ js::ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccesso RootedValue v(cx); if (!GetProperty(cx, props, props, id, &v) || !ToPropertyDescriptor(cx, v, checkAccessors, &desc) || - !descs->append(desc)) + !descs.append(desc)) { return false; } @@ -467,7 +467,7 @@ bool js::DefineProperties(JSContext* cx, HandleObject obj, HandleObject props) { AutoIdVector ids(cx); - AutoPropertyDescriptorVector descs(cx); + Rooted descs(cx, PropertyDescriptorVector(cx)); if (!ReadPropertyDescriptors(cx, props, true, &ids, &descs)) return false; @@ -527,15 +527,15 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) return false; // Get an in-order list of the shapes in this object. - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); for (Shape::Range r(nobj->lastProperty()); !r.empty(); r.popFront()) { if (!shapes.append(&r.front())) return false; } Reverse(shapes.begin(), shapes.end()); - for (size_t i = 0; i < shapes.length(); i++) { - StackShape unrootedChild(shapes[i]); + for (Shape* shape : shapes) { + StackShape unrootedChild(shape); RootedGeneric child(cx, &unrootedChild); child->attrs |= GetSealedOrFrozenAttributes(child->attrs, level); @@ -1362,15 +1362,15 @@ InitializePropertiesFromCompatibleNativeObject(JSContext* cx, return false; // Get an in-order list of the shapes in the src object. - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); for (Shape::Range r(src->lastProperty()); !r.empty(); r.popFront()) { if (!shapes.append(&r.front())) return false; } Reverse(shapes.begin(), shapes.end()); - for (size_t i = 0; i < shapes.length(); i++) { - StackShape unrootedChild(shapes[i]); + for (Shape* shape : shapes) { + StackShape unrootedChild(shape); RootedGeneric child(cx, &unrootedChild); shape = cx->compartment()->propertyTree.getChild(cx, shape, *child); if (!shape) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 0f5c6266a8..e89766b457 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -23,6 +23,7 @@ #include "js/Conversions.h" #include "js/GCAPI.h" #include "js/HeapAPI.h" +#include "js/TraceableVector.h" #include "vm/Shape.h" #include "vm/String.h" #include "vm/Xdr.h" @@ -33,7 +34,7 @@ struct ClassInfo; namespace js { -typedef AutoVectorRooter AutoPropertyDescriptorVector; +using PropertyDescriptorVector = TraceableVector; class GCMarker; class Nursery; @@ -1166,7 +1167,7 @@ CompletePropertyDescriptor(MutableHandle desc); */ extern bool ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors, - AutoIdVector* ids, AutoPropertyDescriptorVector* descs); + AutoIdVector* ids, MutableHandle descs); /* Read the name using a dynamic lookup on the scopeChain. */ extern bool diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 4939b9bb10..e322a01c76 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -622,8 +622,6 @@ IsInternalFunctionObject(JSObject* funobj) return fun->isLambda() && fun->isInterpreted() && !fun->environment(); } -typedef AutoVectorRooter AutoPropertyDescriptorVector; - /* * Make an object with the specified prototype. If parent is null, it will * default to the prototype's global if the prototype is non-null. diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index f36727c26a..088f5bfa65 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -37,6 +37,7 @@ class Rooted; class JS_FRIEND_API(CompileOptions); class JS_FRIEND_API(ReadOnlyCompileOptions); class JS_FRIEND_API(OwningCompileOptions); +class JS_FRIEND_API(TransitiveCompileOptions); class JS_PUBLIC_API(CompartmentOptions); class Value; @@ -47,7 +48,6 @@ struct Zone; namespace js { struct ContextFriendFields; class RootLists; -class Shape; } // namespace js /* @@ -219,9 +219,7 @@ class JS_PUBLIC_API(AutoGCRooter) enum { VALARRAY = -2, /* js::AutoValueArray */ PARSER = -3, /* js::frontend::Parser */ - SHAPEVECTOR = -4, /* js::AutoShapeVector */ IDARRAY = -6, /* js::AutoIdArray */ - DESCVECTOR = -7, /* js::AutoPropertyDescriptorVector */ VALVECTOR = -10, /* js::AutoValueVector */ IDVECTOR = -11, /* js::AutoIdVector */ IDVALVECTOR = -12, /* js::AutoIdValueVector */ @@ -233,7 +231,6 @@ class JS_PUBLIC_API(AutoGCRooter) IONMASM = -19, /* js::jit::MacroAssembler */ WRAPVECTOR = -20, /* js::AutoWrapperVector */ WRAPPER = -21, /* js::AutoWrapperRooter */ - OBJU32HASHMAP=-23, /* js::AutoObjectUnsigned32HashMap */ JSONPARSER = -25, /* js::JSONParser */ CUSTOM = -26 /* js::CustomAutoRooter */ }; @@ -243,8 +240,6 @@ class JS_PUBLIC_API(AutoGCRooter) static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; } static ptrdiff_t GetTag(JSScript* script) { return SCRIPTVECTOR; } static ptrdiff_t GetTag(JSString* string) { return STRINGVECTOR; } - static ptrdiff_t GetTag(js::Shape* shape) { return SHAPEVECTOR; } - static ptrdiff_t GetTag(const JSPropertyDescriptor& pd) { return DESCVECTOR; } private: AutoGCRooter ** const stackTop; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 9caa5f4110..ba32c5f1c0 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -7022,7 +7022,7 @@ DebuggerObject_defineProperties(JSContext* cx, unsigned argc, Value* vp) return false; AutoIdVector ids(cx); - AutoPropertyDescriptorVector descs(cx); + Rooted descs(cx, PropertyDescriptorVector(cx)); if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs)) return false; size_t n = ids.length(); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 2f721aeceb..3651961a6f 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -831,7 +831,7 @@ js::XDRStaticBlockObject(XDRState* xdr, HandleObject enclosingScope, obj->setAliased(i, aliased); } } else { - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!shapes.growBy(count)) return false; @@ -884,19 +884,20 @@ CloneStaticBlockObject(JSContext* cx, HandleObject enclosingScope, HandlesetLocalOffset(srcBlock->localOffset()); /* Shape::Range is reverse order, so build a list in forward order. */ - AutoShapeVector shapes(cx); + Rooted shapes(cx, ShapeVector(cx)); if (!shapes.growBy(srcBlock->numVariables())) return nullptr; for (Shape::Range r(srcBlock->lastProperty()); !r.empty(); r.popFront()) shapes[srcBlock->shapeToIndex(r.front())].set(&r.front()); - for (Shape** p = shapes.begin(); p != shapes.end(); ++p) { - RootedId id(cx, (*p)->propid()); - unsigned i = srcBlock->shapeToIndex(**p); + RootedId id(cx); + for (Shape* shape : shapes) { + id = shape->propid(); + unsigned i = srcBlock->shapeToIndex(*shape); bool redeclared; - if (!StaticBlockObject::addVar(cx, clone, id, !(*p)->writable(), i, &redeclared)) { + if (!StaticBlockObject::addVar(cx, clone, id, !shape->writable(), i, &redeclared)) { MOZ_ASSERT(!redeclared); return nullptr; } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 85e718be0e..7bdf4fbcaf 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1707,17 +1707,34 @@ static bool CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject, HandleObject clone) { AutoIdVector ids(cx); + Vector attrs(cx); for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) { if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) { if (!ids.append(INT_TO_JSID(i))) return false; + if (!attrs.append(JSPROP_ENUMERATE)) + return false; } } + Rooted shapes(cx, ShapeVector(cx)); for (Shape::Range range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) { Shape& shape = range.front(); - if (shape.enumerable() && !ids.append(shape.propid())) + if (shape.enumerable() && !shapes.append(&shape)) + return false; + } + + // Now our shapes are in last-to-first order, so.... + Reverse(shapes.begin(), shapes.end()); + for (size_t i = 0; i < shapes.length(); ++i) { + MOZ_ASSERT(!shapes[i]->isAccessorShape(), + "Can't handle cloning accessors here yet."); + if (!ids.append(shapes[i]->propid())) + return false; + uint8_t shapeAttrs = + shapes[i]->attributes() & (JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + if (!attrs.append(shapeAttrs)) return false; } @@ -1729,7 +1746,7 @@ CloneProperties(JSContext* cx, HandleNativeObject selfHostedObject, HandleObject if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue)) return false; if (!CloneValue(cx, selfHostedValue, &val) || - !JS_DefinePropertyById(cx, clone, id, val, 0)) + !JS_DefinePropertyById(cx, clone, id, val, attrs[i])) { return false; } diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index c24048f76a..0a7656f3c0 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -78,11 +78,11 @@ Shape::search(ExclusiveContext *cx, Shape *start, jsid id, ShapeTable::Entry **p return nullptr; } -inline Shape * -Shape::new_(ExclusiveContext *cx, StackShape& unrootedOther, uint32_t nfixed) +inline Shape* +Shape::new_(ExclusiveContext* cx, StackShape& unrootedOther, uint32_t nfixed) { RootedGeneric other(cx, &unrootedOther); - Shape *shape = other->isAccessorShape() + Shape* shape = other->isAccessorShape() ? js::Allocate(cx) : js::Allocate(cx); if (!shape) { diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index fd4698cf93..b18afb6d90 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1526,6 +1526,10 @@ EmptyShape::insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleOb InitialShapeEntry& entry = const_cast(*p); + // The metadata callback can end up causing redundant changes of the initial shape. + if (entry.shape == shape) + return; + /* The new shape had better be rooted at the old one. */ #ifdef DEBUG Shape* nshape = shape; diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 44716f75f3..8976fa0dba 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1132,7 +1132,7 @@ typedef HashSet Initial struct StackShape { /* For performance, StackShape only roots when absolutely necessary. */ - UnownedBaseShape *base; + UnownedBaseShape* base; jsid propid; GetterOp rawGetter; SetterOp rawSetter; diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index e7eb6d7d9c..deee4a204f 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -42,6 +42,7 @@ #include "builtin/MapObject.h" #include "js/Date.h" +#include "js/TraceableHashTable.h" #include "vm/SharedArrayObject.h" #include "vm/TypedArrayObject.h" #include "vm/WrapperObject.h" @@ -268,8 +269,9 @@ struct JSStructuredCloneWriter { Value tVal) : out(cx), objs(out.context()), counts(out.context()), entries(out.context()), - memory(out.context()), callbacks(cb), closure(cbClosure), - transferable(out.context(), tVal), transferableObjects(out.context()) { } + memory(out.context(), CloneMemory(out.context())), callbacks(cb), + closure(cbClosure), transferable(out.context(), tVal), transferableObjects(out.context()) + {} ~JSStructuredCloneWriter(); @@ -284,6 +286,9 @@ struct JSStructuredCloneWriter { } private: + JSStructuredCloneWriter() = delete; + JSStructuredCloneWriter(const JSStructuredCloneWriter&) = delete; + JSContext* context() { return out.context(); } bool writeTransferMap(); @@ -325,8 +330,8 @@ struct JSStructuredCloneWriter { // The "memory" list described in the HTML5 internal structured cloning algorithm. // memory is a superset of objs; items are never removed from Memory // until a serialization operation is finished - typedef AutoObjectUnsigned32HashMap CloneMemory; - CloneMemory memory; + using CloneMemory = TraceableHashMap; + Rooted memory; // The user defined callbacks that will be used for cloning. const JSStructuredCloneCallbacks* callbacks; diff --git a/js/xpconnect/idl/nsIScriptError.idl b/js/xpconnect/idl/nsIScriptError.idl index 8b76762994..8968a8e19d 100644 --- a/js/xpconnect/idl/nsIScriptError.idl +++ b/js/xpconnect/idl/nsIScriptError.idl @@ -11,7 +11,11 @@ #include "nsISupports.idl" #include "nsIConsoleMessage.idl" -[scriptable, uuid(d6a8dae2-367f-4939-a843-11e0c48e240c)] +%{C++ +#include "nsStringGlue.h" // for nsDependentCString +%} + +[scriptable, uuid(18bdefde-e57b-11e4-832a-000c29a57fff)] interface nsIScriptError : nsIConsoleMessage { /** pseudo-flag for default case */ @@ -27,6 +31,9 @@ interface nsIScriptError : nsIConsoleMessage /** error or warning is due to strict option */ const unsigned long strictFlag = 0x4; + /** just a log message */ + const unsigned long infoFlag = 0x8; + /** * The error message without any context/line number information. * @@ -59,6 +66,8 @@ interface nsIScriptError : nsIConsoleMessage readonly attribute boolean isFromPrivateWindow; + attribute jsval stack; + void init(in AString message, in AString sourceName, in AString sourceLine, diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build index e4a69dc5fe..de880e5e21 100644 --- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -15,6 +15,7 @@ EXPORTS += [ UNIFIED_SOURCES += [ 'ExportHelpers.cpp', 'nsScriptError.cpp', + 'nsScriptErrorWithStack.cpp', 'nsXPConnect.cpp', 'Sandbox.cpp', 'XPCCallContext.cpp', diff --git a/js/xpconnect/src/nsScriptError.cpp b/js/xpconnect/src/nsScriptError.cpp index 887c61b512..a7e7360c6a 100644 --- a/js/xpconnect/src/nsScriptError.cpp +++ b/js/xpconnect/src/nsScriptError.cpp @@ -89,8 +89,13 @@ nsScriptError::GetMessageMoz(char16_t** result) { NS_IMETHODIMP nsScriptError::GetLogLevel(uint32_t* aLogLevel) { - *aLogLevel = mFlags & (uint32_t)nsIScriptError::errorFlag ? - nsIConsoleMessage::error : nsIConsoleMessage::warn; + if (mFlags & (uint32_t)nsIScriptError::infoFlag) { + *aLogLevel = nsIConsoleMessage::info; + } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) { + *aLogLevel = nsIConsoleMessage::warn; + } else { + *aLogLevel = nsIConsoleMessage::error; + } return NS_OK; } @@ -137,6 +142,17 @@ nsScriptError::GetCategory(char** result) { return NS_OK; } +NS_IMETHODIMP +nsScriptError::GetStack(JS::MutableHandleValue aStack) { + aStack.setUndefined(); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptError::SetStack(JS::HandleValue aStack) { + return NS_OK; +} + NS_IMETHODIMP nsScriptError::Init(const nsAString& message, const nsAString& sourceName, diff --git a/js/xpconnect/src/nsScriptErrorWithStack.cpp b/js/xpconnect/src/nsScriptErrorWithStack.cpp new file mode 100644 index 0000000000..aacb20a464 --- /dev/null +++ b/js/xpconnect/src/nsScriptErrorWithStack.cpp @@ -0,0 +1,69 @@ +/* -*- 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/. */ + +/* + * nsScriptErrorWithStack implementation. + * a main-thread-only, cycle-collected subclass of nsScriptError + * that can store a SavedFrame stack trace object. + */ + +#include "xpcprivate.h" +#include "MainThreadUtils.h" +#include "mozilla/Assertions.h" +#include "nsGlobalWindow.h" +#include "nsCycleCollectionParticipant.h" + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptErrorWithStack) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptErrorWithStack) + tmp->mStack = nullptr; +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptErrorWithStack) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsScriptErrorWithStack) + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mStack) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptErrorWithStack) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptErrorWithStack) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptErrorWithStack) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_INTERFACE_MAP_ENTRY(nsIConsoleMessage) + NS_INTERFACE_MAP_ENTRY(nsIScriptError) +NS_INTERFACE_MAP_END + +nsScriptErrorWithStack::nsScriptErrorWithStack(JS::HandleObject aStack) + : nsScriptError(), + mStack(aStack) +{ + mozilla::HoldJSObjects(this); +} + +nsScriptErrorWithStack::~nsScriptErrorWithStack() { + mozilla::DropJSObjects(this); +} + +NS_IMETHODIMP +nsScriptErrorWithStack::Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) +{ + MOZ_CRASH("nsScriptErrorWithStack requires to be initialized with a document, by using InitWithWindowID"); +} + +NS_IMETHODIMP +nsScriptErrorWithStack::GetStack(JS::MutableHandleValue aStack) { + aStack.setObjectOrNull(mStack); + return NS_OK; +} diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 978a71d133..3b0d0e958e 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -218,6 +218,11 @@ static PRLogModuleInfo* gJSDiagnostics; void xpc::ErrorReport::LogToConsole() +{ + LogToConsoleWithStack(nullptr); +} +void +xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack) { // Log to stdout. if (nsContentUtils::DOMWindowDumpEnabled()) { @@ -254,8 +259,17 @@ xpc::ErrorReport::LogToConsole() // mechanisms. nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); - nsCOMPtr errorObject = - do_CreateInstance("@mozilla.org/scripterror;1"); + + nsCOMPtr errorObject; + if (mWindowID && aStack) { + // Only set stack on messages related to a document + // As we cache messages in the console service, + // we have to ensure not leaking them after the related + // context is destroyed and we only track document lifecycle for now. + errorObject = new nsScriptErrorWithStack(aStack); + } else { + errorObject = new nsScriptError(); + } NS_ENSURE_TRUE_VOID(consoleService && errorObject); nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine, diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 2245208775..8a27c260ee 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2993,7 +2993,7 @@ xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals, // Definition of nsScriptError, defined here because we lack a place to put // XPCOM objects associated with the JavaScript engine. -class nsScriptError final : public nsIScriptError { +class nsScriptError : public nsIScriptError { public: nsScriptError(); @@ -3003,7 +3003,7 @@ public: NS_DECL_NSICONSOLEMESSAGE NS_DECL_NSISCRIPTERROR -private: +protected: virtual ~nsScriptError(); void @@ -3026,6 +3026,30 @@ private: bool mIsFromPrivateWindow; }; +class nsScriptErrorWithStack : public nsScriptError { +public: + nsScriptErrorWithStack(JS::HandleObject); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack) + + NS_IMETHOD Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) override; + + NS_IMETHOD GetStack(JS::MutableHandleValue); + +private: + virtual ~nsScriptErrorWithStack(); + // Complete stackframe where the error happened. + // Must be SavedFrame object. + JS::Heap mStack; +}; + /****************************************************************************** * Handles pre/post script processing. */ diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 87c87bb6e5..ea03e16d73 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -515,6 +515,7 @@ class ErrorReport { void Init(JSErrorReport* aReport, const char* aFallbackMessage, bool aIsChrome, uint64_t aWindowID); void LogToConsole(); + void LogToConsoleWithStack(JS::HandleObject aStack); public: diff --git a/js/xpconnect/tests/chrome/chrome.ini b/js/xpconnect/tests/chrome/chrome.ini index 1b1189ebad..c661a82b5a 100644 --- a/js/xpconnect/tests/chrome/chrome.ini +++ b/js/xpconnect/tests/chrome/chrome.ini @@ -107,3 +107,4 @@ skip-if = buildapp == 'mulet' # Disabled until this test gets updated to test the new proxy based wrappers. skip-if = true [test_watchpoints.xul] +[test_nsScriptErrorWithStack.html] diff --git a/js/xpconnect/tests/chrome/test_nsScriptErrorWithStack.html b/js/xpconnect/tests/chrome/test_nsScriptErrorWithStack.html new file mode 100644 index 0000000000..9179e39852 --- /dev/null +++ b/js/xpconnect/tests/chrome/test_nsScriptErrorWithStack.html @@ -0,0 +1,63 @@ + + +Test for 814497 + +
+ diff --git a/toolkit/components/console/content/console.css b/toolkit/components/console/content/console.css index e05f13c3ef..148c27bf31 100644 --- a/toolkit/components/console/content/console.css +++ b/toolkit/components/console/content/console.css @@ -13,7 +13,8 @@ } .console-row[type="error"], -.console-row[type="warning"] { +.console-row[type="warning"], +.console-row[type="message"][typetext] { -moz-binding: url("chrome://global/content/consoleBindings.xml#error"); } diff --git a/toolkit/components/console/content/consoleBindings.xml b/toolkit/components/console/content/consoleBindings.xml index 1b00326bfc..c0285329ec 100644 --- a/toolkit/components/console/content/consoleBindings.xml +++ b/toolkit/components/console/content/consoleBindings.xml @@ -221,12 +221,12 @@ var row = this.createConsoleRow(); var nsIScriptError = Components.interfaces.nsIScriptError; - // Is this error actually just a non-fatal warning? - var warning = aObject.flags & nsIScriptError.warningFlag != 0; + // nsIConsoleMessage constants: debug, info, warn, error + var typetext = ["typeMessage", "typeMessage", "typeWarning", "typeError"][aObject.logLevel]; + var type = ["message", "message", "warning", "error"][aObject.logLevel]; - var typetext = warning ? "typeWarning" : "typeError"; row.setAttribute("typetext", this.mStrBundle.getString(typetext)); - row.setAttribute("type", warning ? "warning" : "error"); + row.setAttribute("type", type); row.setAttribute("msg", aObject.errorMessage); row.setAttribute("category", aObject.category); row.setAttribute("time", this.properFormatTime(aObject.timeStamp)); diff --git a/toolkit/devtools/server/actors/webconsole.js b/toolkit/devtools/server/actors/webconsole.js index d36d88fee1..9f5736f1b7 100644 --- a/toolkit/devtools/server/actors/webconsole.js +++ b/toolkit/devtools/server/actors/webconsole.js @@ -1285,6 +1285,7 @@ WebConsoleActor.prototype = error: !!(aPageError.flags & aPageError.errorFlag), exception: !!(aPageError.flags & aPageError.exceptionFlag), strict: !!(aPageError.flags & aPageError.strictFlag), + info: !!(aPageError.flags & aPageError.infoFlag), private: aPageError.isFromPrivateWindow, }; }, diff --git a/toolkit/devtools/webconsole/webconsole.js b/toolkit/devtools/webconsole/webconsole.js index 0318e9cc2a..c1689a8d8b 100644 --- a/toolkit/devtools/webconsole/webconsole.js +++ b/toolkit/devtools/webconsole/webconsole.js @@ -1409,6 +1409,8 @@ WebConsoleFrame.prototype = { let severity = 'error'; if (aScriptError.warning || aScriptError.strict) { severity = 'warning'; + } else if (aScriptError.info) { + severity = 'log'; } let category = 'js'; diff --git a/toolkit/locales/en-US/chrome/global/console.properties b/toolkit/locales/en-US/chrome/global/console.properties index d01b5e59b6..a51977ecd2 100644 --- a/toolkit/locales/en-US/chrome/global/console.properties +++ b/toolkit/locales/en-US/chrome/global/console.properties @@ -4,6 +4,7 @@ typeError=Error: typeWarning=Warning: +typeMessage=Message: errFile=Source File: %S errLine=Line: %S errLineCol=Line: %S, Column: %S diff --git a/xpcom/base/nsConsoleService.cpp b/xpcom/base/nsConsoleService.cpp index 3c702c219a..df422c78c9 100644 --- a/xpcom/base/nsConsoleService.cpp +++ b/xpcom/base/nsConsoleService.cpp @@ -20,6 +20,7 @@ #include "nsIClassInfoImpl.h" #include "nsIConsoleListener.h" #include "nsPrintfCString.h" +#include "nsIScriptError.h" #include "mozilla/Preferences.h" @@ -62,6 +63,45 @@ nsConsoleService::nsConsoleService() mBufferSize = 250; } + +NS_IMETHODIMP +nsConsoleService::ClearMessagesForWindowID(const uint64_t innerID) +{ + // Remove the messages related to this window + for (uint32_t i = 0; i < mBufferSize && mMessages[i]; i++) { + // Only messages implementing nsIScriptError interface exposes the inner window ID + nsCOMPtr scriptError = do_QueryInterface(mMessages[i]); + if (!scriptError) { + continue; + } + uint64_t innerWindowID; + nsresult rv = scriptError->GetInnerWindowID(&innerWindowID); + if (NS_FAILED(rv) || innerWindowID != innerID) { + continue; + } + + // Free this matching message! + NS_RELEASE(mMessages[i]); + + uint32_t j = i; + // Now shift all the following messages + for (; j < mBufferSize - 1 && mMessages[j + 1]; j++) { + mMessages[j] = mMessages[j + 1]; + } + // Nullify the current slot + mMessages[j] = nullptr; + mCurrent = j; + + // The array is no longer full + mFull = false; + + // Ensure the next iteration handles the messages we just shifted down + i--; + } + + return NS_OK; +} + nsConsoleService::~nsConsoleService() { uint32_t i = 0; diff --git a/xpcom/base/nsIConsoleService.idl b/xpcom/base/nsIConsoleService.idl index fb9e906fb7..53c488179f 100644 --- a/xpcom/base/nsIConsoleService.idl +++ b/xpcom/base/nsIConsoleService.idl @@ -8,7 +8,7 @@ interface nsIConsoleListener; interface nsIConsoleMessage; -[scriptable, uuid(0eb81d20-c37e-42d4-82a8-ca9ae96bdf52)] +[scriptable, uuid(2436031e-2167-4307-9f1c-a3f38b55a224)] interface nsIConsoleService : nsISupports { void logMessage(in nsIConsoleMessage message); @@ -44,6 +44,11 @@ interface nsIConsoleService : nsISupports * Clear the message buffer (e.g. for privacy reasons). */ void reset(); + + /** + * Clear the message buffer for a given inner window. + */ + void clearMessagesForWindowID(in uint64_t innerWindowID); }; diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index 035ed97ab9..cca5cb7bd4 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -5,10 +5,13 @@ #include "mozilla/Logging.h" #include "nsAutoPtr.h" +#include "nsIConsoleService.h" #include "nsIObserverService.h" #include "nsIObserver.h" +#include "nsIScriptError.h" #include "nsObserverService.h" #include "nsObserverList.h" +#include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "nsEnumeratorUtils.h" #include "xpcpublic.h" @@ -230,6 +233,13 @@ nsObserverService::AddObserver(nsIObserver* aObserver, const char* aTopic, } if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) { + nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + nsCOMPtr error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); + error->Init(NS_LITERAL_STRING("http-on-* observers only work in the parent process"), + EmptyString(), EmptyString(), 0, 0, + nsIScriptError::warningFlag, "chrome javascript"); + console->LogMessage(error); + return NS_ERROR_NOT_IMPLEMENTED; }