From d3040f3cadd9c37da8aece00acefa55f8c05cd27 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Mon, 9 Dec 2013 17:07:13 -0500 Subject: [PATCH 01/34] Bug 948128. Add StackArray helper. r=Bas This is helpful for when we want to convert between different types and we need a short lived piece of memory. --HG-- extra : rebase_source : b841a535cb1ddd837df4b34949bd34054c438c67 --- gfx/2d/StackArray.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 gfx/2d/StackArray.h diff --git a/gfx/2d/StackArray.h b/gfx/2d/StackArray.h new file mode 100644 index 000000000000..e3c2684a0bf2 --- /dev/null +++ b/gfx/2d/StackArray.h @@ -0,0 +1,30 @@ +/* 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/. */ + +/* A handy class that will allocate data for size*T objects on the stack and + * otherwise allocate them on the heap. It is similar in purpose to nsAutoTArray */ + +template +class StackArray +{ +public: + StackArray(size_t count) { + if (count > size) { + mData = new T[count]; + } else { + mData = mStackData; + } + } + ~StackArray() { + if (mData != mStackData) { + delete[] mData; + } + } + T& operator[](size_t n) { return mData[n]; } + const T& operator[](size_t n) const { return mData[n]; } + T* data() { return mData; }; +private: + T mStackData[size]; + T* mData; +}; From 03fbbbdef717ce7599fbc6bba030296ae24f0ccc Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 16 Dec 2013 10:53:02 -0800 Subject: [PATCH 02/34] Bug 785905 - Build Ion MIR graph off thread, r=jandem. --- js/src/frontend/BytecodeEmitter.cpp | 8 +- js/src/gc/Marking.cpp | 42 ++-- js/src/gc/RootMarking.cpp | 2 +- js/src/jit/BaselineCompiler.cpp | 6 +- js/src/jit/BaselineIC.cpp | 174 ++++++------- js/src/jit/BaselineIC.h | 34 ++- js/src/jit/BaselineInspector.cpp | 38 +++ js/src/jit/BaselineJIT.cpp | 6 +- js/src/jit/BaselineJIT.h | 4 +- js/src/jit/CodeGenerator.cpp | 12 +- js/src/jit/CompileInfo.h | 15 +- js/src/jit/CompileWrappers.cpp | 9 + js/src/jit/CompileWrappers.h | 4 + js/src/jit/Ion.cpp | 56 +++-- js/src/jit/IonAnalysis.cpp | 12 +- js/src/jit/IonBuilder.cpp | 59 ++++- js/src/jit/IonBuilder.h | 15 +- js/src/jit/IonCaches.cpp | 11 +- js/src/jit/IonMacroAssembler.h | 6 +- js/src/jit/MIR.cpp | 16 +- js/src/jit/VMFunctions.cpp | 2 +- .../jit/shared/CodeGenerator-x86-shared.cpp | 2 +- js/src/jscntxt.cpp | 5 +- js/src/jscntxt.h | 72 +++++- js/src/jscompartment.cpp | 2 +- js/src/jsfun.cpp | 34 ++- js/src/jsfun.h | 30 ++- js/src/jsinfer.cpp | 231 ++++++++++++------ js/src/jsinfer.h | 141 +++++++++-- js/src/jsinferinlines.h | 157 +++++------- js/src/jsiter.cpp | 1 + js/src/jsobj.cpp | 39 ++- js/src/jsobj.h | 2 +- js/src/jsobjinlines.h | 30 ++- js/src/jsproxy.cpp | 2 +- js/src/jsproxy.h | 2 - js/src/jsscript.cpp | 5 +- js/src/jsscript.h | 9 +- js/src/jsscriptinlines.h | 5 +- js/src/jsworkers.cpp | 14 +- js/src/jswrapper.cpp | 4 +- js/src/vm/GlobalObject.cpp | 30 ++- js/src/vm/GlobalObject.h | 14 +- js/src/vm/Interpreter.cpp | 2 +- js/src/vm/ObjectImpl.cpp | 12 +- js/src/vm/ObjectImpl.h | 12 +- js/src/vm/Runtime.cpp | 85 ++++++- js/src/vm/Runtime.h | 99 +++++++- js/src/vm/SPSProfiler.cpp | 3 +- js/src/vm/SelfHosting.cpp | 3 +- js/src/vm/TypedArrayObject.cpp | 10 +- js/src/vm/TypedArrayObject.h | 4 +- 52 files changed, 1086 insertions(+), 506 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7108177f385b..ddf2ca9c9e9f 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2804,7 +2804,13 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo /* Initialize fun->script() so that the debugger has a valid fun->script(). */ RootedFunction fun(cx, bce->script->function()); JS_ASSERT(fun->isInterpreted()); - fun->setScript(bce->script); + + if (fun->isInterpretedLazy()) { + AutoLockForCompilation lock(cx); + fun->setUnlazifiedScript(bce->script); + } else { + fun->setScript(bce->script); + } bce->tellDebuggerAboutCompiledScript(cx); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index d0e3bde29e8a..2b1393e0b22e 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1129,23 +1129,17 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type) PushMarkStack(gcmarker, JSID_TO_STRING(prop->id)); } - if (TaggedProto(type->proto).isObject()) - PushMarkStack(gcmarker, type->proto); + if (type->proto().isObject()) + PushMarkStack(gcmarker, type->proto().toObject()); if (type->singleton && !type->lazy()) PushMarkStack(gcmarker, type->singleton); - if (type->addendum) { - switch (type->addendum->kind) { - case types::TypeObjectAddendum::NewScript: - PushMarkStack(gcmarker, type->newScript()->fun); - PushMarkStack(gcmarker, type->newScript()->templateObject); - break; - - case types::TypeObjectAddendum::TypedObject: - PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject()); - break; - } + if (type->hasNewScript()) { + PushMarkStack(gcmarker, type->newScript()->fun); + PushMarkStack(gcmarker, type->newScript()->templateObject); + } else if (type->hasTypedObject()) { + PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject()); } if (type->interpretedFunction) @@ -1162,23 +1156,17 @@ gc::MarkChildren(JSTracer *trc, types::TypeObject *type) MarkId(trc, &prop->id, "type_prop"); } - if (TaggedProto(type->proto).isObject()) - MarkObject(trc, &type->proto, "type_proto"); + if (type->proto().isObject()) + MarkObject(trc, &type->protoRaw(), "type_proto"); if (type->singleton && !type->lazy()) MarkObject(trc, &type->singleton, "type_singleton"); - if (type->addendum) { - switch (type->addendum->kind) { - case types::TypeObjectAddendum::NewScript: - MarkObject(trc, &type->newScript()->fun, "type_new_function"); - MarkObject(trc, &type->newScript()->templateObject, "type_new_template"); - break; - - case types::TypeObjectAddendum::TypedObject: - type->typedObject()->typeRepr->mark(trc); - break; - } + if (type->hasNewScript()) { + MarkObject(trc, &type->newScript()->fun, "type_new_function"); + MarkObject(trc, &type->newScript()->templateObject, "type_new_template"); + } else if (type->hasTypedObject()) { + type->typedObject()->typeRepr->mark(trc); } if (type->interpretedFunction) @@ -1441,7 +1429,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget) PushMarkStack(this, shape); /* Call the trace hook if necessary. */ - const Class *clasp = type->clasp; + const Class *clasp = type->clasp(); if (clasp->trace) { JS_ASSERT_IF(runtime->gcMode() == JSGC_MODE_INCREMENTAL && runtime->gcIncrementalEnabled, diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 541ad84d996c..40843d6cff40 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -47,7 +47,7 @@ MarkExactStackRoot(JSTracer *trc, Rooted *rooter, ThingRootKind kind) if (IsNullTaggedPointer(*addr)) return; - if (kind == THING_ROOT_OBJECT && *addr == Proxy::LazyProto) + if (kind == THING_ROOT_OBJECT && *addr == TaggedProto::LazyProto) return; switch (kind) { diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 38e2bc69b9b6..fa39e21b24ea 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -186,10 +186,8 @@ BaselineCompiler::compile() baselineScript->setMethod(code); baselineScript->setTemplateScope(templateScope); - script->setBaselineScript(baselineScript); - IonSpew(IonSpew_BaselineScripts, "Created BaselineScript %p (raw %p) for %s:%d", - (void *) script->baselineScript(), (void *) code->raw(), + (void *) baselineScript, (void *) code->raw(), script->filename(), script->lineno()); #ifdef JS_ION_PERF @@ -254,6 +252,8 @@ BaselineCompiler::compile() if (script->compartment()->debugMode()) baselineScript->setDebugMode(); + script->setBaselineScript(cx, baselineScript); + return Method_Compiled; } diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 0f7e235058c8..75e6308e5839 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -130,12 +130,16 @@ ICStubIterator::operator++() } void -ICStubIterator::unlink(Zone *zone) +ICStubIterator::unlink(JSContext *cx) { JS_ASSERT(currentStub_->next() != nullptr); JS_ASSERT(currentStub_ != fallbackStub_); JS_ASSERT(!unlinked_); - fallbackStub_->unlinkStub(zone, previousStub_, currentStub_); + + { + AutoLockForCompilation lock(cx); + fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_); + } // Mark the current iterator position as unlinked, so operator++ works properly. unlinked_ = true; @@ -485,7 +489,7 @@ ICFallbackStub::unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind) { for (ICStubIterator iter = beginChain(); !iter.atEnd(); iter++) { if (iter->kind() == kind) - iter.unlink(cx->zone()); + iter.unlink(cx); } } @@ -1061,7 +1065,7 @@ DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stu ICStub *optStub = compiler.getStub(compiler.getStubSpace(script)); if (!optStub) return false; - stub->addNewStub(optStub); + stub->addNewStub(cx, optStub); return true; } @@ -1146,8 +1150,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type); ICStub *stub = existingStub ? compiler.updateStub() : compiler.getStub(compiler.getStubSpace(script)); - if (!stub) + if (!stub) { + js_ReportOutOfMemory(cx); return false; + } IonSpew(IonSpew_BaselineIC, " %s TypeMonitor stub %p for primitive type %d", existingStub ? "Modified existing" : "Created new", stub, type); @@ -1171,8 +1177,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip ICTypeMonitor_SingleObject::Compiler compiler(cx, obj); ICStub *stub = compiler.getStub(compiler.getStubSpace(script)); - if (!stub) + if (!stub) { + js_ReportOutOfMemory(cx); return false; + } IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for singleton %p", stub, obj.get()); @@ -1193,8 +1201,10 @@ ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext *cx, HandleScript scrip ICTypeMonitor_TypeObject::Compiler compiler(cx, type); ICStub *stub = compiler.getStub(compiler.getStubSpace(script)); - if (!stub) + if (!stub) { + js_ReportOutOfMemory(cx); return false; + } IonSpew(IonSpew_BaselineIC, " Added TypeMonitor stub %p for TypeObject %p", stub, type.get()); @@ -1785,7 +1795,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!int32Stub) return false; - stub->addNewStub(int32Stub); + stub->addNewStub(cx, int32Stub); return true; } @@ -1803,7 +1813,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!doubleStub) return false; - stub->addNewStub(doubleStub); + stub->addNewStub(cx, doubleStub); return true; } @@ -1818,7 +1828,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!doubleStub) return false; - stub->addNewStub(doubleStub); + stub->addNewStub(cx, doubleStub); return true; } @@ -1829,7 +1839,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!booleanStub) return false; - stub->addNewStub(booleanStub); + stub->addNewStub(cx, booleanStub); return true; } @@ -1842,7 +1852,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!optStub) return false; - stub->addNewStub(optStub); + stub->addNewStub(cx, optStub); return true; } @@ -1854,7 +1864,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!stringStub) return false; - stub->addNewStub(stringStub); + stub->addNewStub(cx, stringStub); return true; } @@ -1866,7 +1876,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!objectStub) return false; - stub->addNewStub(objectStub); + stub->addNewStub(cx, objectStub); return true; } @@ -1884,7 +1894,7 @@ DoCompareFallback(JSContext *cx, BaselineFrame *frame, ICCompare_Fallback *stub, if (!objectStub) return false; - stub->addNewStub(objectStub); + stub->addNewStub(cx, objectStub); return true; } } @@ -2090,7 +2100,7 @@ ICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler &masm) Label emulatesUndefined; Register obj = masm.extractObject(objectOperand, ExtractTemp0); masm.loadPtr(Address(obj, JSObject::offsetOfType()), obj); - masm.loadPtr(Address(obj, offsetof(types::TypeObject, clasp)), obj); + masm.loadPtr(Address(obj, types::TypeObject::offsetOfClasp()), obj); masm.branchTest32(Assembler::NonZero, Address(obj, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED), @@ -2196,7 +2206,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H if (!int32Stub) return false; - stub->addNewStub(int32Stub); + stub->addNewStub(cx, int32Stub); return true; } @@ -2207,7 +2217,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H if (!doubleStub) return false; - stub->addNewStub(doubleStub); + stub->addNewStub(cx, doubleStub); return true; } @@ -2218,7 +2228,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H if (!stringStub) return false; - stub->addNewStub(stringStub); + stub->addNewStub(cx, stringStub); return true; } @@ -2228,7 +2238,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H if (!nilStub) return false; - stub->addNewStub(nilStub); + stub->addNewStub(cx, nilStub); return true; } @@ -2239,7 +2249,7 @@ DoToBoolFallback(JSContext *cx, BaselineFrame *frame, ICToBool_Fallback *stub, H if (!objStub) return false; - stub->addNewStub(objStub); + stub->addNewStub(cx, objStub); return true; } @@ -2531,11 +2541,11 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac } if (ret.isDouble()) - stub->setSawDoubleResult(); + stub->setSawDoubleResult(cx); // Check to see if a new stub should be generated. if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) { - stub->noteUnoptimizableOperands(); + stub->noteUnoptimizableOperands(cx); return true; } @@ -2548,7 +2558,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script)); if (!strcatStub) return false; - stub->addNewStub(strcatStub); + stub->addNewStub(cx, strcatStub); return true; } @@ -2561,7 +2571,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script)); if (!strcatStub) return false; - stub->addNewStub(strcatStub); + stub->addNewStub(cx, strcatStub); return true; } } @@ -2577,13 +2587,13 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script)); if (!arithStub) return false; - stub->addNewStub(arithStub); + stub->addNewStub(cx, arithStub); return true; } // Handle only int32 or double. if (!lhs.isNumber() || !rhs.isNumber()) { - stub->noteUnoptimizableOperands(); + stub->noteUnoptimizableOperands(cx); return true; } @@ -2607,7 +2617,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script)); if (!doubleStub) return false; - stub->addNewStub(doubleStub); + stub->addNewStub(cx, doubleStub); return true; } default: @@ -2625,7 +2635,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script)); if (!int32Stub) return false; - stub->addNewStub(int32Stub); + stub->addNewStub(cx, int32Stub); return true; } @@ -2644,7 +2654,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac ICStub *optStub = compiler.getStub(compiler.getStubSpace(script)); if (!optStub) return false; - stub->addNewStub(optStub); + stub->addNewStub(cx, optStub); return true; } default: @@ -2652,7 +2662,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac } } - stub->noteUnoptimizableOperands(); + stub->noteUnoptimizableOperands(cx); return true; } #if defined(_MSC_VER) @@ -3047,7 +3057,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script)); if (!int32Stub) return false; - stub->addNewStub(int32Stub); + stub->addNewStub(cx, int32Stub); return true; } @@ -3061,7 +3071,7 @@ DoUnaryArithFallback(JSContext *cx, BaselineFrame *frame, ICUnaryArith_Fallback ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script)); if (!doubleStub) return false; - stub->addNewStub(doubleStub); + stub->addNewStub(cx, doubleStub); return true; } @@ -3629,7 +3639,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle // If the holder matches, but the holder's lastProperty doesn't match, then // this stub is invalid anyway. Unlink it. if (holder->lastProperty() != protoStub->holderShape()) { - iter.unlink(cx->zone()); + iter.unlink(cx); continue; } } else { @@ -3645,7 +3655,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle // If the holder matches, but the holder's lastProperty doesn't match, then // this stub is invalid anyway. Unlink it. if (holder->lastProperty() != protoStub->holderShape()) { - iter.unlink(cx->zone()); + iter.unlink(cx); continue; } } @@ -3654,7 +3664,7 @@ RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, Handle // If the new stub needs atomization, and the old stub doesn't atomize, then // remove the old stub. if (needsAtomize && !getElemNativeStub->needsAtomize()) { - iter.unlink(cx->zone()); + iter.unlink(cx); continue; } @@ -3745,7 +3755,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -3797,7 +3807,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -3831,7 +3841,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!stringStub) return false; - stub->addNewStub(stringStub); + stub->addNewStub(cx, stringStub); return true; } @@ -3849,7 +3859,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!argsStub) return false; - stub->addNewStub(argsStub); + stub->addNewStub(cx, argsStub); return true; } @@ -3871,7 +3881,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!argsStub) return false; - stub->addNewStub(argsStub); + stub->addNewStub(cx, argsStub); return true; } } @@ -3886,7 +3896,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!denseStub) return false; - stub->addNewStub(denseStub); + stub->addNewStub(cx, denseStub); return true; } @@ -3920,7 +3930,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!typedArrayStub) return false; - stub->addNewStub(typedArrayStub); + stub->addNewStub(cx, typedArrayStub); return true; } @@ -3928,13 +3938,13 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl // be cached by either Baseline or Ion. Indicate this in the cache so that // Ion does not generate a cache for this op. if (!obj->isNative() && !obj->is()) - stub->noteNonNativeAccess(); + stub->noteNonNativeAccess(cx); // GetElem operations which could access negative indexes generally can't // be optimized without the potential for bailouts, as we can't statically // determine that an object has no properties on such indexes. if (rhs.isNumber() && rhs.toNumber() < 0) - stub->noteNegativeIndex(); + stub->noteNegativeIndex(cx); return true; } @@ -4844,7 +4854,7 @@ RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, Han // TypedArraySetElem stubs are only removed using this procedure if // being replaced with one that expects out of bounds index. JS_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds()); - iter.unlink(cx->zone()); + iter.unlink(cx); return true; } return false; @@ -5001,7 +5011,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub, if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs)) return false; - stub->addNewStub(denseStub); + stub->addNewStub(cx, denseStub); } else if (!addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj)) { @@ -5015,7 +5025,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub, if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs)) return false; - stub->addNewStub(denseStub); + stub->addNewStub(cx, denseStub); } } @@ -5048,7 +5058,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub, if (!typedArrayStub) return false; - stub->addNewStub(typedArrayStub); + stub->addNewStub(cx, typedArrayStub); return true; } } @@ -5098,13 +5108,13 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm) } void -BaselineScript::noteArrayWriteHole(uint32_t pcOffset) +BaselineScript::noteArrayWriteHole(JSContext *cx, uint32_t pcOffset) { ICEntry &entry = icEntryFromPCOffset(pcOffset); ICFallbackStub *stub = entry.fallbackStub(); if (stub->isSetElem_Fallback()) - stub->toSetElem_Fallback()->noteArrayWriteHole(); + stub->toSetElem_Fallback()->noteArrayWriteHole(cx); } // @@ -5626,7 +5636,7 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback * if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -5716,7 +5726,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -5923,7 +5933,7 @@ DoGetIntrinsicFallback(JSContext *cx, BaselineFrame *frame, ICGetIntrinsic_Fallb if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -5971,7 +5981,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub return false; *attached = true; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -5983,7 +5993,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub return false; *attached = true; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -6000,7 +6010,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub return false; *attached = true; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } if (obj->is()) { @@ -6012,7 +6022,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub return false; *attached = true; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -6028,7 +6038,7 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub return false; *attached = true; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -6111,7 +6121,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -6142,7 +6152,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -6189,7 +6199,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, } if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -6209,7 +6219,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -6263,7 +6273,7 @@ TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -6349,7 +6359,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub, } JS_ASSERT(!attached); - stub->noteUnoptimizableAccess(); + stub->noteUnoptimizableAccess(cx); return true; } @@ -7094,13 +7104,13 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm) } void -BaselineScript::noteAccessedGetter(uint32_t pcOffset) +BaselineScript::noteAccessedGetter(JSContext *cx, uint32_t pcOffset) { ICEntry &entry = icEntryFromPCOffset(pcOffset); ICFallbackStub *stub = entry.fallbackStub(); if (stub->isGetProp_Fallback()) - stub->toGetProp_Fallback()->noteAccessedGetter(); + stub->toGetProp_Fallback()->noteAccessedGetter(cx); } // @@ -7141,7 +7151,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs)) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -7159,7 +7169,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs)) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -7181,7 +7191,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -7200,7 +7210,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); *attached = true; return true; } @@ -7271,7 +7281,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub, return true; JS_ASSERT(!attached); - stub->noteUnoptimizableAccess(); + stub->noteUnoptimizableAccess(cx); return true; } @@ -7775,7 +7785,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -7792,7 +7802,7 @@ TryAttachFunApplyStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } } @@ -7933,7 +7943,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted); // Add new generalized stub. - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -7962,7 +7972,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -7999,7 +8009,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); return true; } @@ -9123,7 +9133,7 @@ DoIteratorMoreFallback(JSContext *cx, BaselineFrame *frame, ICIteratorMore_Fallb ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script())); if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); } return true; @@ -9197,7 +9207,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb return false; if (!res.isString() && !stub->hasNonStringResult()) - stub->setHasNonStringResult(); + stub->setHasNonStringResult(cx); if (iteratorObject->is() && !stub->hasStub(ICStub::IteratorNext_Native)) @@ -9206,7 +9216,7 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script())); if (!newStub) return false; - stub->addNewStub(newStub); + stub->addNewStub(cx, newStub); } return true; @@ -9370,7 +9380,7 @@ DoTypeOfFallback(JSContext *cx, BaselineFrame *frame, ICTypeOf_Fallback *stub, H ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script())); if (!typeOfStub) return false; - stub->addNewStub(typeOfStub); + stub->addNewStub(cx, typeOfStub); } return true; @@ -9457,7 +9467,7 @@ DoRetSubFallback(JSContext *cx, BaselineFrame *frame, ICRetSub_Fallback *stub, if (!optStub) return false; - stub->addNewStub(optStub); + stub->addNewStub(cx, optStub); return true; } diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index c4c223551cdc..18a205b91ef2 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -516,7 +516,7 @@ class ICStubIterator return currentStub_ == (ICStub *) fallbackStub_; } - void unlink(Zone *zone); + void unlink(JSContext *cx); }; // @@ -687,6 +687,8 @@ class ICStub } inline void setNext(ICStub *stub) { + // Note: next_ only needs to be changed under the compilation lock for + // non-type-monitor/update ICs. next_ = stub; } @@ -833,7 +835,8 @@ class ICFallbackStub : public ICStub } // Add a new stub to the IC chain terminated by this fallback stub. - void addNewStub(ICStub *stub) { + void addNewStub(JSContext *cx, ICStub *stub) { + AutoLockForCompilation lock(cx); JS_ASSERT(*lastStubPtrAddr_ == this); JS_ASSERT(stub->next() == nullptr); stub->setNext(this); @@ -2439,13 +2442,15 @@ class ICBinaryArith_Fallback : public ICFallbackStub bool sawDoubleResult() const { return extra_ & SAW_DOUBLE_RESULT_BIT; } - void setSawDoubleResult() { + void setSawDoubleResult(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= SAW_DOUBLE_RESULT_BIT; } bool hadUnoptimizableOperands() const { return extra_ & UNOPTIMIZABLE_OPERANDS_BIT; } - void noteUnoptimizableOperands() { + void noteUnoptimizableOperands(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= UNOPTIMIZABLE_OPERANDS_BIT; } @@ -2846,14 +2851,16 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub return space->allocate(code); } - void noteNonNativeAccess() { + void noteNonNativeAccess(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= EXTRA_NON_NATIVE; } bool hasNonNativeAccess() const { return extra_ & EXTRA_NON_NATIVE; } - void noteNegativeIndex() { + void noteNegativeIndex(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= EXTRA_NEGATIVE_INDEX; } bool hasNegativeIndex() const { @@ -3441,7 +3448,8 @@ class ICSetElem_Fallback : public ICFallbackStub return space->allocate(code); } - void noteArrayWriteHole() { + void noteArrayWriteHole(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ = 1; } bool hasArrayWriteHole() const { @@ -4016,14 +4024,16 @@ class ICGetProp_Fallback : public ICMonitoredFallbackStub static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0; static const size_t ACCESSED_GETTER_BIT = 1; - void noteUnoptimizableAccess() { + void noteUnoptimizableAccess(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT); } bool hadUnoptimizableAccess() const { return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT); } - void noteAccessedGetter() { + void noteAccessedGetter(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= (1u << ACCESSED_GETTER_BIT); } bool hasAccessedGetter() const { @@ -4830,7 +4840,8 @@ class ICSetProp_Fallback : public ICFallbackStub } static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0; - void noteUnoptimizableAccess() { + void noteUnoptimizableAccess(JSContext *cx) { + AutoLockForCompilation lock(cx); extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT); } bool hadUnoptimizableAccess() const { @@ -5721,7 +5732,8 @@ class ICIteratorNext_Fallback : public ICFallbackStub return space->allocate(code); } - void setHasNonStringResult() { + void setHasNonStringResult(JSContext *cx) { + AutoLockForCompilation lock(cx); JS_ASSERT(extra_ == 0); extra_ = 1; } diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index f7e4433326f5..720d6ef36894 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -18,6 +18,8 @@ using mozilla::DebugOnly; bool SetElemICInspector::sawOOBDenseWrite() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!icEntry_) return false; @@ -38,6 +40,8 @@ SetElemICInspector::sawOOBDenseWrite() const bool SetElemICInspector::sawOOBTypedArrayWrite() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!icEntry_) return false; @@ -54,6 +58,8 @@ SetElemICInspector::sawOOBTypedArrayWrite() const bool SetElemICInspector::sawDenseWrite() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!icEntry_) return false; @@ -68,6 +74,8 @@ SetElemICInspector::sawDenseWrite() const bool SetElemICInspector::sawTypedArrayWrite() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!icEntry_) return false; @@ -82,6 +90,8 @@ SetElemICInspector::sawTypedArrayWrite() const bool BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + // Return a list of shapes seen by the baseline IC for the current op. // An empty list indicates no shapes are known, or there was an uncacheable // access. @@ -139,6 +149,8 @@ BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes) ICStub * BaselineInspector::monomorphicStub(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return nullptr; @@ -156,6 +168,8 @@ BaselineInspector::monomorphicStub(jsbytecode *pc) bool BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return false; @@ -176,6 +190,8 @@ BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **pseco MIRType BaselineInspector::expectedResultType(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + // Look at the IC entries for this op to guess what type it will produce, // returning MIRType_None otherwise. @@ -222,6 +238,8 @@ CanUseInt32Compare(ICStub::Kind kind) MCompare::CompareType BaselineInspector::expectedCompareType(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + ICStub *first = monomorphicStub(pc), *second = nullptr; if (!first && !dimorphicStub(pc, &first, &second)) return MCompare::Compare_Unknown; @@ -304,6 +322,8 @@ TryToSpecializeBinaryArithOp(ICStub **stubs, MIRType BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + MIRType result; ICStub *stubs[2]; @@ -332,6 +352,8 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc) bool BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return false; @@ -346,6 +368,8 @@ BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc) bool BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return false; @@ -360,6 +384,8 @@ BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc) bool BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return false; @@ -374,6 +400,8 @@ BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc) bool BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT); if (!hasBaselineScript()) @@ -388,6 +416,8 @@ BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc) bool BaselineInspector::hasSeenDoubleResult(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return false; @@ -407,6 +437,8 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode *pc) JSObject * BaselineInspector::getTemplateObject(jsbytecode *pc) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return nullptr; @@ -434,6 +466,8 @@ BaselineInspector::getTemplateObject(jsbytecode *pc) JSObject * BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + if (!hasBaselineScript()) return nullptr; @@ -467,6 +501,8 @@ BaselineInspector::templateCallObject() JSObject * BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + const ICEntry &entry = icEntryFromPC(pc); for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isGetProp_CallScripted() || stub->isGetProp_CallNative()) { @@ -482,6 +518,8 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J JSObject * BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + const ICEntry &entry = icEntryFromPC(pc); for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) { if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) { diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 36e2867a888a..833a8ca0aaaf 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -237,7 +237,7 @@ jit::BaselineCompile(JSContext *cx, HandleScript script) JS_ASSERT_IF(status != Method_Compiled, !script->hasBaselineScript()); if (status == Method_CantCompile) - script->setBaselineScript(BASELINE_DISABLED_SCRIPT); + script->setBaselineScript(cx, BASELINE_DISABLED_SCRIPT); return status; } @@ -650,7 +650,7 @@ BaselineScript::copyPCMappingIndexEntries(const PCMappingIndexEntry *entries) uint8_t * BaselineScript::nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo) { - JS_ASSERT(script->baselineScript() == this); + JS_ASSERT_IF(script->hasBaselineScript(), script->baselineScript() == this); uint32_t pcOffset = script->pcToOffset(pc); @@ -892,7 +892,7 @@ jit::FinishDiscardBaselineScript(FreeOp *fop, JSScript *script) } BaselineScript *baseline = script->baselineScript(); - script->setBaselineScript(nullptr); + script->setBaselineScript(nullptr, nullptr); BaselineScript::Destroy(fop, baseline); } diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index 473edf187112..a9a6dc409e91 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -289,8 +289,8 @@ struct BaselineScript void toggleSPS(bool enable); - void noteAccessedGetter(uint32_t pcOffset); - void noteArrayWriteHole(uint32_t pcOffset); + void noteAccessedGetter(JSContext *cx, uint32_t pcOffset); + void noteArrayWriteHole(JSContext *cx, uint32_t pcOffset); static size_t offsetOfFlags() { return offsetof(BaselineScript, flags_); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 8dbe1e277efa..aeffad793ec0 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3389,14 +3389,14 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir) ool = oolCallVM(NewCallObjectInfo, lir, (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()), ImmGCPtr(templateObj->lastProperty()), - ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()), + ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()), ToRegister(lir->slots())), StoreRegisterTo(obj)); } else { ool = oolCallVM(NewCallObjectInfo, lir, (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()), ImmGCPtr(templateObj->lastProperty()), - ImmGCPtr(templateObj->hasLazyType() ? nullptr : templateObj->type()), + ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()), ImmPtr(nullptr)), StoreRegisterTo(obj)); } @@ -7409,8 +7409,7 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject) // out of the loop on Proxy::LazyProto. // Load the lhs's prototype. - masm.loadPtr(Address(objReg, JSObject::offsetOfType()), output); - masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output); + masm.loadObjProto(objReg, output); Label testLazy; { @@ -7424,14 +7423,13 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject) masm.jump(&done); masm.bind(¬PrototypeObject); - JS_ASSERT(uintptr_t(Proxy::LazyProto) == 1); + JS_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1); // Test for nullptr or Proxy::LazyProto masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy); // Load the current object's prototype. - masm.loadPtr(Address(output, JSObject::offsetOfType()), output); - masm.loadPtr(Address(output, offsetof(types::TypeObject, proto)), output); + masm.loadObjProto(output, output); masm.jump(&loopPrototypeChain); } diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index 874ad1487ebf..622a41b5d99c 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -45,9 +45,9 @@ class CompileInfo { public: CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing, - ExecutionMode executionMode) + ExecutionMode executionMode, bool scriptNeedsArgsObj) : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing), - executionMode_(executionMode) + executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj) { JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY); @@ -68,7 +68,7 @@ class CompileInfo CompileInfo(unsigned nlocals, ExecutionMode executionMode) : script_(nullptr), fun_(nullptr), osrPc_(nullptr), constructing_(false), - executionMode_(executionMode) + executionMode_(executionMode), scriptNeedsArgsObj_(false) { nimplicit_ = 0; nargs_ = 0; @@ -250,10 +250,10 @@ class CompileInfo return script()->argumentsAliasesFormals(); } bool needsArgsObj() const { - return script()->needsArgsObj(); + return scriptNeedsArgsObj_; } bool argsObjAliasesFormals() const { - return script()->argsObjAliasesFormals(); + return scriptNeedsArgsObj_ && !script()->strict(); } ExecutionMode executionMode() const { @@ -275,6 +275,11 @@ class CompileInfo jsbytecode *osrPc_; bool constructing_; ExecutionMode executionMode_; + + // Whether a script needs an arguments object is unstable over compilation + // since the arguments optimization could be marked as failed on the main + // thread, so cache a value here and use it throughout for consistency. + bool scriptNeedsArgsObj_; }; } // namespace jit diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index 58aaacf4a932..439bab359935 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -125,11 +125,13 @@ CompileRuntime::positiveInfinityValue() return runtime()->positiveInfinityValue; } +#ifdef DEBUG bool CompileRuntime::isInsideNursery(gc::Cell *cell) { return UninlinedIsInsideNursery(runtime(), cell); } +#endif const DOMCallbacks * CompileRuntime::DOMcallbacks() @@ -228,3 +230,10 @@ CompileCompartment::hasObjectMetadataCallback() { return compartment()->hasObjectMetadataCallback(); } + +AutoLockForCompilation::AutoLockForCompilation(CompileCompartment *compartment + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + init(compartment->compartment()->runtimeFromAnyThread()); +} diff --git a/js/src/jit/CompileWrappers.h b/js/src/jit/CompileWrappers.h index 487e063ea516..7da0253f9083 100644 --- a/js/src/jit/CompileWrappers.h +++ b/js/src/jit/CompileWrappers.h @@ -66,7 +66,9 @@ class CompileRuntime const Value &NaNValue(); const Value &positiveInfinityValue(); +#ifdef DEBUG bool isInsideNursery(gc::Cell *cell); +#endif // DOM callbacks must be threadsafe (and will hopefully be removed soon). const DOMCallbacks *DOMcallbacks(); @@ -96,6 +98,8 @@ class CompileCompartment { JSCompartment *compartment(); + friend class js::AutoLockForCompilation; + public: static CompileCompartment *get(JSCompartment *comp); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 547c5363c848..733f4a11067a 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -49,6 +49,8 @@ using namespace js; using namespace js::jit; +using mozilla::Maybe; + // Global variables. IonOptions jit::js_IonOptions; @@ -516,6 +518,8 @@ JitCompartment::ensureIonStubsExist(JSContext *cx) void jit::FinishOffThreadBuilder(IonBuilder *builder) { + builder->script()->runtimeFromMainThread()->removeCompilationThread(); + ExecutionMode executionMode = builder->info().executionMode(); // Clear the recompiling flag if it would have failed. @@ -1563,6 +1567,9 @@ AttachFinishedCompilations(JSContext *cx) // operation callback and can't propagate failures. cx->clearPendingException(); } + } else { + if (builder->abortReason() == AbortReason_Disable) + SetIonScript(builder->script(), builder->info().executionMode(), ION_DISABLED_SCRIPT); } FinishOffThreadBuilder(builder); @@ -1663,11 +1670,13 @@ IonCompile(JSContext *cx, JSScript *script, return AbortReason_Alloc; CompileInfo *info = alloc->new_(script, script->function(), osrPc, constructing, - executionMode); + executionMode, script->needsArgsObj()); if (!info) return AbortReason_Alloc; - BaselineInspector inspector(script); + BaselineInspector *inspector = alloc->new_(script); + if (!inspector) + return AbortReason_Alloc; BaselineFrameInspector *baselineFrameInspector = nullptr; if (baselineFrame) { @@ -1686,7 +1695,7 @@ IonCompile(JSContext *cx, JSScript *script, IonBuilder *builder = alloc->new_((JSContext *) nullptr, CompileCompartment::get(cx->compartment()), temp, graph, constraints, - &inspector, info, baselineFrameInspector); + inspector, info, baselineFrameInspector); if (!builder) return AbortReason_Alloc; @@ -1696,28 +1705,6 @@ IonCompile(JSContext *cx, JSScript *script, RootedScript builderScript(cx, builder->script()); IonSpewNewFunction(graph, builderScript); - mozilla::Maybe protect; - if (js_IonOptions.checkThreadSafety && - cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && - !cx->runtime()->profilingScripts && - !cx->runtime()->spsProfiler.enabled()) - { - protect.construct(cx->runtime()); - } - - bool succeeded = builder->build(); - builder->clearForBackEnd(); - - if (!succeeded) { - if (cx->isExceptionPending()) { - IonSpew(IonSpew_Abort, "Builder raised exception."); - return AbortReason_Error; - } - - IonSpew(IonSpew_Abort, "Builder failed to build."); - return builder->abortReason(); - } - // If possible, compile the script off thread. if (OffThreadCompilationAvailable(cx)) { if (recompile) { @@ -1739,6 +1726,24 @@ IonCompile(JSContext *cx, JSScript *script, return AbortReason_NoAbort; } + Maybe ionCompiling; + ionCompiling.construct(); + + Maybe protect; + if (js_IonOptions.checkThreadSafety && + cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && + !cx->runtime()->profilingScripts && + !cx->runtime()->spsProfiler.enabled()) + { + protect.construct(cx->runtime()); + } + + bool succeeded = builder->build(); + builder->clearForBackEnd(); + + if (!succeeded) + return builder->abortReason(); + ScopedJSDeletePtr codegen(CompileBackEnd(builder)); if (!codegen) { IonSpew(IonSpew_Abort, "Failed during back-end compilation."); @@ -1747,6 +1752,7 @@ IonCompile(JSContext *cx, JSScript *script, if (!protect.empty()) protect.destroy(); + ionCompiling.destroy(); bool success = codegen->link(cx, builder->constraints()); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 049c9de5c5c6..d70f534998bf 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -222,11 +222,10 @@ IsPhiObservable(MPhi *phi, Observability observe) if (fun && slot == info.thisSlot()) return true; - // If the function is heavyweight, and the Phi is of the |scopeChain| - // value, and the function may need an arguments object, then make sure - // to preserve the scope chain, because it may be needed to construct the - // arguments object during bailout. - if (fun && fun->isHeavyweight() && info.hasArguments() && slot == info.scopeChainSlot()) + // If the function may need an arguments object, then make sure to preserve + // the scope chain, because it may be needed to construct the arguments + // object during bailout. + if (fun && info.hasArguments() && slot == info.scopeChainSlot()) return true; // If the Phi is one of the formal argument, and we are using an argument @@ -2177,7 +2176,8 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun, MIRGraph graph(&temp); CompileInfo info(script, fun, /* osrPc = */ nullptr, /* constructing = */ false, - DefinitePropertiesAnalysis); + DefinitePropertiesAnalysis, + script->needsArgsObj()); AutoTempAllocatorRooter root(cx, &temp); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 934654267982..27d57b3609b2 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -135,16 +135,24 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Tem lazyArguments_(nullptr), inlineCallInfo_(nullptr) { - script_.init(info->script()); + script_ = info->script(); pc = info->startPC(); +#ifdef DEBUG + lock(); JS_ASSERT(script()->hasBaselineScript()); + unlock(); +#endif JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis)); } void IonBuilder::clearForBackEnd() { + // This case should only be hit if there was a failure while building. + if (!lock_.empty()) + lock_.destroy(); + JS_ASSERT(!analysisContext); baselineFrame_ = nullptr; @@ -581,12 +589,16 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e bool IonBuilder::init() { + lock(); + if (!types::TypeScript::FreezeTypeSets(constraints(), script(), &thisTypes, &argTypes, &typeArray)) { return false; } + unlock(); + if (!analysis().init(alloc(), gsn)) return false; @@ -694,6 +706,8 @@ IonBuilder::build() if (!traverseBytecode()) return false; + unlock(); + if (!maybeAddOsrTypeBarriers()) return false; @@ -851,6 +865,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi if (!traverseBytecode()) return false; + unlock(); return true; } @@ -905,6 +920,9 @@ IonBuilder::initParameters() // interpreter and didn't accumulate type information, try to use that OSR // frame to determine possible initial types for 'this' and parameters. + // For unknownProperties() tests under addType. + lock(); + if (thisTypes->empty() && baselineFrame_) { if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc())) return false; @@ -928,6 +946,8 @@ IonBuilder::initParameters() current->initSlot(info().argSlotUnchecked(i), param); } + unlock(); + return true; } @@ -950,6 +970,8 @@ IonBuilder::initScopeChain(MDefinition *callee) if (!script()->compileAndGo()) return abort("non-CNG global scripts are not supported"); + lock(); + if (JSFunction *fun = info().fun()) { if (!callee) { MCallee *calleeIns = MCallee::New(alloc()); @@ -975,6 +997,8 @@ IonBuilder::initScopeChain(MDefinition *callee) scope = constant(ObjectValue(script()->global())); } + unlock(); + current->setScopeChain(scope); return true; } @@ -1168,6 +1192,14 @@ IonBuilder::maybeAddOsrTypeBarriers() bool IonBuilder::traverseBytecode() { + // Always hold the compilation lock when traversing bytecode, though release + // it before reacquiring it every few opcodes so that the main thread does not + // block for long when updating compilation data. + lock(); + + size_t lockOpcodeCount = 0; + static const size_t LOCK_OPCODE_GRANULARITY = 5; + for (;;) { JS_ASSERT(pc < info().limitPC()); @@ -1242,6 +1274,12 @@ IonBuilder::traverseBytecode() if (!inspectOpcode(op)) return false; + if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) { + unlock(); + lock(); + lockOpcodeCount = 0; + } + #ifdef DEBUG for (size_t i = 0; i < popped.length(); i++) { // Call instructions can discard PassArg instructions. Ignore them. @@ -3845,13 +3883,16 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) LifoAlloc *lifoAlloc = alloc_->lifoAlloc(); CompileInfo *info = lifoAlloc->new_(calleeScript, target, (jsbytecode *)nullptr, callInfo.constructing(), - this->info().executionMode()); + this->info().executionMode(), + /* needsArgsObj = */ false); if (!info) return false; MIRGraphReturns returns(alloc()); AutoAccumulateReturns aar(graph(), returns); + unlock(); + // Build the graph. IonBuilder inlineBuilder(analysisContext, compartment, &alloc(), &graph(), constraints(), &inspector, info, nullptr, @@ -3875,6 +3916,8 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) return false; } + lock(); + // Create return block. jsbytecode *postCall = GetNextPc(pc); MBasicBlock *returnBlock = newBlock(nullptr, postCall); @@ -4698,7 +4741,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee) JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject || !templateObject->is()) return nullptr; - if (templateObject->getProto() != proto) + if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto) return nullptr; if (!target->nonLazyScript()->types) @@ -5096,6 +5139,8 @@ IonBuilder::testShouldDOMCall(types::TypeSet *inTypes, if (!curType) continue; + if (!curType->hasTenuredProto()) + return false; JSObject *proto = curType->proto().toObjectOrNull(); if (!instanceChecker(proto, jinfo->protoID, jinfo->depth)) return false; @@ -6031,6 +6076,8 @@ IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name) if (ClassHasResolveHook(compartment, obj->getClass(), name)) return nullptr; + if (!obj->hasTenuredProto()) + return nullptr; obj = obj->getProto(); } @@ -6104,6 +6151,8 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr if (property.isOwnProperty(constraints())) return false; + if (!object->hasTenuredProto()) + return false; if (JSObject *proto = object->proto().toObjectOrNull()) { // Test this type. if (testSingletonProperty(proto, name) != singleton) @@ -7897,6 +7946,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN return false; } + if (!type->hasTenuredProto()) + return false; JSObject *proto = type->proto().toObjectOrNull(); if (proto == foundProto) break; @@ -7996,7 +8047,7 @@ IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPro if (!baseTypeObj) continue; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(baseTypeObj); - if (typeObj->unknownProperties() || !typeObj->proto().isObject()) + if (typeObj->unknownProperties() || !typeObj->hasTenuredProto() || !typeObj->proto().isObject()) continue; const Class *clasp = typeObj->clasp(); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index b3094b74e461..6839e1d9d958 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -724,7 +724,7 @@ class IonBuilder : public MIRGenerator } // A builder is inextricably tied to a particular script. - HeapPtrScript script_; + JSScript *script_; // If off thread compilation is successful, the final code generator is // attached here. Code has been generated, but not linked (there is not yet @@ -735,7 +735,7 @@ class IonBuilder : public MIRGenerator public: void clearForBackEnd(); - JSScript *script() const { return script_.get(); } + JSScript *script() const { return script_; } CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; } void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; } @@ -765,6 +765,17 @@ class IonBuilder : public MIRGenerator // Constraints for recording dependencies on type information. types::CompilerConstraintList *constraints_; + mozilla::Maybe lock_; + + void lock() { + if (!analysisContext) + lock_.construct(compartment); + } + void unlock() { + if (!analysisContext) + lock_.destroy(); + } + // Basic analysis information about the script. BytecodeAnalysis analysis_; BytecodeAnalysis &analysis() { diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 188053a3a0b3..de66d8abf91c 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -468,7 +468,7 @@ GeneratePrototypeGuards(JSContext *cx, IonScript *ion, MacroAssembler &masm, JSO // Note: objectReg and scratchReg may be the same register, so we cannot // use objectReg in the rest of this function. masm.loadPtr(Address(objectReg, JSObject::offsetOfType()), scratchReg); - Address proto(scratchReg, offsetof(types::TypeObject, proto)); + Address proto(scratchReg, types::TypeObject::offsetOfProto()); masm.branchNurseryPtr(Assembler::NotEqual, proto, ImmMaybeNurseryPtr(obj->getProto()), failures); } @@ -796,11 +796,7 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm, Register lastReg = object; JS_ASSERT(scratchReg != object); while (proto) { - Address addrType(lastReg, JSObject::offsetOfType()); - masm.loadPtr(addrType, scratchReg); - Address addrProto(scratchReg, offsetof(types::TypeObject, proto)); - masm.loadPtr(addrProto, scratchReg); - Address addrShape(scratchReg, JSObject::offsetOfShape()); + masm.loadObjProto(lastReg, scratchReg); // Guard the shape of the current prototype. masm.branchPtr(Assembler::NotEqual, @@ -2584,8 +2580,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att Shape *protoShape = proto->lastProperty(); // load next prototype - masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg); - masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg); + masm.loadObjProto(protoReg, protoReg); // Ensure that its shape matches. masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &failuresPopObject); diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 35c9aaeb8fbe..2d5d85fc43d1 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -292,12 +292,12 @@ class MacroAssembler : public MacroAssemblerSpecific } void loadObjClass(Register objReg, Register dest) { loadPtr(Address(objReg, JSObject::offsetOfType()), dest); - loadPtr(Address(dest, offsetof(types::TypeObject, clasp)), dest); + loadPtr(Address(dest, types::TypeObject::offsetOfClasp()), dest); } void branchTestObjClass(Condition cond, Register obj, Register scratch, const js::Class *clasp, Label *label) { loadPtr(Address(obj, JSObject::offsetOfType()), scratch); - branchPtr(cond, Address(scratch, offsetof(types::TypeObject, clasp)), ImmPtr(clasp), label); + branchPtr(cond, Address(scratch, types::TypeObject::offsetOfClasp()), ImmPtr(clasp), label); } void branchTestObjShape(Condition cond, Register obj, const Shape *shape, Label *label) { branchPtr(cond, Address(obj, JSObject::offsetOfShape()), ImmGCPtr(shape), label); @@ -353,7 +353,7 @@ class MacroAssembler : public MacroAssemblerSpecific void loadObjProto(Register obj, Register dest) { loadPtr(Address(obj, JSObject::offsetOfType()), dest); - loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest); + loadPtr(Address(dest, types::TypeObject::offsetOfProto()), dest); } void loadStringLength(Register str, Register dest) { diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 6c3efded51fe..92cff151ffb4 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2929,7 +2929,13 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, // If this access has never executed, try to add types to the observed set // according to any property which exists on the object or its prototype. if (updateObserved && observed->empty() && name) { - JSObject *obj = object->singleton() ? object->singleton() : object->proto().toObjectOrNull(); + JSObject *obj; + if (object->singleton()) + obj = object->singleton(); + else if (object->hasTenuredProto()) + obj = object->proto().toObjectOrNull(); + else + obj = nullptr; while (obj) { if (!obj->getClass()->isNative()) @@ -2953,6 +2959,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, } } + if (!obj->hasTenuredProto()) + break; obj = obj->getProto(); } } @@ -3004,7 +3012,11 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons types::TypeObjectKey *object = types->getObject(i); if (!object) continue; - while (object->proto().isObject()) { + while (true) { + if (!object->hasTenuredProto()) + return true; + if (!object->proto().isObject()) + break; object = types::TypeObjectKey::get(object->proto().toObject()); if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed)) return true; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 717a2703df7a..061f84714bb1 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -946,7 +946,7 @@ AssertValidObjectPtr(JSContext *cx, JSObject *obj) JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime()); JS_ASSERT_IF(!obj->hasLazyType(), - obj->type()->clasp == obj->lastProperty()->getObjectClass()); + obj->type()->clasp() == obj->lastProperty()->getObjectClass()); if (obj->isTenured()) { JS_ASSERT(obj->isAligned()); diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 2a563f422cac..2163c0e7cb97 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -1725,7 +1725,7 @@ CodeGeneratorX86Shared::visitGuardClass(LGuardClass *guard) Register tmp = ToRegister(guard->tempInt()); masm.loadPtr(Address(obj, JSObject::offsetOfType()), tmp); - masm.cmpPtr(Operand(tmp, offsetof(types::TypeObject, clasp)), ImmPtr(guard->mir()->getClass())); + masm.cmpPtr(Operand(tmp, types::TypeObject::offsetOfClasp()), ImmPtr(guard->mir()->getClass())); if (!bailoutIf(Assembler::NotEqual, guard->snapshot())) return false; return true; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 602bac144815..cbc4567c0dd0 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -116,6 +116,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite()); JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); JS_ASSERT(types::UseNewTypeForClone(fun)); + JS_ASSERT(CurrentThreadCanReadCompilationData()); /* * If we start allocating function objects in the nursery, then the callsite @@ -126,7 +127,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction if (!table.initialized()) return nullptr; - CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc))); + CallsiteCloneTable::Ptr p = table.readonlyThreadsafeLookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc))); if (p) return p->value(); @@ -153,6 +154,8 @@ js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript scri typedef CallsiteCloneKey Key; typedef CallsiteCloneTable Table; + AutoLockForCompilation lock(cx); + Table &table = cx->compartment()->callsiteClones; if (!table.initialized() && !table.init()) return nullptr; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 691e0a0c26f7..3aee93c84a20 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -32,7 +32,10 @@ js_ReportOverRecursed(js::ThreadSafeContext *cx); namespace js { -namespace jit { class IonContext; } +namespace jit { +class IonContext; +class CompileCompartment; +} struct CallsiteCloneKey { /* The original function that we are cloning. */ @@ -1038,7 +1041,9 @@ class AutoLockForExclusiveAccess if (runtime->numExclusiveThreads) { runtime->assertCanLock(JSRuntime::ExclusiveAccessLock); PR_Lock(runtime->exclusiveAccessLock); +#ifdef DEBUG runtime->exclusiveAccessOwner = PR_GetCurrentThread(); +#endif } else { JS_ASSERT(!runtime->mainThreadHasExclusiveAccess); runtime->mainThreadHasExclusiveAccess = true; @@ -1057,9 +1062,7 @@ class AutoLockForExclusiveAccess ~AutoLockForExclusiveAccess() { if (runtime->numExclusiveThreads) { JS_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread()); -#ifdef DEBUG runtime->exclusiveAccessOwner = nullptr; -#endif PR_Unlock(runtime->exclusiveAccessLock); } else { JS_ASSERT(runtime->mainThreadHasExclusiveAccess); @@ -1083,6 +1086,69 @@ class AutoLockForExclusiveAccess MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +class AutoLockForCompilation +{ +#ifdef JS_WORKER_THREADS + JSRuntime *runtime; + + void init(JSRuntime *rt) { + runtime = rt; + if (runtime->numCompilationThreads) { + runtime->assertCanLock(JSRuntime::CompilationLock); + PR_Lock(runtime->compilationLock); +#ifdef DEBUG + runtime->compilationLockOwner = PR_GetCurrentThread(); +#endif + } else { +#ifdef DEBUG + JS_ASSERT(!runtime->mainThreadHasCompilationLock); + runtime->mainThreadHasCompilationLock = true; +#endif + } + } + + public: + AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (cx->isJSContext()) + init(cx->asJSContext()->runtime()); + else + runtime = nullptr; + } + AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoLockForCompilation() { + if (runtime) { + if (runtime->numCompilationThreads) { + JS_ASSERT(runtime->compilationLockOwner == PR_GetCurrentThread()); +#ifdef DEBUG + runtime->compilationLockOwner = nullptr; +#endif + PR_Unlock(runtime->compilationLock); + } else { +#ifdef DEBUG + JS_ASSERT(runtime->mainThreadHasCompilationLock); + runtime->mainThreadHasCompilationLock = false; +#endif + } + } + } +#else // JS_WORKER_THREADS + public: + AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoLockForCompilation() { + // An empty destructor is needed to avoid warnings from clang about + // unused local variables of this type. + } +#endif // JS_WORKER_THREADS + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + } /* namespace js */ #ifdef _MSC_VER diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 84f911528a8e..326593b23ef6 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -338,7 +338,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin return true; } - RootedObject proto(cx, Proxy::LazyProto); + RootedObject proto(cx, TaggedProto::LazyProto); RootedObject existing(cx, existingArg); if (existing) { /* Is it possible to reuse |existing|? */ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 9d1624cb3e43..2eb8d021ae7f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1124,25 +1124,21 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti // THING_ROOT_LAZY_SCRIPT). AutoSuppressGC suppressGC(cx); - fun->flags_ &= ~INTERPRETED_LAZY; - fun->flags_ |= INTERPRETED; - RootedScript script(cx, lazy->maybeScript()); if (script) { - fun->initScript(script); + AutoLockForCompilation lock(cx); + fun->setUnlazifiedScript(script); return true; } - fun->initScript(nullptr); - if (fun != lazy->function()) { script = lazy->function()->getOrCreateScript(cx); - if (!script) { - fun->initLazyScript(lazy); + if (!script) return false; - } - fun->initScript(script); + + AutoLockForCompilation lock(cx); + fun->setUnlazifiedScript(script); return true; } @@ -1162,17 +1158,19 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti if (script) { RootedObject enclosingScope(cx, lazy->enclosingScope()); RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script)); - if (!clonedScript) { - fun->initLazyScript(lazy); + if (!clonedScript) return false; - } clonedScript->setSourceObject(lazy->sourceObject()); fun->initAtom(script->function()->displayAtom()); - fun->initScript(clonedScript); clonedScript->setFunction(fun); + { + AutoLockForCompilation lock(cx); + fun->setUnlazifiedScript(clonedScript); + } + CallNewScriptHook(cx, clonedScript, fun); lazy->initScript(clonedScript); @@ -1184,18 +1182,14 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti // Parse and compile the script from source. SourceDataCache::AutoSuppressPurge asp(cx); const jschar *chars = lazy->source()->chars(cx, asp); - if (!chars) { - fun->initLazyScript(lazy); + if (!chars) return false; - } const jschar *lazyStart = chars + lazy->begin(); size_t lazyLength = lazy->end() - lazy->begin(); - if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) { - fun->initLazyScript(lazy); + if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) return false; - } script = fun->nonLazyScript(); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 9638848e4aad..f0df951a511f 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -123,8 +123,6 @@ class JSFunction : public JSObject /* Possible attributes of an interpreted function: */ bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; } - bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; } - bool hasScript() const { return flags() & INTERPRETED; } bool isExprClosure() const { return flags() & EXPR_CLOSURE; } bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } bool isLambda() const { return flags() & LAMBDA; } @@ -136,6 +134,17 @@ class JSFunction : public JSObject return flags() & SH_WRAPPABLE; } + // Functions can change between being lazily interpreted and having scripts + // when under the compilation lock. + bool isInterpretedLazy() const { + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); + return flags() & INTERPRETED_LAZY; + } + bool hasScript() const { + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); + return flags() & INTERPRETED; + } + bool hasJITCode() const { if (!hasScript()) return false; @@ -321,6 +330,7 @@ class JSFunction : public JSObject JSScript *nonLazyScript() const { JS_ASSERT(hasScript()); + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); return u.i.s.script_; } @@ -331,11 +341,13 @@ class JSFunction : public JSObject js::LazyScript *lazyScript() const { JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_); + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); return u.i.s.lazy_; } js::LazyScript *lazyScriptOrNull() const { JS_ASSERT(isInterpretedLazy()); + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); return u.i.s.lazy_; } @@ -357,15 +369,25 @@ class JSFunction : public JSObject bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } void setScript(JSScript *script_) { - JS_ASSERT(isInterpreted()); + JS_ASSERT(hasScript()); mutableScript() = script_; } void initScript(JSScript *script_) { - JS_ASSERT(isInterpreted()); + JS_ASSERT(hasScript()); mutableScript().init(script_); } + void setUnlazifiedScript(JSScript *script) { + // Note: createScriptForLazilyInterpretedFunction triggers a barrier on + // lazy script before it is overwritten here. + JS_ASSERT(js::CurrentThreadCanWriteCompilationData()); + JS_ASSERT(isInterpretedLazy()); + flags_ &= ~INTERPRETED_LAZY; + flags_ |= INTERPRETED; + initScript(script); + } + void initLazyScript(js::LazyScript *lazy) { JS_ASSERT(isInterpreted()); flags_ &= ~INTERPRETED; diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 7fe019b6902e..5bfec3ee4129 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -685,6 +685,8 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script TemporaryTypeSet **pArgTypes, TemporaryTypeSet **pBytecodeTypes) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + LifoAlloc *alloc = constraints->alloc(); StackTypeSet *existing = script->types->typeArray(); @@ -791,13 +793,26 @@ CompilerConstraintInstance::generateTypeConstraint(JSContext *cx, RecompileIn const Class * TypeObjectKey::clasp() { - return isTypeObject() ? asTypeObject()->clasp : asSingleObject()->getClass(); + return isTypeObject() ? asTypeObject()->clasp() : asSingleObject()->getClass(); } TaggedProto TypeObjectKey::proto() { - return isTypeObject() ? TaggedProto(asTypeObject()->proto) : asSingleObject()->getTaggedProto(); + JS_ASSERT(hasTenuredProto()); + return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto(); +} + +bool +ObjectImpl::hasTenuredProto() const +{ + return type_->hasTenuredProto(); +} + +bool +TypeObjectKey::hasTenuredProto() +{ + return isTypeObject() ? asTypeObject()->hasTenuredProto() : asSingleObject()->hasTenuredProto(); } JSObject * @@ -836,6 +851,7 @@ HeapTypeSetKey TypeObjectKey::property(jsid id) { JS_ASSERT(!unknownProperties()); + JS_ASSERT(CurrentThreadCanReadCompilationData()); HeapTypeSetKey property; property.object_ = this; @@ -1429,8 +1445,10 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY); /* Mark as unknown after getting the types, to avoid assertion. */ - if (markingUnknown) - object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES; + if (markingUnknown) { + AutoLockForCompilation lock(cxArg); + object->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES); + } if (types) { if (JSContext *cx = cxArg->maybeJSContext()) { @@ -1678,6 +1696,9 @@ TemporaryTypeSet::getCommonPrototype() if (!object) continue; + if (!object->hasTenuredProto()) + return nullptr; + TaggedProto nproto = object->proto(); if (proto) { if (nproto != proto) @@ -1737,18 +1758,24 @@ TypeZone::init(JSContext *cx) } TypeObject * -TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle proto, bool unknown) +TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle proto, + TypeObjectFlags initialFlags) { JS_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject())); + if (!cx->typeInferenceEnabled()) + initialFlags |= OBJECT_FLAG_UNKNOWN_MASK; + + if (cx->isJSContext()) { + if (proto.isObject() && IsInsideNursery(cx->asJSContext()->runtime(), proto.toObject())) + initialFlags |= OBJECT_FLAG_NURSERY_PROTO; + } + TypeObject *object = gc::NewGCThing(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject), gc::TenuredHeap); if (!object) return nullptr; - new(object) TypeObject(clasp, proto, unknown); - - if (!cx->typeInferenceEnabled()) - object->flags |= OBJECT_FLAG_UNKNOWN_MASK; + new(object) TypeObject(clasp, proto, initialFlags); return object; } @@ -1871,12 +1898,11 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke return nullptr; Rooted tagged(cx, TaggedProto(proto)); - res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged); + res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE); if (!res) { cx->compartment()->types.setPendingNukeTypes(cx); return nullptr; } - res->flags |= OBJECT_FLAG_FROM_ALLOCATION_SITE; key.script = keyScript; } @@ -2010,6 +2036,8 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj) HeapTypeSetKey index = type->property(JSID_VOID); if (index.configured(constraints) || index.isOwnProperty(constraints)) return true; + if (!obj->hasTenuredProto()) + return true; obj = obj->getProto(); } while (obj); @@ -2175,10 +2203,9 @@ void TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target) { JS_ASSERT(this == &cx->compartment()->types); - JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN)); + JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN)); JS_ASSERT(!target->singleton); JS_ASSERT(target->unknownProperties()); - target->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN; AutoEnterAnalysis enter(cx); @@ -2219,6 +2246,9 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target) } } } + + AutoLockForCompilation lock(cx); + target->addFlags(OBJECT_FLAG_SETS_MARKED_UNKNOWN); } void @@ -2511,7 +2541,7 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj) ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup); if (p) { - JS_ASSERT(obj->getProto() == p->value().object->proto); + JS_ASSERT(obj->getProto() == p->value().object->proto().toObject()); JS_ASSERT(obj->lastProperty() == p->value().shape); UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length()); @@ -2614,7 +2644,7 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n cx->clearPendingException(); return nullptr; } - JS_ASSERT(obj->getProto() == p->value().object->proto); + JS_ASSERT(obj->getProto() == p->value().object->proto().toObject()); RootedShape shape(cx, p->value().shape); if (!JSObject::setLastProperty(cx, obj, shape)) { @@ -2635,6 +2665,36 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n // TypeObject ///////////////////////////////////////////////////////////////////// +#ifdef DEBUG +void +TypeObject::assertCanAccessProto() +{ + // The proto pointer for type objects representing singletons may move. + JS_ASSERT_IF(singleton, CurrentThreadCanReadCompilationData()); + + // Any proto pointer which is in the nursery may be moved, and may not be + // accessed during off thread compilation. +#if defined(JSGC_GENERATIONAL) && defined(JS_WORKER_THREADS) + PerThreadData *pt = TlsPerThreadData.get(); + TaggedProto proto(proto_); + JS_ASSERT_IF(proto.isObject() && !proto.toObject()->isTenured(), + !pt || !pt->ionCompiling); +#endif +} +#endif // DEBUG + +void +TypeObject::setProto(JSContext *cx, TaggedProto proto) +{ + JS_ASSERT(CurrentThreadCanWriteCompilationData()); + JS_ASSERT(singleton); + + if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject())) + addFlags(OBJECT_FLAG_NURSERY_PROTO); + + setProtoUnchecked(proto); +} + static inline void UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shape *shape, bool indexed) @@ -2644,7 +2704,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap if (shape->hasGetterValue() || shape->hasSetterValue()) { types->setConfiguredProperty(cx); - types->addType(cx, Type::UnknownType()); + if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc())) + cx->compartment()->types.setPendingNukeTypes(cx); } else if (shape->hasDefaultGetter() && shape->hasSlot()) { if (!indexed && types->canSetDefinite(shape->slot())) types->setDefinite(shape->slot()); @@ -2658,7 +2719,8 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap */ if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) { Type type = GetValueType(value); - types->addType(cx, type); + if (!types->TypeSet::addType(type, &cx->typeLifoAlloc())) + cx->compartment()->types.setPendingNukeTypes(cx); } } } @@ -2696,7 +2758,8 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop) const Value &value = singleton->getDenseElement(i); if (!value.isMagic(JS_ELEMENTS_HOLE)) { Type type = GetValueType(value); - base->types.addType(cx, type); + if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc())) + cx->compartment()->types.setPendingNukeTypes(cx); } } } else if (!JSID_IS_EMPTY(id)) { @@ -2871,7 +2934,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg) void TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags) { - if ((this->flags & flags) == flags) + if (hasAllFlags(flags)) return; AutoEnterAnalysis enter(cx); @@ -2882,7 +2945,10 @@ TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags) singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON)); } - this->flags |= flags; + { + AutoLockForCompilation lock(cx); + addFlags(flags); + } InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags); @@ -2897,7 +2963,7 @@ TypeObject::markUnknown(ExclusiveContext *cx) JS_ASSERT(cx->compartment()->activeAnalysis); JS_ASSERT(!unknownProperties()); - if (!(flags & OBJECT_FLAG_ADDENDUM_CLEARED)) + if (!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED)) clearAddendum(cx); InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this)); @@ -2926,8 +2992,11 @@ TypeObject::markUnknown(ExclusiveContext *cx) void TypeObject::clearAddendum(ExclusiveContext *cx) { - JS_ASSERT(!(flags & OBJECT_FLAG_ADDENDUM_CLEARED)); - flags |= OBJECT_FLAG_ADDENDUM_CLEARED; + JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED)); + { + AutoLockForCompilation lock(cx); + addFlags(OBJECT_FLAG_ADDENDUM_CLEARED); + } /* * It is possible for the object to not have a new script or other @@ -3072,11 +3141,11 @@ TypeObject::clearTypedObjectAddendum(ExclusiveContext *cx) void TypeObject::print() { - TaggedProto tagged(proto); + TaggedProto tagged(proto()); fprintf(stderr, "%s : %s", - TypeObjectString(this), - tagged.isObject() ? TypeString(Type::ObjectType(proto)) - : (tagged.isLazy() ? "(lazy)" : "(null)")); + TypeObjectString(this), + tagged.isObject() ? TypeString(Type::ObjectType(tagged.toObject())) + : (tagged.isLazy() ? "(lazy)" : "(null)")); if (unknownProperties()) { fprintf(stderr, " unknown"); @@ -3142,7 +3211,7 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint * non-writable, both of which are indicated by the source type set * being marked as configured. */ - if (!(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty()) + if (!(object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty()) object->clearAddendum(cx); } @@ -3166,7 +3235,7 @@ types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject * * a permanent property in any transitive prototype, the definite * properties get cleared from the type. */ - RootedObject parent(cx, type->proto); + RootedObject parent(cx, type->proto().toObjectOrNull()); while (parent) { TypeObject *parentObject = parent->getType(cx); if (!parentObject || parentObject->unknownProperties()) @@ -3196,7 +3265,7 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint const char *kind() { return "clearDefiniteSingle"; } void newType(JSContext *cx, TypeSet *source, Type type) { - if (object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) + if (object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED) return; if (source->baseFlags() || source->getObjectCount() > 1) @@ -3279,9 +3348,9 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun) } if (baseobj->slotSpan() == 0 || - !!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED)) + !!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)) { - if (type->addendum) + if (type->hasNewScript()) type->clearAddendum(cx); return; } @@ -3296,8 +3365,8 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun) type->clearAddendum(cx); return; } - JS_ASSERT(!type->addendum); - JS_ASSERT(!(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED)); + JS_ASSERT(!type->hasNewScript()); + JS_ASSERT(!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)); gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan()); @@ -3336,7 +3405,11 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun) newScript = (TypeNewScript *) cx->calloc_(numBytes); #endif new (newScript) TypeNewScript(); - type->addendum = newScript; + + { + AutoLockForCompilation lock(cx); + type->setAddendum(newScript); + } if (!newScript) { cx->compartment()->types.setPendingNukeTypes(cx); @@ -3633,8 +3706,11 @@ JSObject::splicePrototype(JSContext *cx, const Class *clasp, Handle return true; } - type->clasp = clasp; - type->proto = proto.raw(); + { + AutoLockForCompilation lock(cx); + type->setClasp(clasp); + type->setProto(cx, proto); + } return true; } @@ -3651,8 +3727,22 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj) if (!fun->getOrCreateScript(cx)) return nullptr; } + + // Find flags which need to be specified immediately on the object. + // Don't track whether singletons are packed. + TypeObjectFlags initialFlags = OBJECT_FLAG_NON_PACKED; + + if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON)) + initialFlags |= OBJECT_FLAG_ITERATED; + + if (obj->isIndexed()) + initialFlags |= OBJECT_FLAG_SPARSE_INDEXES; + + if (obj->is() && obj->as().length() > INT32_MAX) + initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW; + Rooted proto(cx, obj->getTaggedProto()); - TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto); + TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags); if (!type) { if (cx->typeInferenceEnabled()) cx->compartment()->types.setPendingNukeTypes(cx); @@ -3674,24 +3764,10 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj) if (obj->is() && obj->as().isInterpreted()) type->interpretedFunction = &obj->as(); - if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON)) - type->flags |= OBJECT_FLAG_ITERATED; - - /* - * Adjust flags for objects which will have the wrong flags set by just - * looking at the class prototype key. - */ - - /* Don't track whether singletons are packed. */ - type->flags |= OBJECT_FLAG_NON_PACKED; - - if (obj->isIndexed()) - type->flags |= OBJECT_FLAG_SPARSE_INDEXES; - - if (obj->is() && obj->as().length() > INT32_MAX) - type->flags |= OBJECT_FLAG_LENGTH_OVERFLOW; - - obj->type_ = type; + { + AutoLockForCompilation lock(cx); + obj->type_ = type; + } return type; } @@ -3707,8 +3783,8 @@ TypeObjectWithNewScriptEntry::hash(const Lookup &lookup) /* static */ inline bool TypeObjectWithNewScriptEntry::match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup) { - return key.object->proto == lookup.matchProto.raw() && - key.object->clasp == lookup.clasp && + return key.object->proto() == lookup.matchProto && + key.object->clasp() == lookup.clasp && key.newFunction == lookup.newFunction; } @@ -3805,8 +3881,8 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction * newTypeObjects.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, fun)); if (p) { TypeObject *type = p->object; - JS_ASSERT(type->clasp == clasp); - JS_ASSERT(type->proto.get() == proto.raw()); + JS_ASSERT(type->clasp() == clasp); + JS_ASSERT(type->proto() == proto); JS_ASSERT_IF(type->hasNewScript(), type->newScript()->fun == fun); return type; } @@ -3816,13 +3892,19 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction * if (proto.isObject() && !proto.toObject()->setDelegate(this)) return nullptr; - bool markUnknown = - proto.isObject() - ? proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN) - : true; + TypeObjectFlags initialFlags = 0; + if (!proto.isObject() || proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)) { + // The new type is not present in any type sets, so mark the object as + // unknown in all type sets it appears in. This allows the prototype of + // such objects to mutate freely without triggering an expensive walk of + // the compartment's type sets. (While scripts normally don't mutate + // __proto__, the browser will for proxies and such, and we need to + // accommodate this behavior). + initialFlags = OBJECT_FLAG_UNKNOWN_MASK | OBJECT_FLAG_SETS_MARKED_UNKNOWN; + } Rooted protoRoot(this, proto); - TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, markUnknown); + TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, initialFlags); if (!type) return nullptr; @@ -3872,17 +3954,6 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction * } } - /* - * The new type is not present in any type sets, so mark the object as - * unknown in all type sets it appears in. This allows the prototype of - * such objects to mutate freely without triggering an expensive walk of - * the compartment's type sets. (While scripts normally don't mutate - * __proto__, the browser will for proxies and such, and we need to - * accommodate this behavior). - */ - if (type->unknownProperties()) - type->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN; - return type; } @@ -3907,7 +3978,7 @@ ExclusiveContext::getLazyType(const Class *clasp, TaggedProto proto) } Rooted protoRoot(this, proto); - TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot, false); + TypeObject *type = compartment()->types.newTypeObject(this, clasp, protoRoot); if (!type) return nullptr; @@ -4159,8 +4230,8 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table) } else if (entry.newFunction && IsObjectAboutToBeFinalized(&entry.newFunction)) { e.removeFront(); } else if (entry.object != e.front().object) { - TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp, - entry.object->proto.get(), + TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp(), + entry.object->proto(), entry.newFunction); e.rekeyFront(lookup, entry); } @@ -4428,7 +4499,7 @@ TypeObject::addTypedObjectAddendum(JSContext *cx, JS_ASSERT(repr); - if (flags & OBJECT_FLAG_ADDENDUM_CLEARED) + if (flags() & OBJECT_FLAG_ADDENDUM_CLEARED) return true; JS_ASSERT(!unknownProperties()); diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index e5d8ac01cfc3..ff7c27970b00 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -25,20 +25,38 @@ namespace js { +#ifdef DEBUG +bool CurrentThreadCanWriteCompilationData(); +bool CurrentThreadCanReadCompilationData(); +#endif + class TypeRepresentation; class TaggedProto { public: + static JSObject * const LazyProto; + TaggedProto() : proto(nullptr) {} TaggedProto(JSObject *proto) : proto(proto) {} uintptr_t toWord() const { return uintptr_t(proto); } - inline bool isLazy() const; - inline bool isObject() const; - inline JSObject *toObject() const; - inline JSObject *toObjectOrNull() const; + bool isLazy() const { + return proto == LazyProto; + } + bool isObject() const { + /* Skip nullptr and LazyProto. */ + return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto); + } + JSObject *toObject() const { + JS_ASSERT(isObject()); + return proto; + } + JSObject *toObjectOrNull() const { + JS_ASSERT(!proto || isObject()); + return proto; + } JSObject *raw() const { return proto; } bool operator ==(const TaggedProto &other) { return proto == other.proto; } @@ -77,10 +95,10 @@ class TaggedProtoOperations public: uintptr_t toWord() const { return value()->toWord(); } - inline bool isLazy() const; - inline bool isObject() const; - inline JSObject *toObject() const; - inline JSObject *toObjectOrNull() const; + inline bool isLazy() const { return value()->isLazy(); } + inline bool isObject() const { return value()->isObject(); } + inline JSObject *toObject() const { return value()->toObject(); } + inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } JSObject *raw() const { return value()->raw(); } }; @@ -383,6 +401,12 @@ enum MOZ_ENUM_TYPE(uint32_t) { /* If set, addendum information should not be installed on this object. */ OBJECT_FLAG_ADDENDUM_CLEARED = 0x2, + /* + * If set, the object's prototype might be in the nursery and can't be + * used during Ion compilation (which may be occurring off thread). + */ + OBJECT_FLAG_NURSERY_PROTO = 0x4, + /* * Whether we have ensured all type sets in the compartment contain * ANYOBJECT instead of this object. @@ -503,7 +527,7 @@ class TypeSet static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc); /* Add a type to this set using the specified allocator. */ - inline bool addType(Type type, LifoAlloc *alloc, bool *padded = nullptr); + inline bool addType(Type type, LifoAlloc *alloc); /* Get a list of all types in this set. */ typedef Vector TypeList; @@ -857,11 +881,45 @@ struct TypeTypedObject : public TypeObjectAddendum /* Type information about an object accessed by a script. */ struct TypeObject : gc::BarrieredCell { - /* Class shared by objects using this type. */ - const Class *clasp; + private: + /* Class shared by object using this type. */ + const Class *clasp_; /* Prototype shared by objects using this type. */ - HeapPtrObject proto; + HeapPtrObject proto_; + +#ifdef DEBUG + void assertCanAccessProto(); +#else + void assertCanAccessProto() {} +#endif + + public: + + const Class *clasp() { + return clasp_; + } + + void setClasp(const Class *clasp) { + JS_ASSERT(CurrentThreadCanWriteCompilationData()); + JS_ASSERT(singleton); + clasp_ = clasp; + } + + TaggedProto proto() { + assertCanAccessProto(); + return TaggedProto(proto_); + } + + HeapPtrObject &protoRaw() { + // For use during marking, don't call otherwise. + return proto_; + } + + void setProto(JSContext *cx, TaggedProto proto); + void setProtoUnchecked(TaggedProto proto) { + proto_ = proto.raw(); + } /* * Whether there is a singleton JS object with this type. That JS object @@ -877,8 +935,9 @@ struct TypeObject : gc::BarrieredCell static const size_t LAZY_SINGLETON = 1; bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; } + private: /* Flags for this object. */ - TypeObjectFlags flags; + TypeObjectFlags flags_; /* * This field allows various special classes of objects to attach @@ -891,23 +950,48 @@ struct TypeObject : gc::BarrieredCell * before the object escapes. */ HeapPtr addendum; + public: + + TypeObjectFlags flags() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); + return flags_; + } + + void addFlags(TypeObjectFlags flags) { + JS_ASSERT(CurrentThreadCanWriteCompilationData()); + flags_ |= flags; + } + + void clearFlags(TypeObjectFlags flags) { + JS_ASSERT(CurrentThreadCanWriteCompilationData()); + flags_ &= ~flags; + } bool hasNewScript() const { + JS_ASSERT(CurrentThreadCanReadCompilationData()); return addendum && addendum->isNewScript(); } TypeNewScript *newScript() { + JS_ASSERT(CurrentThreadCanReadCompilationData()); return addendum->asNewScript(); } bool hasTypedObject() { + JS_ASSERT(CurrentThreadCanReadCompilationData()); return addendum && addendum->isTypedObject(); } TypeTypedObject *typedObject() { + JS_ASSERT(CurrentThreadCanReadCompilationData()); return addendum->asTypedObject(); } + void setAddendum(TypeObjectAddendum *addendum) { + JS_ASSERT(CurrentThreadCanWriteCompilationData()); + this->addendum = addendum; + } + /* * Tag the type object for a binary data type descriptor, instance, * or handle with the type representation of the data it points at. @@ -919,6 +1003,7 @@ struct TypeObject : gc::BarrieredCell TypeTypedObject::Kind kind , TypeRepresentation *repr); + private: /* * Properties of this object. This may contain JSID_VOID, representing the * types of all integer indexes of the object, and/or JSID_EMPTY, holding @@ -953,6 +1038,7 @@ struct TypeObject : gc::BarrieredCell * might update the property with a new type. */ Property **propertySet; + public: /* If this is an interpreted function, the function object. */ HeapPtrFunction interpretedFunction; @@ -961,27 +1047,31 @@ struct TypeObject : gc::BarrieredCell uint32_t padding; #endif - inline TypeObject(const Class *clasp, TaggedProto proto, bool unknown); + inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags); bool hasAnyFlags(TypeObjectFlags flags) { JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); - return !!(this->flags & flags); + return !!(this->flags() & flags); } bool hasAllFlags(TypeObjectFlags flags) { JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); - return (this->flags & flags) == flags; + return (this->flags() & flags) == flags; } bool unknownProperties() { - JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES, + JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES, hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); - return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES); + return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES); } bool shouldPreTenure() { return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties(); } + bool hasTenuredProto() const { + return !(flags() & OBJECT_FLAG_NURSERY_PROTO); + } + gc::InitialHeap initialHeap(CompilerConstraintList *constraints); bool canPreTenure() { @@ -991,7 +1081,7 @@ struct TypeObject : gc::BarrieredCell // this bit reliably. if (unknownProperties()) return false; - return (flags & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript(); + return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript(); } void setShouldPreTenure(ExclusiveContext *cx) { @@ -1046,12 +1136,20 @@ struct TypeObject : gc::BarrieredCell static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; } + static inline uint32_t offsetOfClasp() { + return offsetof(TypeObject, clasp_); + } + + static inline uint32_t offsetOfProto() { + return offsetof(TypeObject, proto_); + } + private: inline uint32_t basePropertyCount() const; inline void setBasePropertyCount(uint32_t count); static void staticAsserts() { - JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto)); + JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto)); } }; @@ -1247,6 +1345,7 @@ struct TypeObjectKey const Class *clasp(); TaggedProto proto(); + bool hasTenuredProto(); JSObject *singleton(); TypeNewScript *newScript(); @@ -1416,7 +1515,7 @@ struct TypeCompartment * js_ObjectClass). */ TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle proto, - bool unknown = false); + TypeObjectFlags initialFlags = 0); /* Get or make an object for an allocation site, and add to the allocation site table. */ TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 5d6f7b38f608..ab4186e83ef9 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -25,61 +25,6 @@ #include "jsanalyzeinlines.h" #include "jscntxtinlines.h" -inline bool -js::TaggedProto::isObject() const -{ - /* Skip nullptr and Proxy::LazyProto. */ - return uintptr_t(proto) > uintptr_t(Proxy::LazyProto); -} - -inline bool -js::TaggedProto::isLazy() const -{ - return proto == Proxy::LazyProto; -} - -inline JSObject * -js::TaggedProto::toObject() const -{ - JS_ASSERT(isObject()); - return proto; -} - -inline JSObject * -js::TaggedProto::toObjectOrNull() const -{ - JS_ASSERT(!proto || isObject()); - return proto; -} - -template -inline bool -js::TaggedProtoOperations::isLazy() const -{ - return value()->isLazy(); -} - -template -inline bool -js::TaggedProtoOperations::isObject() const -{ - return value()->isObject(); -} - -template -inline JSObject * -js::TaggedProtoOperations::toObject() const -{ - return value()->toObject(); -} - -template -inline JSObject * -js::TaggedProtoOperations::toObjectOrNull() const -{ - return value()->toObjectOrNull(); -} - namespace js { namespace types { @@ -534,7 +479,7 @@ MarkTypeObjectUnknownProperties(JSContext *cx, TypeObject *obj, if (cx->typeInferenceEnabled()) { if (!obj->unknownProperties()) obj->markUnknown(cx); - if (markSetsUnknown && !(obj->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN)) + if (markSetsUnknown && !(obj->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN)) cx->compartment()->types.markSetsUnknown(cx, obj); } } @@ -605,7 +550,8 @@ TypeScript::NumTypeSets(JSScript *script) /* static */ inline StackTypeSet * TypeScript::ThisTypes(JSScript *script) { - return script->types->typeArray() + script->nTypeSets() + js::analyze::ThisSlot(); + JS_ASSERT(CurrentThreadCanReadCompilationData()); + return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot(); } /* @@ -618,7 +564,8 @@ TypeScript::ThisTypes(JSScript *script) TypeScript::ArgTypes(JSScript *script, unsigned i) { JS_ASSERT(i < script->function()->nargs()); - return script->types->typeArray() + script->nTypeSets() + js::analyze::ArgSlot(i); + JS_ASSERT(CurrentThreadCanReadCompilationData()); + return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i); } template @@ -1089,10 +1036,8 @@ TypeSet::clearObjects() } bool -TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) +TypeSet::addType(Type type, LifoAlloc *alloc) { - JS_ASSERT_IF(padded, !*padded); - if (unknown()) return true; @@ -1100,8 +1045,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) flags |= TYPE_FLAG_BASE_MASK; clearObjects(); JS_ASSERT(unknown()); - if (padded) - *padded = true; return true; } @@ -1115,8 +1058,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) flag |= TYPE_FLAG_INT32; flags |= flag; - if (padded) - *padded = true; return true; } @@ -1156,8 +1097,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) clearObjects(); } - if (padded) - *padded = true; return true; } @@ -1166,13 +1105,16 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type) { JS_ASSERT(cxArg->compartment()->activeAnalysis); - bool added = false; - if (!TypeSet::addType(type, &cxArg->typeLifoAlloc(), &added)) { - cxArg->compartment()->types.setPendingNukeTypes(cxArg); + if (hasType(type)) return; + + { + AutoLockForCompilation lock(cxArg); + if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) { + cxArg->compartment()->types.setPendingNukeTypes(cxArg); + return; + } } - if (!added) - return; InferSpew(ISpewOps, "addType: %sT%p%s %s", InferSpewColor(this), this, InferSpewColorReset(), @@ -1275,7 +1217,7 @@ TypeSet::getObjectClass(unsigned i) const if (JSObject *object = getSingleObject(i)) return object->getClass(); if (TypeObject *object = getTypeObject(i)) - return object->clasp; + return object->clasp(); return nullptr; } @@ -1283,18 +1225,16 @@ TypeSet::getObjectClass(unsigned i) const // TypeObject ///////////////////////////////////////////////////////////////////// -inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknown) +inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags) { mozilla::PodZero(this); /* Inner objects may not appear on prototype chains. */ JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject); - this->clasp = clasp; - this->proto = proto.raw(); - - if (unknown) - flags |= OBJECT_FLAG_UNKNOWN_MASK; + this->clasp_ = clasp; + this->proto_ = proto.raw(); + this->flags_ = initialFlags; InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this)); } @@ -1302,15 +1242,17 @@ inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, bool unknow inline uint32_t TypeObject::basePropertyCount() const { - return (flags & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT; + JS_ASSERT(CurrentThreadCanReadCompilationData()); + return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT; } inline void TypeObject::setBasePropertyCount(uint32_t count) { + // Note: Callers must ensure they are performing threadsafe operations. JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT); - flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK) - | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT); + flags_ = (flags() & ~OBJECT_FLAG_PROPERTY_COUNT_MASK) + | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT); } inline HeapTypeSet * @@ -1322,36 +1264,46 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id) JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); JS_ASSERT(!unknownProperties()); - uint32_t propertyCount = basePropertyCount(); - Property **pprop = HashSetInsert - (cx->typeLifoAlloc(), propertySet, propertyCount, id); - if (!pprop) { - cx->compartment()->types.setPendingNukeTypes(cx); - return nullptr; - } + if (HeapTypeSet *types = maybeGetProperty(id)) + return types; + + uint32_t propertyCount; + Property **pprop; + { + AutoLockForCompilation lock(cx); + + propertyCount = basePropertyCount(); + pprop = HashSetInsert + (cx->typeLifoAlloc(), propertySet, propertyCount, id); + if (!pprop) { + cx->compartment()->types.setPendingNukeTypes(cx); + return nullptr; + } + + JS_ASSERT(!*pprop); - if (!*pprop) { setBasePropertyCount(propertyCount); if (!addProperty(cx, id, pprop)) { setBasePropertyCount(0); propertySet = nullptr; return nullptr; } - if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) { - markUnknown(cx); + } - /* - * Return an arbitrary property in the object, as all have unknown - * type and are treated as configured. - */ - unsigned count = getPropertyCount(); - for (unsigned i = 0; i < count; i++) { - if (Property *prop = getProperty(i)) - return &prop->types; - } + if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) { + markUnknown(cx); - MOZ_ASSUME_UNREACHABLE("Missing property"); + /* + * Return an arbitrary property in the object, as all have unknown + * type and are treated as configured. + */ + unsigned count = getPropertyCount(); + for (unsigned i = 0; i < count; i++) { + if (Property *prop = getProperty(i)) + return &prop->types; } + + MOZ_ASSUME_UNREACHABLE("Missing property"); } return &(*pprop)->types; @@ -1363,6 +1315,7 @@ TypeObject::maybeGetProperty(jsid id) JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id)); JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); JS_ASSERT(!unknownProperties()); + JS_ASSERT(CurrentThreadCanReadCompilationData()); Property *prop = HashSetLookup (propertySet, basePropertyCount(), id); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 00a2ebc25cc8..d45705cdf3c1 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1937,6 +1937,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle global) if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto)) return false; + AutoLockForCompilation lock(cx); global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto)); global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction)); global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto)); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index a9515a889c35..61ff5de58012 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1273,7 +1273,7 @@ NewObject(ExclusiveContext *cx, const Class *clasp, types::TypeObject *type_, JS if (!NewObjectMetadata(cx, &metadata)) return nullptr; - RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(type->proto), + RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto(), parent, metadata, kind)); if (!shape) return nullptr; @@ -1457,7 +1457,7 @@ js::NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc NewObjectCache &cache = cx->runtime()->newObjectCache; NewObjectCache::EntryIndex entry = -1; - if (parent == type->proto->getParent() && + if (parent == type->proto().toObject()->getParent() && newKind == GenericObject && !cx->compartment()->hasObjectMetadataCallback()) { @@ -1985,9 +1985,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & * Swap the object's types, to restore their initial type information. * The prototypes and classes of the objects were swapped in ReserveForTradeGuts. */ - TypeObject *tmp = a->type_; - a->type_ = b->type_; - b->type_ = tmp; + { + AutoLockForCompilation lock(cx); + TypeObject *tmp = a->type_; + a->type_ = b->type_; + b->type_ = tmp; + } /* Don't try to swap a JSFunction for a plain function JSObject. */ JS_ASSERT_IF(a->is(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis()); @@ -2019,9 +2022,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & char tmp[mozilla::tl::Max::value]; JS_ASSERT(size <= sizeof(tmp)); - js_memcpy(tmp, a, size); - js_memcpy(a, b, size); - js_memcpy(b, tmp, size); + { + AutoLockForCompilation lock(cx); + js_memcpy(tmp, a, size); + js_memcpy(a, b, size); + js_memcpy(b, tmp, size); + } #ifdef JSGC_GENERATIONAL /* @@ -2059,9 +2065,12 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & void *bpriv = b->hasPrivate() ? b->getPrivate() : nullptr; char tmp[sizeof(JSObject)]; - js_memcpy(&tmp, a, sizeof tmp); - js_memcpy(a, b, sizeof tmp); - js_memcpy(b, &tmp, sizeof tmp); + { + AutoLockForCompilation lock(cx); + js_memcpy(&tmp, a, sizeof tmp); + js_memcpy(a, b, sizeof tmp); + js_memcpy(b, &tmp, sizeof tmp); + } if (a->isNative()) a->shape_->setNumFixedSlots(reserved.newafixed); @@ -2967,7 +2976,11 @@ js::SetClassAndProto(JSContext *cx, HandleObject obj, MarkTypeObjectUnknownProperties(cx, obj->type(), true); MarkTypeObjectUnknownProperties(cx, type, true); - obj->setType(type); + { + AutoLockForCompilation lock(cx); + obj->setType(type); + } + *succeeded = true; return true; } @@ -4030,7 +4043,7 @@ NativeGetInline(JSContext *cx, case JSOP_GETPROP: case JSOP_CALLPROP: case JSOP_LENGTH: - script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc)); + script->baselineScript()->noteAccessedGetter(cx, script->pcToOffset(pc)); break; default: break; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index fabb240c24c5..0c4ffa3edd08 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -474,7 +474,7 @@ class JSObject : public js::ObjectImpl bool uninlinedIsProxy() const; JSObject *getProto() const { JS_ASSERT(!uninlinedIsProxy()); - return js::ObjectImpl::getProto(); + return getTaggedProto().toObjectOrNull(); } static inline bool getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 71ca517b5689..674d4ea03c17 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -393,6 +393,9 @@ JSObject::clearType(JSContext *cx, js::HandleObject obj) inline void JSObject::setType(js::types::TypeObject *newType) { + // Note: This is usually called for newly created objects that haven't + // escaped to script yet, so don't require that the compilation lock be + // held here. JS_ASSERT(newType); JS_ASSERT(!hasSingletonType()); type_ = newType; @@ -405,7 +408,7 @@ JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject JS_ASSERT(obj->is()); return js::Proxy::getPrototypeOf(cx, obj, protop); } else { - protop.set(obj->js::ObjectImpl::getProto()); + protop.set(obj->getTaggedProto().toObjectOrNull()); return true; } } @@ -461,11 +464,11 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi * make sure their presence is consistent with the shape. */ JS_ASSERT(shape && type); - JS_ASSERT(type->clasp == shape->getObjectClass()); - JS_ASSERT(type->clasp != &js::ArrayObject::class_); - JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp) == shape->numFixedSlots()); - JS_ASSERT_IF(type->clasp->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); - JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap); + JS_ASSERT(type->clasp() == shape->getObjectClass()); + JS_ASSERT(type->clasp() != &js::ArrayObject::class_); + JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots()); + JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); + JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap); JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())); js::HeapSlot *slots = extantSlots; @@ -495,7 +498,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi obj->slots = slots; obj->elements = js::emptyObjectElements; - const js::Class *clasp = type->clasp; + const js::Class *clasp = type->clasp(); if (clasp->hasPrivate()) obj->privateRef(shape->numFixedSlots()) = nullptr; @@ -512,9 +515,9 @@ JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc:: uint32_t length) { JS_ASSERT(shape && type); - JS_ASSERT(type->clasp == shape->getObjectClass()); - JS_ASSERT(type->clasp == &js::ArrayObject::class_); - JS_ASSERT_IF(type->clasp->finalize, heap == js::gc::TenuredHeap); + JS_ASSERT(type->clasp() == shape->getObjectClass()); + JS_ASSERT(type->clasp() == &js::ArrayObject::class_); + JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap); /* * Arrays use their fixed slots to store elements, and must have enough @@ -979,8 +982,11 @@ DefineConstructorAndPrototype(JSContext *cx, Handle global, JS_ASSERT(!global->nativeLookup(cx, id)); /* Set these first in case AddTypePropertyId looks for this class. */ - global->setConstructor(key, ObjectValue(*ctor)); - global->setPrototype(key, ObjectValue(*proto)); + { + AutoLockForCompilation lock(cx); + global->setConstructor(key, ObjectValue(*ctor)); + global->setPrototype(key, ObjectValue(*proto)); + } global->setConstructorPropertySlot(key, ObjectValue(*ctor)); if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index b1d4dcdd6605..1b1582516c2b 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -2748,7 +2748,7 @@ Proxy::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandl return proxy->as().handler()->defaultValue(cx, proxy, hint, vp); } -JSObject * const Proxy::LazyProto = reinterpret_cast(0x1); +JSObject * const TaggedProto::LazyProto = reinterpret_cast(0x1); bool Proxy::getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject proto) diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 12cc9ceab9d1..e463388fd8d7 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -324,8 +324,6 @@ class Proxy /* IC entry path for handling __noSuchMethod__ on access. */ static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id, MutableHandleValue vp); - - static JSObject * const LazyProto; }; // Use these in places where you don't want to #include vm/ProxyObject.h. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 7c25e8dbabe8..30c7feebe25f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3015,7 +3015,10 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) JS_ASSERT(!script->isGenerator()); - script->needsArgsObj_ = true; + { + AutoLockForCompilation lock(cx); + script->needsArgsObj_ = true; + } #ifdef JS_ION /* diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 93c309e498ca..7f03e3185827 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -977,7 +977,11 @@ class JSScript : public js::gc::BarrieredCell * that needsArgsObj is only called after the script has been analyzed. */ bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } - bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; } + bool needsArgsObj() const { + JS_ASSERT(analyzedArgsUsage()); + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); + return needsArgsObj_; + } void setNeedsArgsObj(bool needsArgsObj); static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script); @@ -1027,6 +1031,7 @@ class JSScript : public js::gc::BarrieredCell } bool hasBaselineScript() const { + JS_ASSERT(js::CurrentThreadCanReadCompilationData()); return baseline && baseline != BASELINE_DISABLED_SCRIPT; } bool canBaselineCompile() const { @@ -1036,7 +1041,7 @@ class JSScript : public js::gc::BarrieredCell JS_ASSERT(hasBaselineScript()); return baseline; } - inline void setBaselineScript(js::jit::BaselineScript *baselineScript); + inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript); void updateBaselineOrIonRaw(); diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index b498a626243a..67398e8d4f8b 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -125,11 +125,14 @@ JSScript::setIsCallsiteClone(JSObject *fun) { } inline void -JSScript::setBaselineScript(js::jit::BaselineScript *baselineScript) { +JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript) { #ifdef JS_ION if (hasBaselineScript()) js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline); #endif + mozilla::Maybe lock; + if (maybecx) + lock.construct(maybecx); baseline = baselineScript; updateBaselineOrIonRaw(); } diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 0136601f6a2e..09abb061397c 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -91,6 +91,8 @@ js::StartOffThreadIonCompile(JSContext *cx, jit::IonBuilder *builder) if (!state.ionWorklist.append(builder)) return false; + cx->runtime()->addCompilationThread(); + state.notifyAll(WorkerThreadState::PRODUCER); return true; } @@ -615,7 +617,7 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke iter.next()) { types::TypeObject *object = iter.get(); - TaggedProto proto(object->proto); + TaggedProto proto(object->proto()); if (!proto.isObject()) continue; @@ -626,7 +628,9 @@ WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *toke JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key); JS_ASSERT(newProto); - object->proto = newProto; + // Note: this is safe to do without requiring the compilation lock, as + // the new type is not yet available to compilation threads. + object->setProtoUnchecked(newProto); } // Move the parsed script and all its contents into the desired compartment. @@ -760,7 +764,11 @@ WorkerThread::handleIonWorkload(WorkerThreadState &state) jit::IonContext ictx(jit::CompileRuntime::get(runtime), jit::CompileCompartment::get(ionBuilder->script()->compartment()), &ionBuilder->alloc()); - ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder)); + AutoEnterIonCompilation ionCompiling; + bool succeeded = ionBuilder->build(); + ionBuilder->clearForBackEnd(); + if (succeeded) + ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder)); } state.lock(); diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 7a2e1c2c1587..413c630ecf13 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -48,7 +48,7 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler) RootedValue priv(cx, ObjectValue(*obj)); ProxyOptions options; options.setCallable(obj->isCallable()); - return NewProxyObject(cx, handler, priv, Proxy::LazyProto, parent, options); + return NewProxyObject(cx, handler, priv, TaggedProto::LazyProto, parent, options); } JSObject * @@ -141,7 +141,7 @@ js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject { // Allow wrapping outer window proxies. JS_ASSERT(!obj->is() || obj->getClass()->ext.innerObject); - JS_ASSERT(wrappedProto == Proxy::LazyProto); + JS_ASSERT(wrappedProto == TaggedProto::LazyProto); return Wrapper::New(cx, obj, parent, &CrossCompartmentWrapper::singleton); } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index aff455ebc495..954e08b7a1d8 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -669,7 +669,7 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha RootedId shId(cx, AtomToId(selfHostedName)); RootedObject holder(cx, cx->global()->intrinsicsHolder()); - if (HasDataProperty(cx, holder, shId, funVal.address())) + if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address())) return true; if (!cx->runtime()->maybeWrappedSelfHostedFunction(cx, shId, funVal)) @@ -685,5 +685,31 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha fun->setExtendedSlot(0, StringValue(selfHostedName)); funVal.setObject(*fun); - return JSObject::defineGeneric(cx, holder, shId, funVal, nullptr, nullptr, 0); + return cx->global()->addIntrinsicValue(cx, shId, funVal); +} + +bool +GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value) +{ + RootedObject holder(cx, intrinsicsHolder()); + + // Work directly with the shape machinery underlying the object, so that we + // don't take the compilation lock until we are ready to update the object + // without triggering a GC. + + uint32_t slot = holder->slotSpan(); + RootedShape last(cx, holder->lastProperty()); + Rooted base(cx, last->base()->unowned()); + + StackShape child(base, id, slot, holder->numFixedSlots(), 0, 0, 0); + RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, holder->numFixedSlots(), child)); + if (!shape) + return false; + + AutoLockForCompilation lock(cx); + if (!JSObject::setLastProperty(cx, holder, shape)) + return false; + + holder->setSlot(shape->slot(), value); + return true; } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 830fc509937d..efac12ea59b9 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -513,26 +513,30 @@ class GlobalObject : public JSObject return &getSlotRefForCompilation(INTRINSICS).toObject(); } - bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { + bool maybeGetIntrinsicValue(jsid id, Value *vp) { + JS_ASSERT(CurrentThreadCanReadCompilationData()); JSObject *holder = intrinsicsHolder(); - if (Shape *shape = holder->nativeLookupPure(name)) { + if (Shape *shape = holder->nativeLookupPure(id)) { *vp = holder->getSlot(shape->slot()); return true; } return false; } + bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { + return maybeGetIntrinsicValue(NameToId(name), vp); + } bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) { if (maybeGetIntrinsicValue(name, value.address())) return true; - Rooted self(cx, this); if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) return false; - RootedObject holder(cx, self->intrinsicsHolder()); RootedId id(cx, NameToId(name)); - return JS_DefinePropertyById(cx, holder, id, value, nullptr, nullptr, 0); + return addIntrinsicValue(cx, id, value); } + bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value); + bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) { #ifdef DEBUG RootedObject self(cx, this); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index f36d344e93c6..32cceba9f052 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1294,7 +1294,7 @@ SetObjectElementOperation(JSContext *cx, Handle obj, HandleId id, con if ((uint32_t)i >= length) { // Annotate script if provided with information (e.g. baseline) if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM) - script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc)); + script->baselineScript()->noteArrayWriteHole(cx, script->pcToOffset(pc)); } } #endif diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 05f355ba9564..c0bf6451fb7d 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -360,7 +360,7 @@ js::ObjectImpl::markChildren(JSTracer *trc) MarkShape(trc, &shape_, "shape"); - const Class *clasp = type_->clasp; + const Class *clasp = type_->clasp(); JSObject *obj = asObjectPtr(); if (clasp->trace) clasp->trace(trc, obj); @@ -538,7 +538,7 @@ js::ArrayBufferDelegate(JSContext *cx, Handle obj) if (obj->getPrivate()) return static_cast(obj->getPrivate()); JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_, - obj->getProto(), nullptr); + obj->getTaggedProto(), nullptr); obj->setPrivateGCThing(delegate); return delegate; } @@ -684,7 +684,7 @@ js::GetProperty(JSContext *cx, Handle obj, Handle rece /* No property? Recur or bottom out. */ if (desc.isUndefined()) { - current = current->getProto(); + current = current->getTaggedProto().toObjectOrNull(); if (current) continue; @@ -746,7 +746,7 @@ js::GetElement(JSContext *cx, Handle obj, Handle recei /* No property? Recur or bottom out. */ if (desc.isUndefined()) { - current = current->getProto(); + current = current->getTaggedProto().toObjectOrNull(); if (current) continue; @@ -811,7 +811,7 @@ js::HasElement(JSContext *cx, Handle obj, uint32_t index, unsigned return true; } - current = current->getProto(); + current = current->getTaggedProto().toObjectOrNull(); if (current) continue; @@ -1009,7 +1009,7 @@ js::SetElement(JSContext *cx, Handle obj, Handle recei MOZ_ASSUME_UNREACHABLE("NYI: setting PropertyOp-based property"); } - current = current->getProto(); + current = current->getTaggedProto().toObjectOrNull(); if (current) continue; diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index d367507deae8..822a1180ca5e 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -980,12 +980,14 @@ class ObjectImpl : public gc::BarrieredCell /* These functions are public, and they should remain public. */ public: - JSObject * getProto() const { - return type_->proto; + js::TaggedProto getTaggedProto() const { + return type_->proto(); } + bool hasTenuredProto() const; + const Class *getClass() const { - return type_->clasp; + return type_->clasp(); } static inline bool @@ -1172,10 +1174,6 @@ class ObjectImpl : public gc::BarrieredCell */ public: - js::TaggedProto getTaggedProto() const { - return TaggedProto(getProto()); - } - Shape * lastProperty() const { MOZ_ASSERT(shape_); return shape_; diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 169921adeee0..cbcb213958c2 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -75,6 +75,9 @@ PerThreadData::PerThreadData(JSRuntime *runtime) asmJSActivationStack_(nullptr), dtoaState(nullptr), suppressGC(0), +#ifdef DEBUG + ionCompiling(false), +#endif activeCompilations(0) {} @@ -135,6 +138,12 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) exclusiveAccessOwner(nullptr), mainThreadHasExclusiveAccess(false), numExclusiveThreads(0), + compilationLock(nullptr), +#ifdef DEBUG + compilationLockOwner(nullptr), + mainThreadHasCompilationLock(false), +#endif + numCompilationThreads(0), #endif systemZone(nullptr), numCompartments(0), @@ -362,6 +371,10 @@ JSRuntime::init(uint32_t maxbytes) exclusiveAccessLock = PR_NewLock(); if (!exclusiveAccessLock) return false; + + compilationLock = PR_NewLock(); + if (!compilationLock) + return false; #endif if (!mainThread.init()) @@ -483,6 +496,10 @@ JSRuntime::~JSRuntime() // Avoid bogus asserts during teardown. JS_ASSERT(!numExclusiveThreads); mainThreadHasExclusiveAccess = true; + + JS_ASSERT(!compilationLockOwner); + if (compilationLock) + PR_DestroyLock(compilationLock); #endif #ifdef JS_THREADSAFE @@ -816,7 +833,7 @@ JSRuntime::activeGCInAtomsZone() #if defined(DEBUG) && !defined(XP_WIN) -AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) +AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) : runtime(rt) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; @@ -834,7 +851,7 @@ AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_G } } -AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation() +AutoProtectHeapForIonCompilation::~AutoProtectHeapForIonCompilation() { JS_ASSERT(runtime->heapProtected_); JS_ASSERT(runtime->unprotectedArenas.empty()); @@ -936,7 +953,7 @@ js::CurrentThreadCanAccessZone(Zone *zone) return true; } -#endif +#endif // JS_THREADSAFE #ifdef DEBUG @@ -954,13 +971,73 @@ JSRuntime::assertCanLock(RuntimeLock which) JS_ASSERT_IF(workerThreadState, !workerThreadState->isLocked()); case OperationCallbackLock: JS_ASSERT(!currentThreadOwnsOperationCallbackLock()); + case CompilationLock: + JS_ASSERT(compilationLockOwner != PR_GetCurrentThread()); case GCLock: JS_ASSERT(gcLockOwner != PR_GetCurrentThread()); break; default: MOZ_CRASH(); } -#endif // JS_THREADSAFE +#endif // JS_WORKER_THREADS +} + +AutoEnterIonCompilation::AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + +#ifdef JS_WORKER_THREADS + PerThreadData *pt = js::TlsPerThreadData.get(); + JS_ASSERT(!pt->ionCompiling); + pt->ionCompiling = true; +#endif +} + +AutoEnterIonCompilation::~AutoEnterIonCompilation() +{ +#ifdef JS_WORKER_THREADS + PerThreadData *pt = js::TlsPerThreadData.get(); + JS_ASSERT(pt->ionCompiling); + pt->ionCompiling = false; +#endif +} + +bool +js::CurrentThreadCanWriteCompilationData() +{ +#ifdef JS_WORKER_THREADS + PerThreadData *pt = TlsPerThreadData.get(); + + // Data can only be read from during compilation. + if (pt->ionCompiling) + return false; + + // Ignore what threads with exclusive contexts are doing; these never have + // run scripts or have associated compilation threads. + JSRuntime *rt = pt->runtimeIfOnOwnerThread(); + if (!rt) + return true; + + return rt->currentThreadHasCompilationLock(); +#else + return true; +#endif +} + +bool +js::CurrentThreadCanReadCompilationData() +{ +#ifdef JS_WORKER_THREADS + PerThreadData *pt = TlsPerThreadData.get(); + + // Data can always be read from freely outside of compilation. + if (!pt || !pt->ionCompiling) + return true; + + return pt->runtime_->currentThreadHasCompilationLock(); +#else + return true; +#endif } #endif // DEBUG diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 0667445320bf..59b6a3c1c92b 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -535,6 +535,9 @@ class PerThreadData : public PerThreadDataFriendFields, friend class js::ActivationIterator; friend class js::jit::JitActivation; friend class js::AsmJSActivation; +#ifdef DEBUG + friend bool js::CurrentThreadCanReadCompilationData(); +#endif /* * Points to the most recent activation running on the thread. @@ -577,7 +580,12 @@ class PerThreadData : public PerThreadDataFriendFields, */ int32_t suppressGC; - // Whether there is an active compilation on this thread. +#ifdef DEBUG + // Whether this thread is actively Ion compiling. + bool ionCompiling; +#endif + + // Number of active bytecode compilation on this thread. unsigned activeCompilations; PerThreadData(JSRuntime *runtime); @@ -677,7 +685,8 @@ class MarkingValidator; typedef Vector ZoneVector; class AutoLockForExclusiveAccess; -class AutoProtectHeapForCompilation; +class AutoLockForCompilation; +class AutoProtectHeapForIonCompilation; void RecomputeStackLimit(JSRuntime *rt, StackKind kind); @@ -727,6 +736,7 @@ struct JSRuntime : public JS::shadow::Runtime, ExclusiveAccessLock, WorkerThreadStateLock, OperationCallbackLock, + CompilationLock, GCLock }; #ifdef DEBUG @@ -805,20 +815,44 @@ struct JSRuntime : public JS::shadow::Runtime, friend class js::AutoLockForExclusiveAccess; + /* + * Lock taken when using data that can be modified by the main thread but + * read by Ion compilation threads. Any time either the main thread writes + * such data or the compilation thread reads it, this lock must be taken. + * Note that no externally visible data is modified by the compilation + * thread, so the main thread never needs to take this lock when reading. + */ + PRLock *compilationLock; +#ifdef DEBUG + PRThread *compilationLockOwner; + bool mainThreadHasCompilationLock; +#endif + + /* Number of in flight Ion compilations. */ + size_t numCompilationThreads; + + friend class js::AutoLockForCompilation; +#ifdef DEBUG + friend bool js::CurrentThreadCanWriteCompilationData(); + friend bool js::CurrentThreadCanReadCompilationData(); +#endif + public: void setUsedByExclusiveThread(JS::Zone *zone); void clearUsedByExclusiveThread(JS::Zone *zone); #endif // JS_THREADSAFE && JS_ION +#ifdef DEBUG bool currentThreadHasExclusiveAccess() { -#if defined(JS_WORKER_THREADS) && defined(DEBUG) +#ifdef JS_WORKER_THREADS return (!numExclusiveThreads && mainThreadHasExclusiveAccess) || - exclusiveAccessOwner == PR_GetCurrentThread(); + exclusiveAccessOwner == PR_GetCurrentThread(); #else return true; #endif } +#endif // DEBUG bool exclusiveThreadsPresent() const { #ifdef JS_WORKER_THREADS @@ -828,6 +862,33 @@ struct JSRuntime : public JS::shadow::Runtime, #endif } + void addCompilationThread() { + numCompilationThreads++; + } + void removeCompilationThread() { + JS_ASSERT(numCompilationThreads); + numCompilationThreads--; + } + + bool compilationThreadsPresent() const { +#ifdef JS_WORKER_THREADS + return numCompilationThreads > 0; +#else + return false; +#endif + } + +#ifdef DEBUG + bool currentThreadHasCompilationLock() { +#ifdef JS_WORKER_THREADS + return (!numCompilationThreads && mainThreadHasCompilationLock) || + compilationLockOwner == PR_GetCurrentThread(); +#else + return true; +#endif + } +#endif // DEBUG + /* Embedders can use this zone however they wish. */ JS::Zone *systemZone; @@ -1431,7 +1492,7 @@ struct JSRuntime : public JS::shadow::Runtime, const char *numGrouping; #endif - friend class js::AutoProtectHeapForCompilation; + friend class js::AutoProtectHeapForIonCompilation; friend class js::AutoThreadSafeAccess; mozilla::DebugOnly heapProtected_; #ifdef DEBUG @@ -2049,16 +2110,36 @@ class RuntimeAllocPolicy extern const JSSecurityCallbacks NullSecurityCallbacks; -class AutoProtectHeapForCompilation +// Debugging RAII class which marks the current thread as performing an Ion +// compilation, for use by CurrentThreadCan{Read,Write}CompilationData +class AutoEnterIonCompilation +{ + public: +#ifdef DEBUG + AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); + ~AutoEnterIonCompilation(); +#else + AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } +#endif + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +// Debugging RAII class which protects the entire GC heap for the duration of an +// Ion compilation. When used only the main thread will be active and all +// accesses to GC things must be wrapped by an AutoThreadSafeAccess instance. +class AutoProtectHeapForIonCompilation { public: #if defined(DEBUG) && !defined(XP_WIN) JSRuntime *runtime; - AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~AutoProtectHeapForCompilation(); + AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoProtectHeapForIonCompilation(); #else - AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp index 8158a9800c01..61411664d5d6 100644 --- a/js/src/vm/SPSProfiler.cpp +++ b/js/src/vm/SPSProfiler.cpp @@ -56,13 +56,14 @@ SPSProfiler::enable(bool enabled) if (enabled_ == enabled) return; - enabled_ = enabled; /* * Ensure all future generated code will be instrumented, or that all * currently instrumented code is discarded */ ReleaseAllJITCode(rt->defaultFreeOp()); + enabled_ = enabled; + #ifdef JS_ION /* Toggle SPS-related jumps on baseline jitcode. * The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index d4c50beeb60e..8e46237b5d99 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -958,10 +958,11 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle na JSScript *cscript = CloneScript(cx, NullPtr(), targetFun, sourceScript); if (!cscript) return false; - targetFun->setScript(cscript); cscript->setFunction(targetFun); + JS_ASSERT(sourceFun->nargs() == targetFun->nargs()); targetFun->setFlags(sourceFun->flags() | JSFunction::EXTENDED); + targetFun->setScript(cscript); return true; } diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 74339e88347d..1b939022765a 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -338,7 +338,7 @@ ArrayBufferObject::neuterViews(JSContext *cx, Handle buffer) size_t numViews = 0; for (view = GetViewList(buffer); view; view = view->nextView()) { numViews++; - view->neuter(); + view->neuter(cx); // Notify compiled jit code that the base pointer has moved. MarkObjectStateChange(cx, view); @@ -1182,8 +1182,10 @@ TypedArrayObject::isArrayIndex(jsid id, uint32_t *ip) } void -TypedArrayObject::neuter() +TypedArrayObject::neuter(JSContext *cx) { + AutoLockForCompilation lock(cx); + setSlot(LENGTH_SLOT, Int32Value(0)); setSlot(BYTELENGTH_SLOT, Int32Value(0)); setSlot(BYTEOFFSET_SLOT, Int32Value(0)); @@ -2625,12 +2627,12 @@ ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead) } void -ArrayBufferViewObject::neuter() +ArrayBufferViewObject::neuter(JSContext *cx) { if (is()) as().neuter(); else - as().neuter(); + as().neuter(cx); } // this default implementation is only valid for integer types diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 275315ace116..7baa47cf8adb 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -276,7 +276,7 @@ class ArrayBufferViewObject : public JSObject void prependToViews(ArrayBufferViewObject *viewsHead); - void neuter(); + void neuter(JSContext *cx); static void trace(JSTracer *trc, JSObject *obj); }; @@ -353,7 +353,7 @@ class TypedArrayObject : public ArrayBufferViewObject inline bool isArrayIndex(jsid id, uint32_t *ip = nullptr); void copyTypedArrayElement(uint32_t index, MutableHandleValue vp); - void neuter(); + void neuter(JSContext *cx); static uint32_t slotWidth(int atype) { switch (atype) { From 9f03cdf6d7647751377ae87856b0f8e4359b4f34 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 16 Dec 2013 11:13:26 -0800 Subject: [PATCH 03/34] Bug 950716 - SpiderMonkey: A minor BitSet::Iterator refactoring. r=nbp --- js/src/jit/BitSet.h | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/js/src/jit/BitSet.h b/js/src/jit/BitSet.h index b602b4285222..8b0f9cb14018 100644 --- a/js/src/jit/BitSet.h +++ b/js/src/jit/BitSet.h @@ -120,6 +120,27 @@ class BitSet::Iterator unsigned word_; uint32_t value_; + void skipEmpty() { + // Skip words containing only zeros. + while (value_ == 0) { + word_++; + if (!more()) + return; + + JS_STATIC_ASSERT(sizeof(value_) * 8 == BitSet::BitsPerWord); + index_ = word_ * sizeof(value_) * 8; + value_ = set_.bits_[word_]; + } + + // Be careful: the result of CountTrailingZeroes32 is undefined if the + // input is 0. + int numZeros = mozilla::CountTrailingZeroes32(value_); + index_ += numZeros; + value_ >>= numZeros; + + JS_ASSERT_IF(index_ < set_.numBits_, set_.contains(index_)); + } + public: Iterator(BitSet &set) : set_(set), @@ -127,8 +148,7 @@ class BitSet::Iterator word_(0), value_(set.bits_[0]) { - if (!set_.contains(index_)) - (*this)++; + skipEmpty(); } inline bool more() const { @@ -145,23 +165,7 @@ class BitSet::Iterator index_++; value_ >>= 1; - // Skip words containing only zeros. - while (value_ == 0) { - word_++; - if (!more()) - return *this; - - index_ = word_ * sizeof(value_) * 8; - value_ = set_.bits_[word_]; - } - - // Be careful: the result of CountTrailingZeroes32 is undefined if the - // input is 0. - int numZeros = mozilla::CountTrailingZeroes32(value_); - index_ += numZeros; - value_ >>= numZeros; - - JS_ASSERT_IF(index_ < set_.numBits_, set_.contains(index_)); + skipEmpty(); return *this; } From fbee2260d8e51ed6518135b3d43bea0e4ba23b8c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 16 Dec 2013 11:13:29 -0800 Subject: [PATCH 04/34] Bug 950716 - IonMonkey: Optimize BitSet a little r=nbp --- js/src/jit/BitSet.cpp | 43 ++++++++++++++++++++++++--------------- js/src/jit/BitSet.h | 6 ++++-- js/src/jit/Safepoints.cpp | 2 +- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/js/src/jit/BitSet.cpp b/js/src/jit/BitSet.cpp index df5fe4846eae..6e393725823c 100644 --- a/js/src/jit/BitSet.cpp +++ b/js/src/jit/BitSet.cpp @@ -36,8 +36,9 @@ bool BitSet::empty() const { JS_ASSERT(bits_); - for (unsigned int i = 0; i < numWords(); i++) { - if (bits_[i]) + const uint32_t *bits = bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) { + if (bits[i]) return false; } return true; @@ -50,8 +51,10 @@ BitSet::insertAll(const BitSet *other) JS_ASSERT(other->numBits_ == numBits_); JS_ASSERT(other->bits_); - for (unsigned int i = 0; i < numWords(); i++) - bits_[i] |= other->bits_[i]; + uint32_t *bits = bits_; + const uint32_t *otherBits = other->bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) + bits[i] |= otherBits[i]; } void @@ -61,8 +64,10 @@ BitSet::removeAll(const BitSet *other) JS_ASSERT(other->numBits_ == numBits_); JS_ASSERT(other->bits_); - for (unsigned int i = 0; i < numWords(); i++) - bits_[i] &= ~other->bits_[i]; + uint32_t *bits = bits_; + const uint32_t *otherBits = other->bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) + bits[i] &= ~otherBits[i]; } void @@ -72,8 +77,10 @@ BitSet::intersect(const BitSet *other) JS_ASSERT(other->numBits_ == numBits_); JS_ASSERT(other->bits_); - for (unsigned int i = 0; i < numWords(); i++) - bits_[i] &= other->bits_[i]; + uint32_t *bits = bits_; + const uint32_t *otherBits = other->bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) + bits[i] &= otherBits[i]; } // returns true if the intersection caused the contents of the set to change. @@ -86,11 +93,13 @@ BitSet::fixedPointIntersect(const BitSet *other) bool changed = false; - for (unsigned int i = 0; i < numWords(); i++) { - uint32_t old = bits_[i]; - bits_[i] &= other->bits_[i]; + uint32_t *bits = bits_; + const uint32_t *otherBits = other->bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) { + uint32_t old = bits[i]; + bits[i] &= otherBits[i]; - if (!changed && old != bits_[i]) + if (!changed && old != bits[i]) changed = true; } return changed; @@ -100,14 +109,16 @@ void BitSet::complement() { JS_ASSERT(bits_); - for (unsigned int i = 0; i < numWords(); i++) - bits_[i] = ~bits_[i]; + uint32_t *bits = bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) + bits[i] = ~bits[i]; } void BitSet::clear() { JS_ASSERT(bits_); - for (unsigned int i = 0; i < numWords(); i++) - bits_[i] = 0; + uint32_t *bits = bits_; + for (unsigned int i = 0, e = numWords(); i < e; i++) + bits[i] = 0; } diff --git a/js/src/jit/BitSet.h b/js/src/jit/BitSet.h index 8b0f9cb14018..c2f04650fd0f 100644 --- a/js/src/jit/BitSet.h +++ b/js/src/jit/BitSet.h @@ -122,14 +122,16 @@ class BitSet::Iterator void skipEmpty() { // Skip words containing only zeros. + unsigned numWords = set_.numWords(); + const uint32_t *bits = set_.bits_; while (value_ == 0) { word_++; - if (!more()) + if (word_ == numWords) return; JS_STATIC_ASSERT(sizeof(value_) * 8 == BitSet::BitsPerWord); index_ = word_ * sizeof(value_) * 8; - value_ = set_.bits_[word_]; + value_ = bits[word_]; } // Be careful: the result of CountTrailingZeroes32 is undefined if the diff --git a/js/src/jit/Safepoints.cpp b/js/src/jit/Safepoints.cpp index c4f0c7906ecf..520fc575755b 100644 --- a/js/src/jit/Safepoints.cpp +++ b/js/src/jit/Safepoints.cpp @@ -106,7 +106,7 @@ MapSlotsToBitset(BitSet *set, CompactBufferWriter &stream, uint32_t nslots, uint } size_t count = set->rawLength(); - uint32_t *words = set->raw(); + const uint32_t *words = set->raw(); for (size_t i = 0; i < count; i++) stream.writeUnsigned(words[i]); } From be2485b3fc65b73ac79b342c50b69d3edc2b7552 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 16 Dec 2013 11:13:31 -0800 Subject: [PATCH 05/34] Bug 950716 - IonMonkey: Reorder struct fields for micro-efficiency. r=nbp --- js/src/jit/BitSet.h | 6 +++--- js/src/jit/FixedList.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/jit/BitSet.h b/js/src/jit/BitSet.h index c2f04650fd0f..b6bab6ec06bb 100644 --- a/js/src/jit/BitSet.h +++ b/js/src/jit/BitSet.h @@ -29,11 +29,11 @@ class BitSet : private TempObject private: BitSet(unsigned int numBits) : - numBits_(numBits), - bits_(nullptr) {} + bits_(nullptr), + numBits_(numBits) {} - unsigned int numBits_; uint32_t *bits_; + const unsigned int numBits_; static inline uint32_t bitForValue(unsigned int value) { return 1l << uint32_t(value % BitsPerWord); diff --git a/js/src/jit/FixedList.h b/js/src/jit/FixedList.h index b5da5e553785..4d336f7d0930 100644 --- a/js/src/jit/FixedList.h +++ b/js/src/jit/FixedList.h @@ -19,8 +19,8 @@ namespace jit { template class FixedList { - size_t length_; T *list_; + size_t length_; private: FixedList(const FixedList&); // no copy definition. From ea8901c289c7687df39f4f57b80ce19578dc5b48 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 16 Dec 2013 10:38:15 -0800 Subject: [PATCH 06/34] Bug 949108 - Fix an exact rooting false positive across the activity callback; r=bholley --HG-- extra : rebase_source : 9c4f0b94b376f9a2d11c5f031b8a8ef27aa2e4fb --- js/src/jsapi.cpp | 8 ++------ js/src/jsgc.cpp | 6 ++++++ js/src/jsgc.h | 1 + js/src/vm/Runtime.cpp | 18 ++++++++++++++++++ js/src/vm/Runtime.h | 1 + 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9281c001ce61..722ec4ceb930 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -700,9 +700,7 @@ StartRequest(JSContext *cx) } else { /* Indicate that a request is running. */ rt->requestDepth = 1; - - if (rt->activityCallback) - rt->activityCallback(rt->activityCallbackArg, true); + rt->triggerActivityCallback(true); } } @@ -718,9 +716,7 @@ StopRequest(JSContext *cx) } else { rt->conservativeGC.updateForRequestEnd(); rt->requestDepth = 0; - - if (rt->activityCallback) - rt->activityCallback(rt->activityCallbackArg, false); + rt->triggerActivityCallback(false); } } #endif /* JS_THREADSAFE */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 80d2b3fafd45..b7177ef208e9 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -5520,6 +5520,12 @@ AutoSuppressGC::AutoSuppressGC(JSCompartment *comp) suppressGC_++; } +AutoSuppressGC::AutoSuppressGC(JSRuntime *rt) + : suppressGC_(rt->mainThread.suppressGC) +{ + suppressGC_++; +} + bool js::UninlinedIsInsideNursery(JSRuntime *rt, const void *thing) { diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 9159f31ec024..9304c2dae940 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1398,6 +1398,7 @@ class AutoSuppressGC public: AutoSuppressGC(ExclusiveContext *cx); AutoSuppressGC(JSCompartment *comp); + AutoSuppressGC(JSRuntime *rt); ~AutoSuppressGC() { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index cbcb213958c2..7b6b6e4b34d5 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -753,6 +753,24 @@ JSRuntime::getDefaultLocale() return defaultLocale; } +void +JSRuntime::triggerActivityCallback(bool active) +{ + if (!activityCallback) + return; + + /* + * The activity callback must not trigger a GC: it would create a cirular + * dependency between entering a request and Rooted's requirement of being + * in a request. In practice this callback already cannot trigger GC. The + * suppression serves to inform the exact rooting hazard analysis of this + * property and ensures that it remains true in the future. + */ + AutoSuppressGC suppress(this); + + activityCallback(activityCallbackArg, active); +} + void JSRuntime::setGCMaxMallocBytes(size_t value) { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 59b6a3c1c92b..599c9d2bb8c4 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1033,6 +1033,7 @@ struct JSRuntime : public JS::shadow::Runtime, js::ActivityCallback activityCallback; void *activityCallbackArg; + void triggerActivityCallback(bool active); #ifdef JS_THREADSAFE /* The request depth for this thread. */ From f455cedda9a6c5d512424e871ae20dcecd09223d Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 16 Dec 2013 14:04:49 -0800 Subject: [PATCH 07/34] Bug 950456 - Fix tracing for baseline type monitor and update stubs, r=jandem. --- js/src/jit/BaselineIC.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 75e6308e5839..0caa47353c9b 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -176,14 +176,14 @@ ICStub::trace(JSTracer *trc) ICTypeMonitor_Fallback *lastMonStub = toMonitoredFallbackStub()->fallbackMonitorStub(); for (ICStubConstIterator iter = lastMonStub->firstMonitorStub(); !iter.atEnd(); iter++) { JS_ASSERT_IF(iter->next() == nullptr, *iter == lastMonStub); - iter->markCode(trc, "baseline-monitor-stub-ioncode"); + iter->trace(trc); } } if (isUpdated()) { for (ICStubConstIterator iter = toUpdatedStub()->firstUpdateStub(); !iter.atEnd(); iter++) { JS_ASSERT_IF(iter->next() == nullptr, iter->isTypeUpdate_Fallback()); - iter->markCode(trc, "baseline-update-stub-ioncode"); + iter->trace(trc); } } From 4f47a5019c0d073cceabcc6ef1d760a38a05c99b Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 16 Dec 2013 08:25:12 -0500 Subject: [PATCH 08/34] Bug 950503 - Build accessible/src/windows in unified mode; r=tbsaunde --- accessible/src/windows/ia2/moz.build | 11 ++++++++--- accessible/src/windows/msaa/moz.build | 10 +++++++--- accessible/src/windows/sdn/moz.build | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/accessible/src/windows/ia2/moz.build b/accessible/src/windows/ia2/moz.build index 33b68b8fb365..8d3d415e3f80 100644 --- a/accessible/src/windows/ia2/moz.build +++ b/accessible/src/windows/ia2/moz.build @@ -15,7 +15,7 @@ EXPORTS += [ 'ia2AccessibleValue.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'ia2Accessible.cpp', 'ia2AccessibleAction.cpp', 'ia2AccessibleComponent.cpp', @@ -24,12 +24,17 @@ SOURCES += [ 'ia2AccessibleHypertext.cpp', 'ia2AccessibleImage.cpp', 'ia2AccessibleRelation.cpp', - 'ia2AccessibleTable.cpp', - 'ia2AccessibleTableCell.cpp', 'ia2AccessibleText.cpp', 'ia2AccessibleValue.cpp', ] +# These files cannot be built in unified mode because they both include +# AccessibleTable2_i.c. +SOURCES += [ + 'ia2AccessibleTable.cpp', + 'ia2AccessibleTableCell.cpp', +] + LOCAL_INCLUDES += [ '../../base', '../../generic', diff --git a/accessible/src/windows/msaa/moz.build b/accessible/src/windows/msaa/moz.build index 4ef11761c0f2..cb3ff5affb00 100644 --- a/accessible/src/windows/msaa/moz.build +++ b/accessible/src/windows/msaa/moz.build @@ -14,7 +14,7 @@ EXPORTS.mozilla.a11y += [ 'HyperTextAccessibleWrap.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'AccessibleWrap.cpp', 'ApplicationAccessibleWrap.cpp', 'ARIAGridAccessibleWrap.cpp', @@ -29,12 +29,16 @@ SOURCES += [ 'nsWinUtils.cpp', 'Platform.cpp', 'RootAccessibleWrap.cpp', - 'ServiceProvider.cpp', 'TextLeafAccessibleWrap.cpp', ] +# This file cannot be built in unified mode because it includes ISimpleDOMNode_i.c. +SOURCES += [ + 'ServiceProvider.cpp', +] + if CONFIG['MOZ_XUL']: - SOURCES += [ + UNIFIED_SOURCES += [ 'XULListboxAccessibleWrap.cpp', 'XULMenuAccessibleWrap.cpp', 'XULTreeGridAccessibleWrap.cpp', diff --git a/accessible/src/windows/sdn/moz.build b/accessible/src/windows/sdn/moz.build index 1ea1388f2ccb..f1a7ba935f96 100644 --- a/accessible/src/windows/sdn/moz.build +++ b/accessible/src/windows/sdn/moz.build @@ -4,7 +4,7 @@ # 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/. -SOURCES += [ +UNIFIED_SOURCES += [ 'sdnAccessible.cpp', 'sdnDocAccessible.cpp', 'sdnTextAccessible.cpp', From 84836b3da9b7747b9c0fc743b5031d7df31c5d33 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Mon, 16 Dec 2013 14:11:10 -0800 Subject: [PATCH 09/34] Bug 950293 (Part 1) - Fix handling of little-endian EXIF data. r=tn --- image/decoders/EXIF.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/image/decoders/EXIF.cpp b/image/decoders/EXIF.cpp index 1c7abd237f94..42296cfb3c92 100644 --- a/image/decoders/EXIF.cpp +++ b/image/decoders/EXIF.cpp @@ -78,16 +78,13 @@ bool EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut) { // Determine byte order. - if (MatchString("MM", 2)) + if (MatchString("MM\0*", 4)) mByteOrder = ByteOrder::BigEndian; - else if (MatchString("II", 2)) + else if (MatchString("II*\0", 4)) mByteOrder = ByteOrder::LittleEndian; else return false; - if (!MatchString("\0*", 2)) - return false; - // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which // is the maximum size of the entry APP1 segment.) uint32_t ifd0Offset; From a5a5fddae5aeaf26566f7bfee8ccb893c96e64a1 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Tue, 10 Dec 2013 17:10:41 +0100 Subject: [PATCH 10/34] Bug 877115 - [Moz2Dify] Part 1. Remove ImageFormat typedef from GLContext. (r=nical) --- gfx/gl/GLContext.cpp | 12 +++++++----- gfx/gl/GLContext.h | 1 - 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 35203f814eaf..45a8b5b00f2e 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2157,19 +2157,19 @@ GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) if (DebugMode()) { NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); } - ImageFormat readFormatGFX; + SurfaceFormat readFormatGFX; switch (readFormat) { case LOCAL_GL_RGBA: case LOCAL_GL_BGRA: { - readFormatGFX = hasAlpha ? gfxImageFormatARGB32 - : gfxImageFormatRGB24; + readFormatGFX = hasAlpha ? FORMAT_B8G8R8A8 + : FORMAT_B8G8R8X8; break; } case LOCAL_GL_RGB: { MOZ_ASSERT(readPixelSize == 2); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); - readFormatGFX = gfxImageFormatRGB16_565; + readFormatGFX = FORMAT_R5G6B5; break; } default: { @@ -2198,7 +2198,9 @@ GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) } } - tempSurf = new gfxImageSurface(dest->GetSize(), readFormatGFX, false); + tempSurf = new gfxImageSurface(dest->GetSize(), + gfxImageFormat(readFormatGFX), + false); readSurf = tempSurf; } else { readPixelSize = destPixelSize; diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 4ebfe1bb3395..cb399d7296fa 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -2377,7 +2377,6 @@ protected: typedef class gfx::SharedSurface SharedSurface; typedef gfx::SharedSurfaceType SharedSurfaceType; - typedef gfxImageFormat ImageFormat; typedef gfx::SurfaceFormat SurfaceFormat; public: From 99e812a7824f2f6b368cfcc5e592c3d01473d91b Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Tue, 10 Dec 2013 17:11:11 +0100 Subject: [PATCH 11/34] Bug 877115 - [Moz2Dify] Part 2. Moz2Dify GLContext::ResizeOffscreen signature. (carries r=nical) --- gfx/gl/GLContext.h | 5 +++-- gfx/gl/GLContextProviderCGL.mm | 6 +++--- gfx/gl/GLContextProviderEGL.cpp | 6 +++--- gfx/gl/GLContextProviderWGL.cpp | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index cb399d7296fa..61499a5ce501 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -41,6 +41,7 @@ #include "GLContextSymbols.h" #include "mozilla/GenericRefCounted.h" #include "mozilla/Scoped.h" +#include "gfx2DGlue.h" #ifdef DEBUG #define MOZ_ENABLE_GL_TRACKING 1 @@ -2492,8 +2493,8 @@ public: * * Only valid if IsOffscreen() returns true. */ - virtual bool ResizeOffscreen(const gfxIntSize& size) { - return ResizeScreenBuffer(size); + virtual bool ResizeOffscreen(const gfx::IntSize& size) { + return ResizeScreenBuffer(ThebesIntSize(size)); } /* diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index e90392bf2e3c..dd4d4d121bdd 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -188,16 +188,16 @@ public: return true; } - bool ResizeOffscreen(const gfxIntSize& aNewSize); + bool ResizeOffscreen(const gfx::IntSize& aNewSize); NSOpenGLContext *mContext; GLuint mTempTextureName; }; bool -GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) +GLContextCGL::ResizeOffscreen(const gfx::IntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + return ResizeScreenBuffer(ThebesIntSize(aNewSize)); } static GLContextCGL * diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 570e7363f4ce..1fbda44c4483 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -539,7 +539,7 @@ public: bool BindTex2DOffscreen(GLContext *aOffscreen); void UnbindTex2DOffscreen(GLContext *aOffscreen); - bool ResizeOffscreen(const gfxIntSize& aNewSize); + bool ResizeOffscreen(const gfx::IntSize& aNewSize); void BindOffscreenFramebuffer(); static already_AddRefed @@ -613,9 +613,9 @@ protected: }; bool -GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) +GLContextEGL::ResizeOffscreen(const gfx::IntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + return ResizeScreenBuffer(ThebesIntSize(aNewSize)); } static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index b1715338563c..130aeffe5ad7 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -378,7 +378,7 @@ public: } } - bool ResizeOffscreen(const gfxIntSize& aNewSize); + bool ResizeOffscreen(const gfx::IntSize& aNewSize); HGLRC Context() { return mContext; } @@ -428,9 +428,9 @@ IsValidSizeForFormat(HDC hDC, int format, } bool -GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) +GLContextWGL::ResizeOffscreen(const gfx::IntSize& aNewSize) { - return ResizeScreenBuffer(aNewSize); + return ResizeScreenBuffer(ThebesIntSize(aNewSize)); } static GLContextWGL * From 2fdd39a52c436551bb8d8e8a147046a70b55bd54 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Tue, 10 Dec 2013 17:11:58 +0100 Subject: [PATCH 12/34] Bug 877115 - [Moz2Dify] Part 3. Change gfxIntSize to gfx::IntSize in GLContext::OffscreenSize and dependendent classes. r=nical --- gfx/gl/GLBlitHelper.cpp | 32 +++++++++---------- gfx/gl/GLBlitHelper.h | 33 ++++++++++--------- gfx/gl/GLContext.cpp | 4 +-- gfx/gl/GLContext.h | 2 +- gfx/gl/GLScreenBuffer.cpp | 12 +++---- gfx/gl/GLScreenBuffer.h | 8 ++--- gfx/gl/GLUploadHelpers.h | 10 +++--- gfx/gl/SharedSurface.h | 8 ++--- gfx/gl/SharedSurfaceANGLE.cpp | 4 +-- gfx/gl/SharedSurfaceANGLE.h | 6 ++-- gfx/gl/SharedSurfaceEGL.cpp | 8 ++--- gfx/gl/SharedSurfaceEGL.h | 12 +++---- gfx/gl/SharedSurfaceGL.cpp | 33 +++++++++++-------- gfx/gl/SharedSurfaceGL.h | 23 ++++++++------ gfx/gl/SharedSurfaceGralloc.cpp | 6 ++-- gfx/gl/SharedSurfaceGralloc.h | 6 ++-- gfx/gl/SharedSurfaceIO.cpp | 6 ++-- gfx/gl/SharedSurfaceIO.h | 4 +-- gfx/gl/SurfaceFactory.h | 2 +- gfx/layers/CopyableCanvasLayer.cpp | 12 +++++-- gfx/layers/d3d10/CanvasLayerD3D10.cpp | 24 ++++++-------- gfx/layers/d3d9/CanvasLayerD3D9.cpp | 24 ++++++-------- gfx/layers/opengl/TextureHostOGL.cpp | 46 ++++++++++++++++++++++----- 23 files changed, 182 insertions(+), 143 deletions(-) diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index 4dcc90867500..3f54e9c335c4 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -14,7 +14,7 @@ namespace gl { static void RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, - GLenum aInternalFormat, const gfxIntSize& aSize) + GLenum aInternalFormat, const gfx::IntSize& aSize) { if (aSamples) { aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, @@ -31,7 +31,7 @@ RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfxIntSize& aSize) + GLenum aType, const gfx::IntSize& aSize) { GLuint tex = 0; aGL->fGenTextures(1, &tex); @@ -57,7 +57,7 @@ CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfxIntSize& aSize) + const gfx::IntSize& aSize) { MOZ_ASSERT(aFormats.color_texInternalFormat); MOZ_ASSERT(aFormats.color_texFormat); @@ -73,7 +73,7 @@ CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfxIntSize& aSize) + const gfx::IntSize& aSize) { GLuint rb = 0; aGL->fGenRenderbuffers(1, &rb); @@ -87,7 +87,7 @@ CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, void CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfxIntSize& aSize, bool aMultisample, + const gfx::IntSize& aSize, bool aMultisample, GLuint* aColorMSRB, GLuint* aDepthRB, GLuint* aStencilRB) { @@ -351,7 +351,7 @@ GLBlitHelper::InitTexQuadProgram(GLenum target) } bool -GLBlitHelper::UseTexQuadProgram(GLenum target, const gfxIntSize& srcSize) +GLBlitHelper::UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize) { if (!InitTexQuadProgram(target)) { return false; @@ -397,8 +397,8 @@ GLBlitHelper::DeleteTexBlitProgram() void GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize) + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); @@ -419,8 +419,8 @@ GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, void GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, const GLFormats& srcFormats) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); @@ -443,8 +443,8 @@ GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum srcTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); @@ -563,8 +563,8 @@ GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, void GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum destTarget) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); @@ -590,8 +590,8 @@ GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, void GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const gfxIntSize& srcSize, - const gfxIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum srcTarget, GLenum destTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h index f46565cc429b..987c4fdb586a 100644 --- a/gfx/gl/GLBlitHelper.h +++ b/gfx/gl/GLBlitHelper.h @@ -11,8 +11,7 @@ #include "GLConsts.h" #include "nsSize.h" #include "mozilla/Attributes.h" - -struct nsIntSize; +#include "mozilla/gfx/Point.h" namespace mozilla { namespace gl { @@ -26,7 +25,7 @@ class GLContext; * See mozilla::gl::CreateTexture. */ GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfxIntSize& aSize); + const gfx::IntSize& aSize); /** * Helper function that creates a 2D texture aSize.width x aSize.height with @@ -39,7 +38,7 @@ GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, * GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE */ GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfxIntSize& aSize); + GLenum aType, const gfx::IntSize& aSize); /** * Helper function to create, potentially, multisample render buffers suitable @@ -47,7 +46,7 @@ GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, * storage specified by aFormat. returns GL render buffer object id. */ GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfxIntSize& aSize); + const gfx::IntSize& aSize); /** * Helper function to create, potentially, multisample render buffers suitable @@ -56,7 +55,7 @@ GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, * aColorMSRB, aDepthRB, and aStencilRB */ void CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfxIntSize& aSize, bool aMultisample, + const gfx::IntSize& aSize, bool aMultisample, GLuint* aColorMSRB, GLuint* aDepthRB, GLuint* aStencilRB); @@ -77,7 +76,7 @@ class GLBlitHelper MOZ_FINAL void UseBlitProgram(); void SetBlitFramebufferForDestTexture(GLuint aTexture); - bool UseTexQuadProgram(GLenum target, const nsIntSize& srcSize); + bool UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize); bool InitTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D); void DeleteTexBlitProgram(); @@ -90,23 +89,23 @@ public: // then you'll need the framebuffer_blit extensions to use // the first BlitFramebufferToFramebuffer. void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const nsIntSize& srcSize, - const nsIntSize& destSize); + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize); void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const nsIntSize& srcSize, - const nsIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, const GLFormats& srcFormats); void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const nsIntSize& srcSize, - const nsIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum srcTarget = LOCAL_GL_TEXTURE_2D); void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const nsIntSize& srcSize, - const nsIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum destTarget = LOCAL_GL_TEXTURE_2D); void BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const nsIntSize& srcSize, - const nsIntSize& destSize, + const gfx::IntSize& srcSize, + const gfx::IntSize& destSize, GLenum srcTarget = LOCAL_GL_TEXTURE_2D, GLenum destTarget = LOCAL_GL_TEXTURE_2D); }; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 45a8b5b00f2e..6ef31c924249 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -1495,7 +1495,7 @@ GLContext::PublishFrame() { MOZ_ASSERT(mScreen); - if (!mScreen->PublishFrame(OffscreenSize())) + if (!mScreen->PublishFrame(ThebesIntSize(OffscreenSize()))) return false; return true; @@ -2459,7 +2459,7 @@ GLContext::GuaranteeResolve() fFinish(); } -const gfxIntSize& +const gfx::IntSize& GLContext::OffscreenSize() const { MOZ_ASSERT(IsOffscreen()); diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 61499a5ce501..90d451fea200 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -2502,7 +2502,7 @@ public: * * Only valid if IsOffscreen() returns true. */ - const gfxIntSize& OffscreenSize() const; + const gfx::IntSize& OffscreenSize() const; void BindFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index c94a7cc90c6a..5e6d75391558 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -339,7 +339,7 @@ GLScreenBuffer::AssureBlitted() MOZ_ASSERT(drawFB != 0); MOZ_ASSERT(drawFB != readFB); MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); - MOZ_ASSERT(mDraw->Size() == mRead->Size()); + MOZ_ASSERT(ToIntSize(mDraw->Size()) == mRead->Size()); ScopedBindFramebuffer boundFB(mGL); ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); @@ -347,8 +347,8 @@ GLScreenBuffer::AssureBlitted() BindReadFB_Internal(drawFB); BindDrawFB_Internal(readFB); - const gfxIntSize& srcSize = mDraw->Size(); - const gfxIntSize& destSize = mRead->Size(); + const gfxIntSize& srcSize = mDraw->Size(); + const gfx::IntSize& destSize = mRead->Size(); mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, 0, 0, destSize.width, destSize.height, @@ -393,7 +393,7 @@ GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) if (mRead && surf->AttachType() == SharedSurf()->AttachType() && - size == Size()) + ToIntSize(size) == Size()) { // Same size, same type, ready for reuse! mRead->Attach(surf); @@ -482,7 +482,7 @@ void GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) { MOZ_ASSERT(src && dest); - MOZ_ASSERT(dest->GetSize() == src->Size()); + MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size()); MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageFormatARGB32 : gfxImageFormatRGB24)); @@ -681,7 +681,7 @@ ReadBuffer::Attach(SharedSurface_GL* surf) mSurf = surf; } -const gfxIntSize& +const gfx::IntSize& ReadBuffer::Size() const { return mSurf->Size(); diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 593a48787450..f95a0d888015 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -18,7 +18,7 @@ #include "SurfaceTypes.h" #include "GLContextTypes.h" #include "GLDefs.h" -#include "gfxPoint.h" +#include "gfx2DGlue.h" // Forwards: class gfxImageSurface; @@ -124,7 +124,7 @@ public: // Cannot attach a surf of a different AttachType or Size than before. void Attach(SharedSurface_GL* surf); - const gfxIntSize& Size() const; + const gfx::IntSize& Size() const; GLuint FB() const { return mFB; @@ -231,9 +231,9 @@ public: void DeletingFB(GLuint fb); - const gfxIntSize& Size() const { + const gfx::IntSize& Size() const { MOZ_ASSERT(mRead); - MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); + MOZ_ASSERT(!mDraw || ToIntSize(mDraw->Size()) == mRead->Size()); return mRead->Size(); } diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h index af6a2bcf1faf..1c314dba0b02 100644 --- a/gfx/gl/GLUploadHelpers.h +++ b/gfx/gl/GLUploadHelpers.h @@ -89,11 +89,11 @@ UploadSurfaceToTexture(GLContext* gl, gfx::DataSourceSurface *aSurface, const nsIntRegion& aDstRegion, GLuint& aTexture, - bool aOverwrite, - const nsIntPoint& aSrcPoint, - bool aPixelBuffer, - GLenum aTextureUnit, - GLenum aTextureTarget); + bool aOverwrite = false, + const nsIntPoint& aSrcPoint = nsIntPoint(0, 0), + bool aPixelBuffer = false, + GLenum aTextureUnit = LOCAL_GL_TEXTURE0, + GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D); bool CanUploadSubTextures(GLContext* gl); bool CanUploadNonPowerOfTwo(GLContext* gl); diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 82d597a37213..e4e8845287c8 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -18,7 +18,7 @@ #include #include "mozilla/Attributes.h" #include "GLDefs.h" -#include "gfxPoint.h" +#include "mozilla/gfx/Point.h" #include "SurfaceTypes.h" namespace mozilla { @@ -32,14 +32,14 @@ protected: const SharedSurfaceType mType; const APITypeT mAPI; const AttachmentType mAttachType; - const gfxIntSize mSize; + const gfx::IntSize mSize; const bool mHasAlpha; bool mIsLocked; SharedSurface(SharedSurfaceType type, APITypeT api, AttachmentType attachType, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha) : mType(type) , mAPI(api) @@ -93,7 +93,7 @@ public: return mAttachType; } - const gfxIntSize& Size() const { + const gfx::IntSize& Size() const { return mSize; } diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp index abc5308a2b2f..d6eb11ef4d39 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -176,7 +176,7 @@ ChooseConfig(GLContext* gl, static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, EGLDisplay display, EGLConfig config, - const gfxIntSize& size) + const gfx::IntSize& size) { EGLint attribs[] = { LOCAL_EGL_WIDTH, size.width, @@ -192,7 +192,7 @@ static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, SharedSurface_ANGLEShareHandle* SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, EGLContext context, EGLConfig config, - const gfxIntSize& size, bool hasAlpha) + const gfx::IntSize& size, bool hasAlpha) { GLLibraryEGL* egl = gl->GetLibraryEGL(); MOZ_ASSERT(egl); diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h index d6bedfd51a90..d398f30e1f39 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -25,7 +25,7 @@ class SharedSurface_ANGLEShareHandle public: static SharedSurface_ANGLEShareHandle* Create(GLContext* gl, ID3D10Device1* d3d, EGLContext context, EGLConfig config, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha); static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) { @@ -43,7 +43,7 @@ protected: SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, EGLContext context, EGLSurface pbuffer, @@ -101,7 +101,7 @@ protected: ID3D10Device1* d3d, const SurfaceCaps& caps); - virtual SharedSurface* CreateShared(const gfxIntSize& size) { + virtual SharedSurface* CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConsD3D, mContext, mConfig, diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index 153ab7bd25a8..8f5b15bfb7ec 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -21,7 +21,7 @@ namespace gl { SharedSurface_EGLImage* SharedSurface_EGLImage::Create(GLContext* prodGL, const GLFormats& formats, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, EGLContext context) { @@ -52,7 +52,7 @@ SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, const GLFormats& formats, GLuint prodTex) @@ -123,7 +123,7 @@ SharedSurface_EGLImage::LockProdImpl() static bool CreateTexturePipe(GLLibraryEGL* const egl, GLContext* const gl, - const GLFormats& formats, const gfxIntSize& size, + const GLFormats& formats, const gfx::IntSize& size, GLuint* const out_tex, EGLImage* const out_image) { MOZ_ASSERT(out_tex && out_image); @@ -173,7 +173,7 @@ SharedSurface_EGLImage::Fence() gfxImageFormat format = HasAlpha() ? gfxImageFormatARGB32 : gfxImageFormatRGB24; - mPixels = new gfxImageSurface(Size(), format); + mPixels = new gfxImageSurface(ThebesIntSize(Size()), format); } mPixels->Flush(); diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 0824e6680e60..242b0d7add4f 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -24,10 +24,10 @@ class SharedSurface_EGLImage { public: static SharedSurface_EGLImage* Create(GLContext* prodGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha, - EGLContext context); + const GLFormats& formats, + const gfx::IntSize& size, + bool hasAlpha, + EGLContext context); static SharedSurface_EGLImage* Cast(SharedSurface* surf) { MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLImageShare); @@ -53,7 +53,7 @@ protected: SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, const GLFormats& formats, GLuint prodTex); @@ -106,7 +106,7 @@ protected: {} public: - virtual SharedSurface* CreateShared(const gfxIntSize& size) { + virtual SharedSurface* CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext); } diff --git a/gfx/gl/SharedSurfaceGL.cpp b/gfx/gl/SharedSurfaceGL.cpp index 46b83f2adef1..859106642b8b 100644 --- a/gfx/gl/SharedSurfaceGL.cpp +++ b/gfx/gl/SharedSurfaceGL.cpp @@ -8,6 +8,7 @@ #include "GLBlitHelper.h" #include "ScopedGLHelpers.h" #include "gfxImageSurface.h" +#include "mozilla/gfx/2D.h" using namespace mozilla::gfx; @@ -243,7 +244,7 @@ SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps, SharedSurface_Basic* SharedSurface_Basic::Create(GLContext* gl, const GLFormats& formats, - const gfxIntSize& size, + const IntSize& size, bool hasAlpha) { gl->MakeCurrent(); @@ -252,18 +253,18 @@ SharedSurface_Basic::Create(GLContext* gl, formats.color_texType, size); - gfxImageFormat format = gfxImageFormatRGB24; + SurfaceFormat format = FORMAT_B8G8R8X8; switch (formats.color_texInternalFormat) { case LOCAL_GL_RGB: case LOCAL_GL_RGB8: if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) - format = gfxImageFormatRGB16_565; + format = FORMAT_R5G6B5; else - format = gfxImageFormatRGB24; + format = FORMAT_B8G8R8X8; break; case LOCAL_GL_RGBA: case LOCAL_GL_RGBA8: - format = gfxImageFormatARGB32; + format = FORMAT_B8G8R8A8; break; default: MOZ_CRASH("Unhandled Tex format."); @@ -272,9 +273,9 @@ SharedSurface_Basic::Create(GLContext* gl, } SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, - const gfxIntSize& size, + const IntSize& size, bool hasAlpha, - gfxImageFormat format, + SurfaceFormat format, GLuint tex) : SharedSurface_GL(SharedSurfaceType::Basic, AttachmentType::GLTexture, @@ -283,7 +284,7 @@ SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, hasAlpha) , mTex(tex) { - mData = new gfxImageSurface(size, format); + mData = Factory::CreateDataSourceSurface(size, format); } SharedSurface_Basic::~SharedSurface_Basic() @@ -301,8 +302,12 @@ SharedSurface_Basic::Fence() MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize()); mGL->MakeCurrent(); - mData->Flush(); - mGL->ReadScreenIntoImageSurface(mData); + nsRefPtr wrappedData = + new gfxImageSurface(mData->GetData(), + ThebesIntSize(mData->GetSize()), + mData->Stride(), + SurfaceFormatToImageFormat(mData->GetFormat())); + mGL->ReadScreenIntoImageSurface(wrappedData); mData->MarkDirty(); } @@ -310,10 +315,10 @@ SharedSurface_Basic::Fence() SharedSurface_GLTexture* SharedSurface_GLTexture::Create(GLContext* prodGL, - GLContext* consGL, - const GLFormats& formats, - const gfxIntSize& size, - bool hasAlpha) + GLContext* consGL, + const GLFormats& formats, + const gfx::IntSize& size, + bool hasAlpha) { MOZ_ASSERT(prodGL); MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL)); diff --git a/gfx/gl/SharedSurfaceGL.h b/gfx/gl/SharedSurfaceGL.h index 25bb00e53ac8..70221aa2e7df 100644 --- a/gfx/gl/SharedSurfaceGL.h +++ b/gfx/gl/SharedSurfaceGL.h @@ -22,6 +22,9 @@ namespace mozilla { namespace gl { class GLContext; } + namespace gfx { + class DataSourceSurface; + } } namespace mozilla { @@ -43,7 +46,7 @@ protected: SharedSurface_GL(SharedSurfaceType type, AttachmentType attachType, GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha) : SharedSurface(type, APITypeT::OpenGL, attachType, size, hasAlpha) , mGL(gl) @@ -121,7 +124,7 @@ class SharedSurface_Basic public: static SharedSurface_Basic* Create(GLContext* gl, const GLFormats& formats, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha); static SharedSurface_Basic* Cast(SharedSurface* surf) { @@ -132,12 +135,12 @@ public: protected: const GLuint mTex; - nsRefPtr mData; + RefPtr mData; SharedSurface_Basic(GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, - gfxImageFormat format, + gfx::SurfaceFormat format, GLuint tex); public: @@ -160,7 +163,7 @@ public: } // Implementation-specific functions below: - gfxImageSurface* GetData() { + gfx::DataSourceSurface* GetData() { return mData; } }; @@ -173,7 +176,7 @@ public: : SurfaceFactory_GL(gl, SharedSurfaceType::Basic, caps) {} - virtual SharedSurface* CreateShared(const gfxIntSize& size) { + virtual SharedSurface* CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha); } @@ -188,7 +191,7 @@ public: static SharedSurface_GLTexture* Create(GLContext* prodGL, GLContext* consGL, const GLFormats& formats, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha); static SharedSurface_GLTexture* Cast(SharedSurface* surf) { @@ -205,7 +208,7 @@ protected: SharedSurface_GLTexture(GLContext* prodGL, GLContext* consGL, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, GLuint tex) : SharedSurface_GL(SharedSurfaceType::GLTextureShare, @@ -258,7 +261,7 @@ public: MOZ_ASSERT(consGL != prodGL); } - virtual SharedSurface* CreateShared(const gfxIntSize& size) { + virtual SharedSurface* CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha); } diff --git a/gfx/gl/SharedSurfaceGralloc.cpp b/gfx/gl/SharedSurfaceGralloc.cpp index d34044a1ad61..214d94f98a90 100644 --- a/gfx/gl/SharedSurfaceGralloc.cpp +++ b/gfx/gl/SharedSurfaceGralloc.cpp @@ -17,6 +17,8 @@ #include "../layers/ipc/ShadowLayers.h" #include "ScopedGLHelpers.h" +#include "gfx2DGlue.h" + #define DEBUG_GRALLOC #ifdef DEBUG_GRALLOC #define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0) @@ -50,7 +52,7 @@ SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, SharedSurface_Gralloc* SharedSurface_Gralloc::Create(GLContext* prodGL, const GLFormats& formats, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, ISurfaceAllocator* allocator) { @@ -75,7 +77,7 @@ SharedSurface_Gralloc::Create(GLContext* prodGL, gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA : GFX_CONTENT_COLOR; - if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc)) + if (!allocator->AllocSurfaceDescriptorWithCaps(ThebesIntSize(size), type, USING_GL_RENDERING_ONLY, &baseDesc)) return false; if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) { diff --git a/gfx/gl/SharedSurfaceGralloc.h b/gfx/gl/SharedSurfaceGralloc.h index 3a78da7bf406..a13f624bf333 100644 --- a/gfx/gl/SharedSurfaceGralloc.h +++ b/gfx/gl/SharedSurfaceGralloc.h @@ -26,7 +26,7 @@ class SharedSurface_Gralloc public: static SharedSurface_Gralloc* Create(GLContext* prodGL, const GLFormats& formats, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, layers::ISurfaceAllocator* allocator); @@ -52,7 +52,7 @@ protected: const GLuint mProdTex; SharedSurface_Gralloc(GLContext* prodGL, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha, GLLibraryEGL* egl, layers::ISurfaceAllocator* allocator, @@ -100,7 +100,7 @@ public: const SurfaceCaps& caps, layers::ISurfaceAllocator* allocator = nullptr); - virtual SharedSurface* CreateShared(const gfxIntSize& size) { + virtual SharedSurface* CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; if (!mAllocator) { return nullptr; diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index 4da90f837583..9298f9389eeb 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -21,7 +21,7 @@ SharedSurface_IOSurface::Create(MacIOSurface* surface, GLContext *gl, bool hasAl MOZ_ASSERT(surface); MOZ_ASSERT(gl); - gfxIntSize size(surface->GetWidth(), surface->GetHeight()); + gfx::IntSize size(surface->GetWidth(), surface->GetHeight()); return new SharedSurface_IOSurface(surface, gl, size, hasAlpha); } @@ -57,7 +57,7 @@ SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei hei SharedSurface_IOSurface::SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, bool hasAlpha) : SharedSurface_GL(SharedSurfaceType::IOSurface, AttachmentType::GLTexture, gl, size, hasAlpha) , mSurface(surface) @@ -96,7 +96,7 @@ SharedSurface_IOSurface::~SharedSurface_IOSurface() } SharedSurface* -SurfaceFactory_IOSurface::CreateShared(const gfxIntSize& size) +SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size) { bool hasAlpha = mReadCaps.alpha; RefPtr surf = diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index 8f3bcbb36072..d153b809a525 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -48,7 +48,7 @@ public: MacIOSurface* GetIOSurface() { return mSurface; } private: - SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, const gfxIntSize& size, bool hasAlpha); + SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, const gfx::IntSize& size, bool hasAlpha); RefPtr mSurface; nsRefPtr mImageSurface; @@ -65,7 +65,7 @@ public: } protected: - virtual SharedSurface* CreateShared(const gfxIntSize& size) MOZ_OVERRIDE; + virtual SharedSurface* CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE; }; } /* namespace gfx */ diff --git a/gfx/gl/SurfaceFactory.h b/gfx/gl/SurfaceFactory.h index 56f52324d26c..869f6488183b 100644 --- a/gfx/gl/SurfaceFactory.h +++ b/gfx/gl/SurfaceFactory.h @@ -30,7 +30,7 @@ public: virtual ~SurfaceFactory(); protected: - virtual SharedSurface* CreateShared(const gfxIntSize& size) = 0; + virtual SharedSurface* CreateShared(const gfx::IntSize& size) = 0; std::queue mScraps; diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index ef0b90c04ed1..ec6fb6f808b1 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -16,6 +16,7 @@ #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat #include "gfxRect.h" // for gfxRect #include "gfxUtils.h" // for gfxUtils +#include "gfx2DGlue.h" // for ThebesIntSize, etc #include "mozilla/gfx/BaseSize.h" // for BaseSize #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc @@ -97,6 +98,7 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) if (mGLContext) { nsRefPtr readSurf; + RefPtr readDSurf; nsRefPtr resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); @@ -105,7 +107,7 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) return; } - gfxIntSize readSize(sharedSurf->Size()); + gfxIntSize readSize(ThebesIntSize(sharedSurf->Size())); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxImageFormatRGB24 : gfxImageFormatARGB32; @@ -125,8 +127,14 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); if (surfGL->Type() == SharedSurfaceType::Basic) { + // sharedSurf_Basic->mData must outlive readSurf and readDSurf. Alas, + // readSurf and readDSurf may not leave the scope they were declared in. SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); - readSurf = sharedSurf_Basic->GetData(); + readDSurf = sharedSurf_Basic->GetData(); + readSurf = new gfxImageSurface(readDSurf->GetData(), + ThebesIntSize(readDSurf->GetSize()), + readDSurf->Stride(), + SurfaceFormatToImageFormat(readDSurf->GetFormat())); } else { if (resultSurf->GetSize() != readSize || !(readSurf = resultSurf->GetAsImageSurface()) || diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.cpp b/gfx/layers/d3d10/CanvasLayerD3D10.cpp index dca2fd4e35da..3ed02faf451f 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp +++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp @@ -159,21 +159,17 @@ CanvasLayerD3D10::UpdateSurface() return; } - gfxImageSurface* frameData = shareSurf->GetData(); - // Scope for gfxContext, so it's destroyed before Unmap. + gfx::DataSourceSurface* frameData = shareSurf->GetData(); + // Scope for DrawTarget, so it's destroyed before Unmap. { - nsRefPtr mapSurf = - new gfxImageSurface((uint8_t*)map.pData, - shareSurf->Size(), - map.RowPitch, - gfxImageFormatARGB32); - - nsRefPtr ctx = new gfxContext(mapSurf); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(frameData); - ctx->Paint(); - - mapSurf->Flush(); + RefPtr dt = Factory::CreateDrawTargetForData(BACKEND_CAIRO, + (uint8_t*)map.pData, + shareSurf->Size(), + map.RowPitch, + FORMAT_B8G8R8A8); + Rect drawRect(0, 0, shareSurf->Size().width, shareSurf->Size().height); + dt->DrawSurface(frameData, drawRect, drawRect); + dt->Flush(); } mTexture->Unmap(0); diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp index 04dfc199b068..eb592d4bed2c 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -101,21 +101,17 @@ CanvasLayerD3D9::UpdateSurface() D3DLOCKED_RECT rect = textureLock.GetLockRect(); - gfxImageSurface* frameData = shareSurf->GetData(); - // Scope for gfxContext, so it's destroyed early. + gfx::DataSourceSurface* frameData = shareSurf->GetData(); + // Scope for DrawTarget, so it's destroyed early. { - nsRefPtr mapSurf = - new gfxImageSurface((uint8_t*)rect.pBits, - shareSurf->Size(), - rect.Pitch, - gfxImageFormatARGB32); - - gfxContext ctx(mapSurf); - ctx.SetOperator(gfxContext::OPERATOR_SOURCE); - ctx.SetSource(frameData); - ctx.Paint(); - - mapSurf->Flush(); + RefPtr mapDt = Factory::CreateDrawTargetForData(BACKEND_CAIRO, + (uint8_t*)rect.pBits, + shareSurf->Size(), + rect.Pitch, + FORMAT_B8G8R8A8); + Rect drawRect(0, 0, shareSurf->Size().width, shareSurf->Size().height); + mapDt->DrawSurface(frameData, drawRect, drawRect); + mapDt->Flush(); } } else { RECT r; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 7207de68d859..3801e7b7914f 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -483,7 +483,8 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - gfxImageSurface* toUpload = nullptr; + gfxImageSurface* deprecatedToUpload = nullptr; + gfx::DataSourceSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf); @@ -502,8 +503,8 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() mTextureHandle = eglImageSurf->AcquireConsumerTexture(gl()); mTextureTarget = eglImageSurf->TextureTarget(); if (!mTextureHandle) { - toUpload = eglImageSurf->GetPixels(); - MOZ_ASSERT(toUpload); + deprecatedToUpload = eglImageSurf->GetPixels(); + MOZ_ASSERT(deprecatedToUpload); } else { mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8 : FORMAT_R8G8B8X8; @@ -530,9 +531,23 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() MOZ_CRASH("Invalid SharedSurface type."); } + if (deprecatedToUpload) { + // FIXME Remove this whole block when deprecatedToUpload gets deleted + // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? + nsIntSize size(deprecatedToUpload->GetSize()); + nsIntRect rect(nsIntPoint(0,0), size); + nsIntRegion bounds(rect); + mFormat = UploadSurfaceToTexture(gl(), + deprecatedToUpload, + bounds, + mUploadTexture, + true); + mTextureHandle = mUploadTexture; + mTextureTarget = LOCAL_GL_TEXTURE_2D; + } if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(toUpload->GetSize()); + nsIntSize size(ThebesIntSize(toUpload->GetSize())); nsIntRect rect(nsIntPoint(0,0), size); nsIntRegion bounds(rect); mFormat = UploadSurfaceToTexture(gl(), @@ -949,7 +964,8 @@ SurfaceStreamHostOGL::Lock() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - gfxImageSurface* toUpload = nullptr; + gfxImageSurface* deprecatedToUpload = nullptr; + DataSourceSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf); @@ -968,8 +984,8 @@ SurfaceStreamHostOGL::Lock() mTextureHandle = eglImageSurf->AcquireConsumerTexture(mGL); mTextureTarget = eglImageSurf->TextureTarget(); if (!mTextureHandle) { - toUpload = eglImageSurf->GetPixels(); - MOZ_ASSERT(toUpload); + deprecatedToUpload = eglImageSurf->GetPixels(); + MOZ_ASSERT(deprecatedToUpload); } else { mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8 : FORMAT_R8G8B8X8; @@ -996,9 +1012,23 @@ SurfaceStreamHostOGL::Lock() MOZ_CRASH("Invalid SharedSurface type."); } + if (deprecatedToUpload) { + // FIXME Remove this whole block when deprecatedToUpload gets deleted + // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? + nsIntSize size(deprecatedToUpload->GetSize()); + nsIntRect rect(nsIntPoint(0,0), size); + nsIntRegion bounds(rect); + mFormat = UploadSurfaceToTexture(mGL, + deprecatedToUpload, + bounds, + mUploadTexture, + true); + mTextureHandle = mUploadTexture; + mTextureTarget = LOCAL_GL_TEXTURE_2D; + } if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(toUpload->GetSize()); + nsIntSize size(ThebesIntSize(toUpload->GetSize())); nsIntRect rect(nsIntPoint(0,0), size); nsIntRegion bounds(rect); mFormat = UploadSurfaceToTexture(mGL, From 4372b58d1cc096b8189cf4646ca937949d1b319b Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Tue, 10 Dec 2013 17:12:18 +0100 Subject: [PATCH 13/34] Bug 877115 - [Moz2Dify] Part 4. Change gfxIntSize to gfx::IntSize in GLScreenBuffer and friends. (carries r=nical) --- gfx/gl/GLScreenBuffer.cpp | 20 ++++++++++---------- gfx/gl/GLScreenBuffer.h | 24 ++++++++++++------------ gfx/gl/SurfaceFactory.cpp | 2 +- gfx/gl/SurfaceFactory.h | 2 +- gfx/gl/SurfaceStream.cpp | 10 +++++----- gfx/gl/SurfaceStream.h | 14 +++++++------- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index 5e6d75391558..45bd0bd9ecbd 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -27,7 +27,7 @@ namespace gl { GLScreenBuffer* GLScreenBuffer::Create(GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, const SurfaceCaps& caps) { if (caps.antialias && @@ -339,7 +339,7 @@ GLScreenBuffer::AssureBlitted() MOZ_ASSERT(drawFB != 0); MOZ_ASSERT(drawFB != readFB); MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); - MOZ_ASSERT(ToIntSize(mDraw->Size()) == mRead->Size()); + MOZ_ASSERT(mDraw->Size() == mRead->Size()); ScopedBindFramebuffer boundFB(mGL); ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); @@ -347,7 +347,7 @@ GLScreenBuffer::AssureBlitted() BindReadFB_Internal(drawFB); BindDrawFB_Internal(readFB); - const gfxIntSize& srcSize = mDraw->Size(); + const gfx::IntSize& srcSize = mDraw->Size(); const gfx::IntSize& destSize = mRead->Size(); mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, @@ -381,7 +381,7 @@ GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamTyp } void -GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) +GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size) { ScopedBindFramebuffer autoFB(mGL); @@ -393,7 +393,7 @@ GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) if (mRead && surf->AttachType() == SharedSurf()->AttachType() && - ToIntSize(size) == Size()) + size == Size()) { // Same size, same type, ready for reuse! mRead->Attach(surf); @@ -419,7 +419,7 @@ GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) } bool -GLScreenBuffer::Swap(const gfxIntSize& size) +GLScreenBuffer::Swap(const gfx::IntSize& size) { SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size); if (!nextSurf) { @@ -438,7 +438,7 @@ GLScreenBuffer::Swap(const gfxIntSize& size) } bool -GLScreenBuffer::PublishFrame(const gfxIntSize& size) +GLScreenBuffer::PublishFrame(const gfx::IntSize& size) { AssureBlitted(); @@ -447,7 +447,7 @@ GLScreenBuffer::PublishFrame(const gfxIntSize& size) } bool -GLScreenBuffer::Resize(const gfxIntSize& size) +GLScreenBuffer::Resize(const gfx::IntSize& size) { SharedSurface* surface = mStream->Resize(mFactory, size); if (!surface) @@ -458,7 +458,7 @@ GLScreenBuffer::Resize(const gfxIntSize& size) } DrawBuffer* -GLScreenBuffer::CreateDraw(const gfxIntSize& size) +GLScreenBuffer::CreateDraw(const gfx::IntSize& size) { GLContext* gl = mFactory->GL(); const GLFormats& formats = mFactory->Formats(); @@ -514,7 +514,7 @@ DrawBuffer* DrawBuffer::Create(GLContext* const gl, const SurfaceCaps& caps, const GLFormats& formats, - const gfxIntSize& size) + const gfx::IntSize& size) { if (!caps.color) { MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil); diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index f95a0d888015..2c37f1e7094c 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -18,7 +18,7 @@ #include "SurfaceTypes.h" #include "GLContextTypes.h" #include "GLDefs.h" -#include "gfx2DGlue.h" +#include "mozilla/gfx/Point.h" // Forwards: class gfxImageSurface; @@ -48,18 +48,18 @@ public: static DrawBuffer* Create(GLContext* const gl, const SurfaceCaps& caps, const GLFormats& formats, - const gfxIntSize& size); + const gfx::IntSize& size); protected: GLContext* const mGL; - const gfxIntSize mSize; + const gfx::IntSize mSize; const GLuint mFB; const GLuint mColorMSRB; const GLuint mDepthRB; const GLuint mStencilRB; DrawBuffer(GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, GLuint fb, GLuint colorMSRB, GLuint depthRB, @@ -75,7 +75,7 @@ protected: public: virtual ~DrawBuffer(); - const gfxIntSize& Size() const { + const gfx::IntSize& Size() const { return mSize; } @@ -148,7 +148,7 @@ protected: public: // Infallible. static GLScreenBuffer* Create(GLContext* gl, - const gfxIntSize& size, + const gfx::IntSize& size, const SurfaceCaps& caps); protected: @@ -233,7 +233,7 @@ public: const gfx::IntSize& Size() const { MOZ_ASSERT(mRead); - MOZ_ASSERT(!mDraw || ToIntSize(mDraw->Size()) == mRead->Size()); + MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); return mRead->Size(); } @@ -270,19 +270,19 @@ public: protected: // Returns false on error or inability to resize. - bool Swap(const gfxIntSize& size); + bool Swap(const gfx::IntSize& size); public: - bool PublishFrame(const gfxIntSize& size); + bool PublishFrame(const gfx::IntSize& size); - bool Resize(const gfxIntSize& size); + bool Resize(const gfx::IntSize& size); void Readback(SharedSurface_GL* src, gfxImageSurface* dest); protected: - void Attach(SharedSurface* surface, const gfxIntSize& size); + void Attach(SharedSurface* surface, const gfx::IntSize& size); - DrawBuffer* CreateDraw(const gfxIntSize& size); + DrawBuffer* CreateDraw(const gfx::IntSize& size); ReadBuffer* CreateRead(SharedSurface_GL* surf); public: diff --git a/gfx/gl/SurfaceFactory.cpp b/gfx/gl/SurfaceFactory.cpp index 9a00f2988fdb..885f447ed64c 100644 --- a/gfx/gl/SurfaceFactory.cpp +++ b/gfx/gl/SurfaceFactory.cpp @@ -21,7 +21,7 @@ SurfaceFactory::~SurfaceFactory() } SharedSurface* -SurfaceFactory::NewSharedSurface(const gfxIntSize& size) +SurfaceFactory::NewSharedSurface(const gfx::IntSize& size) { // Attempt to reuse an old surface. while (!mScraps.empty()) { diff --git a/gfx/gl/SurfaceFactory.h b/gfx/gl/SurfaceFactory.h index 869f6488183b..4209d4628a0d 100644 --- a/gfx/gl/SurfaceFactory.h +++ b/gfx/gl/SurfaceFactory.h @@ -35,7 +35,7 @@ protected: std::queue mScraps; public: - SharedSurface* NewSharedSurface(const gfxIntSize& size); + SharedSurface* NewSharedSurface(const gfx::IntSize& size); // Auto-deletes surfs of the wrong type. void Recycle(SharedSurface*& surf); diff --git a/gfx/gl/SurfaceStream.cpp b/gfx/gl/SurfaceStream.cpp index 4048fe78abe0..1b55ded14d0e 100644 --- a/gfx/gl/SurfaceStream.cpp +++ b/gfx/gl/SurfaceStream.cpp @@ -57,7 +57,7 @@ SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glC } void -SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& size, +SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size, SharedSurface*& surf) { MOZ_ASSERT(!surf); @@ -170,7 +170,7 @@ SurfaceStream::SwapConsumer() } SharedSurface* -SurfaceStream::Resize(SurfaceFactory* factory, const gfxIntSize& size) +SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size) { MonitorAutoLock lock(mMonitor); @@ -220,7 +220,7 @@ SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) + const gfx::IntSize& size) { MonitorAutoLock lock(mMonitor); if (mConsumer) { @@ -313,7 +313,7 @@ SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) + const gfx::IntSize& size) { MonitorAutoLock lock(mMonitor); @@ -407,7 +407,7 @@ SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) + const gfx::IntSize& size) { PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer"); diff --git a/gfx/gl/SurfaceStream.h b/gfx/gl/SurfaceStream.h index b39af35d9b65..a597f614b650 100644 --- a/gfx/gl/SurfaceStream.h +++ b/gfx/gl/SurfaceStream.h @@ -10,7 +10,7 @@ #include #include "mozilla/Monitor.h" #include "mozilla/Attributes.h" -#include "gfxPoint.h" +#include "mozilla/gfx/Point.h" #include "SurfaceTypes.h" namespace mozilla { @@ -89,7 +89,7 @@ protected: from = nullptr; } - void New(SurfaceFactory* factory, const gfxIntSize& size, + void New(SurfaceFactory* factory, const gfx::IntSize& size, SharedSurface*& surf); void Delete(SharedSurface*& surf); void Recycle(SurfaceFactory* factory, SharedSurface*& surf); @@ -117,9 +117,9 @@ public: * One common failure is asking for a too-large |size|. */ virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size) = 0; + const gfx::IntSize& size) = 0; - virtual SharedSurface* Resize(SurfaceFactory* factory, const gfxIntSize& size); + virtual SharedSurface* Resize(SurfaceFactory* factory, const gfx::IntSize& size); protected: // SwapCons will return the same surface more than once, @@ -148,7 +148,7 @@ public: * SwapCons being called in Render. */ virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); + const gfx::IntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); @@ -168,7 +168,7 @@ public: virtual ~SurfaceStream_TripleBuffer_Copy(); virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); + const gfx::IntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); @@ -200,7 +200,7 @@ private: public: // Done writing to prod, swap prod and staging virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfxIntSize& size); + const gfx::IntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); From 96f82c49cb8391cc8f8242b7cac6a92734eb5f1d Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Tue, 10 Dec 2013 17:12:42 +0100 Subject: [PATCH 14/34] Bug 877115 - [Moz2Dify] Part 5. Minimize gfxIntSize usage in GLContext. r=nical --- gfx/gl/GLContext.cpp | 6 +++--- gfx/gl/GLContext.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 6ef31c924249..72b883573e53 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -2467,7 +2467,7 @@ GLContext::OffscreenSize() const } bool -GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps) +GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps) { GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps); if (!newScreen) @@ -2490,7 +2490,7 @@ GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& cap } bool -GLContext::ResizeScreenBuffer(const gfxIntSize& size) +GLContext::ResizeScreenBuffer(const IntSize& size) { if (!IsOffscreenSizeAllowed(size)) return false; @@ -2533,7 +2533,7 @@ GLContext::EmptyTexGarbageBin() } bool -GLContext::IsOffscreenSizeAllowed(const gfxIntSize& aSize) const { +GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const { int32_t biggerDimension = std::max(aSize.width, aSize.height); int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize); return biggerDimension <= maxAllowed; diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 90d451fea200..6d1c5635afbc 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -2494,7 +2494,7 @@ public: * Only valid if IsOffscreen() returns true. */ virtual bool ResizeOffscreen(const gfx::IntSize& size) { - return ResizeScreenBuffer(ThebesIntSize(size)); + return ResizeScreenBuffer(size); } /* @@ -2714,7 +2714,7 @@ public: return thisShared == otherShared; } - bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) { + bool InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps) { if (!CreateScreenBuffer(size, caps)) return false; @@ -2735,7 +2735,7 @@ public: protected: // Note that it does -not- clear the resized buffers. - bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) { + bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps) { if (!IsOffscreenSizeAllowed(size)) return false; @@ -2757,11 +2757,11 @@ protected: return false; } - bool CreateScreenBufferImpl(const gfxIntSize& size, + bool CreateScreenBufferImpl(const gfx::IntSize& size, const SurfaceCaps& caps); public: - bool ResizeScreenBuffer(const gfxIntSize& size); + bool ResizeScreenBuffer(const gfx::IntSize& size); protected: SurfaceCaps mCaps; @@ -2861,7 +2861,7 @@ public: void EmptyTexGarbageBin(); - bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const; + bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; protected: GLuint mReadTextureImagePrograms[4]; From 2d0ad0d42d287c74e4804f2c5d9687a10ecf004c Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Mon, 16 Dec 2013 15:50:53 -0500 Subject: [PATCH 15/34] Bug 877115 - [Moz2Dify] Part 6. Moz2Dify SharedSurface_EGLImage::GetPixels. r=nical --- gfx/gl/SharedSurfaceEGL.cpp | 18 ++++++++----- gfx/gl/SharedSurfaceEGL.h | 4 +-- gfx/layers/opengl/TextureHostOGL.cpp | 38 +++------------------------- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index 8f5b15bfb7ec..4178f81bd957 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -170,14 +170,18 @@ SharedSurface_EGLImage::Fence() } if (!mPixels) { - gfxImageFormat format = - HasAlpha() ? gfxImageFormatARGB32 - : gfxImageFormatRGB24; - mPixels = new gfxImageSurface(ThebesIntSize(Size()), format); + SurfaceFormat format = + HasAlpha() ? FORMAT_B8G8R8A8 + : FORMAT_B8G8R8X8; + mPixels = Factory::CreateDataSourceSurface(Size(), format); } - mPixels->Flush(); - mGL->ReadScreenIntoImageSurface(mPixels); + nsRefPtr wrappedData = + new gfxImageSurface(mPixels->GetData(), + ThebesIntSize(mPixels->GetSize()), + mPixels->Stride(), + SurfaceFormatToImageFormat(mPixels->GetFormat())); + mGL->ReadScreenIntoImageSurface(wrappedData); mPixels->MarkDirty(); return; } @@ -270,7 +274,7 @@ SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL) return 0; } -gfxImageSurface* +DataSourceSurface* SharedSurface_EGLImage::GetPixels() const { MutexAutoLock lock(mMutex); diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 242b0d7add4f..03339f44bb75 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -40,7 +40,7 @@ protected: GLLibraryEGL* const mEGL; const GLFormats mFormats; GLuint mProdTex; - nsRefPtr mPixels; + RefPtr mPixels; GLuint mProdTexForPipe; // Moves to mProdTex when mPipeActive becomes true. EGLImage mImage; GLContext* mCurConsGL; @@ -82,7 +82,7 @@ public: GLuint AcquireConsumerTexture(GLContext* consGL); // Will be void if AcquireConsumerTexture returns non-zero. - gfxImageSurface* GetPixels() const; + gfx::DataSourceSurface* GetPixels() const; }; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 3801e7b7914f..58c35e52f639 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -483,7 +483,6 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - gfxImageSurface* deprecatedToUpload = nullptr; gfx::DataSourceSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { @@ -503,8 +502,8 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() mTextureHandle = eglImageSurf->AcquireConsumerTexture(gl()); mTextureTarget = eglImageSurf->TextureTarget(); if (!mTextureHandle) { - deprecatedToUpload = eglImageSurf->GetPixels(); - MOZ_ASSERT(deprecatedToUpload); + toUpload = eglImageSurf->GetPixels(); + MOZ_ASSERT(toUpload); } else { mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8 : FORMAT_R8G8B8X8; @@ -531,20 +530,6 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() MOZ_CRASH("Invalid SharedSurface type."); } - if (deprecatedToUpload) { - // FIXME Remove this whole block when deprecatedToUpload gets deleted - // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(deprecatedToUpload->GetSize()); - nsIntRect rect(nsIntPoint(0,0), size); - nsIntRegion bounds(rect); - mFormat = UploadSurfaceToTexture(gl(), - deprecatedToUpload, - bounds, - mUploadTexture, - true); - mTextureHandle = mUploadTexture; - mTextureTarget = LOCAL_GL_TEXTURE_2D; - } if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? nsIntSize size(ThebesIntSize(toUpload->GetSize())); @@ -964,7 +949,6 @@ SurfaceStreamHostOGL::Lock() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - gfxImageSurface* deprecatedToUpload = nullptr; DataSourceSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { @@ -984,8 +968,8 @@ SurfaceStreamHostOGL::Lock() mTextureHandle = eglImageSurf->AcquireConsumerTexture(mGL); mTextureTarget = eglImageSurf->TextureTarget(); if (!mTextureHandle) { - deprecatedToUpload = eglImageSurf->GetPixels(); - MOZ_ASSERT(deprecatedToUpload); + toUpload = eglImageSurf->GetPixels(); + MOZ_ASSERT(toUpload); } else { mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8 : FORMAT_R8G8B8X8; @@ -1012,20 +996,6 @@ SurfaceStreamHostOGL::Lock() MOZ_CRASH("Invalid SharedSurface type."); } - if (deprecatedToUpload) { - // FIXME Remove this whole block when deprecatedToUpload gets deleted - // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(deprecatedToUpload->GetSize()); - nsIntRect rect(nsIntPoint(0,0), size); - nsIntRegion bounds(rect); - mFormat = UploadSurfaceToTexture(mGL, - deprecatedToUpload, - bounds, - mUploadTexture, - true); - mTextureHandle = mUploadTexture; - mTextureTarget = LOCAL_GL_TEXTURE_2D; - } if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? nsIntSize size(ThebesIntSize(toUpload->GetSize())); From 1b5da13c0dc8b3cc76508a19f55d8f6ca5115dd9 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 13 Dec 2013 19:17:18 -0500 Subject: [PATCH 16/34] Bug 950281 - micro-optimize NS_TableDrivenQI by ensuring the table has at least 1 non-null entry; r=bsmedberg --- xpcom/glue/nsISupportsImpl.cpp | 4 ++-- xpcom/glue/nsISupportsImpl.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/xpcom/glue/nsISupportsImpl.cpp b/xpcom/glue/nsISupportsImpl.cpp index 4f0170c5d653..75198aacce68 100644 --- a/xpcom/glue/nsISupportsImpl.cpp +++ b/xpcom/glue/nsISupportsImpl.cpp @@ -8,7 +8,7 @@ nsresult NS_FASTCALL NS_TableDrivenQI(void* aThis, const QITableEntry* entries, REFNSIID aIID, void **aInstancePtr) { - while (entries->iid) { + do { if (aIID.Equals(*entries->iid)) { nsISupports* r = reinterpret_cast @@ -19,7 +19,7 @@ NS_TableDrivenQI(void* aThis, const QITableEntry* entries, } ++entries; - } + } while (entries->iid); *aInstancePtr = nullptr; return NS_ERROR_NO_INTERFACE; diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index bd09a65f1711..27abc32a1cb1 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -609,8 +609,15 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ reinterpret_cast((_class*) 0x1000)) \ }, +/* + * XXX: we want to use mozilla::ArrayLength (or equivalent, + * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't + * see that the static_assert condition is actually constant in those + * cases, even with constexpr support (?). + */ #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \ { nullptr, 0 } }; \ + static_assert((sizeof(table)/sizeof(table[0])) > 1, "need at least 1 interface"); \ rv = NS_TableDrivenQI(static_cast(_ptr), \ table, aIID, aInstancePtr); From f74a7c3b7ed7a1830d63f1d0eabfc4d42362d39d Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 16 Dec 2013 10:20:35 -0600 Subject: [PATCH 17/34] Bug 950527 - Mark asm.js success messages as not being an error (r=bbouvier) --- js/src/jit-test/tests/asm.js/testBasic.js | 32 ----------------------- js/src/js.msg | 2 +- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/js/src/jit-test/tests/asm.js/testBasic.js b/js/src/jit-test/tests/asm.js/testBasic.js index 716985703cb8..c9847fc61bcf 100644 --- a/js/src/jit-test/tests/asm.js/testBasic.js +++ b/js/src/jit-test/tests/asm.js/testBasic.js @@ -107,38 +107,6 @@ assertTypeFailInEval('function f(global, {imports}) { "use asm"; function g() {} assertTypeFailInEval('function f(g = 2) { "use asm"; function g() {} return g }'); assertTypeFailInEval('function *f() { "use asm"; function g() {} return g }'); -function assertLinkFailInEval(str) -{ - if (!isAsmJSCompilationAvailable()) - return; - - var caught = false; - var oldOpts = options("werror"); - assertEq(oldOpts.indexOf("werror"), -1); - try { - eval(str); - } catch (e) { - assertEq((''+e).indexOf(ASM_OK_STRING) == -1, false); - caught = true; - } - assertEq(caught, true); - options("werror"); - - var code = eval(str); - - var caught = false; - var oldOpts = options("werror"); - assertEq(oldOpts.indexOf("werror"), -1); - try { - code.apply(null, Array.slice(arguments, 1)); - } catch (e) { - caught = true; - } - assertEq(caught, true); - options("werror"); -} -assertLinkFailInEval('(function(global) { "use asm"; var im=global.Math.imul; function g() {} return g })'); - assertThrowsInstanceOf(function() { new Function(USE_ASM + 'var)') }, SyntaxError); assertThrowsInstanceOf(function() { new Function(USE_ASM + 'return)') }, SyntaxError); assertThrowsInstanceOf(function() { new Function(USE_ASM + 'var z=-2w') }, SyntaxError); diff --git a/js/src/js.msg b/js/src/js.msg index 75e0dce894c4..ba232ffccc93 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -391,7 +391,7 @@ MSG_DEF(JSMSG_DATE_NOT_FINITE, 337, 0, JSEXN_RANGEERR, "date value is not MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 338, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body") MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 339, 1, JSEXN_TYPEERR, "asm.js type error: {0}") MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 340, 1, JSEXN_TYPEERR, "asm.js link error: {0}") -MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 341, 1, JSEXN_ERR, "successfully compiled asm.js code ({0})") +MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 341, 1, JSEXN_NONE, "Successfully compiled asm.js code ({0})") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 342, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_YIELD_IN_ARROW, 343, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield") MSG_DEF(JSMSG_WRONG_VALUE, 344, 2, JSEXN_ERR, "expected {0} but found {1}") From ef7ea5783d1462c1b62847c9dd0be4a8a308c54e Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 16 Dec 2013 14:55:49 -0800 Subject: [PATCH 18/34] Bug 937089 - Deoptimize arguments when it is redeclared as a variable inside a with statement inside an eval, r=luke. --- js/src/frontend/Parser.cpp | 21 +++++++++++---------- js/src/jit-test/tests/basic/bug937089.js | 10 ++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug937089.js diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 41971fe98211..2fbf9361e175 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2853,17 +2853,18 @@ Parser::bindVarOrConst(BindData *data, if (pc->sc->isFunctionBox()) { FunctionBox *funbox = pc->sc->asFunctionBox(); funbox->setMightAliasLocals(); - - /* - * This definition isn't being added to the parse context's - * declarations, so make sure to indicate the need to deoptimize - * the script's arguments object. Mark the function as if it - * contained a debugger statement, which will deoptimize arguments - * as much as possible. - */ - if (name == cx->names().arguments) - funbox->setHasDebuggerStatement(); } + + /* + * This definition isn't being added to the parse context's + * declarations, so make sure to indicate the need to deoptimize + * the script's arguments object. Mark the function as if it + * contained a debugger statement, which will deoptimize arguments + * as much as possible. + */ + if (name == cx->names().arguments) + pc->sc->setHasDebuggerStatement(); + return true; } diff --git a/js/src/jit-test/tests/basic/bug937089.js b/js/src/jit-test/tests/basic/bug937089.js new file mode 100644 index 000000000000..09eedbe0307a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug937089.js @@ -0,0 +1,10 @@ + +function test1() { + eval("with (arguments) var arguments = 0;"); +} +test1(); + +function test2() { + eval("eval('with (arguments) var arguments = 0;')"); +} +test2(); From b038c71e607e14b5104c71e5a3457f3496c0a426 Mon Sep 17 00:00:00 2001 From: Christian Holler Date: Mon, 16 Dec 2013 18:44:55 +0100 Subject: [PATCH 19/34] Bug 950658 - Clear pending exception in HeapTypeSetKey::instantiate on OOM. r=bhackett --HG-- extra : rebase_source : 8f8c28f51ee7f08ef822fec5ac590a7d1cfebed7 --- js/src/jsinfer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 5bfec3ee4129..44f7edef8dae 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -884,8 +884,10 @@ HeapTypeSetKey::instantiate(JSContext *cx) { if (maybeTypes()) return true; - if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx)) + if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx)) { + cx->clearPendingException(); return false; + } maybeTypes_ = object()->maybeType()->getProperty(cx, id()); return maybeTypes_ != nullptr; } From 8d1888e84af19a97b6e3065b570da8696c83efc3 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Tue, 17 Dec 2013 11:58:16 +1300 Subject: [PATCH 20/34] Bug 866080 - Use Android I420ColorConverter in OMX plugin r=sotaro,doublec --- content/media/plugins/MPAPI.h | 2 +- content/media/plugins/MediaPluginReader.cpp | 67 +++++++-- content/media/plugins/MediaPluginReader.h | 6 + media/omx-plugin/Makefile.in | 2 + media/omx-plugin/OmxPlugin.cpp | 134 +++++++++++++----- .../include/ics/I420ColorConverter.h | 35 +++++ .../include/ics/II420ColorConverter.h | 127 +++++++++++++++++ .../lib/ics/libvideoeditorplayer/Makefile.in | 25 ++++ .../libvideoeditorplayer.cpp | 23 +++ .../lib/ics/libvideoeditorplayer/moz.build | 15 ++ toolkit/toolkit.mozbuild | 1 + 11 files changed, 393 insertions(+), 44 deletions(-) create mode 100644 media/omx-plugin/include/ics/I420ColorConverter.h create mode 100644 media/omx-plugin/include/ics/II420ColorConverter.h create mode 100644 media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in create mode 100644 media/omx-plugin/lib/ics/libvideoeditorplayer/libvideoeditorplayer.cpp create mode 100644 media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build diff --git a/content/media/plugins/MPAPI.h b/content/media/plugins/MPAPI.h index 1ba8069098d3..4ebe642989bb 100644 --- a/content/media/plugins/MPAPI.h +++ b/content/media/plugins/MPAPI.h @@ -11,7 +11,7 @@ namespace MPAPI { enum ColorFormat { - YCbCr, + I420, RGB565 }; diff --git a/content/media/plugins/MediaPluginReader.cpp b/content/media/plugins/MediaPluginReader.cpp index a76950f9428e..7f14dfce5af2 100644 --- a/content/media/plugins/MediaPluginReader.cpp +++ b/content/media/plugins/MediaPluginReader.cpp @@ -18,6 +18,7 @@ namespace mozilla { typedef mozilla::layers::Image Image; +typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage; MediaPluginReader::MediaPluginReader(AbstractMediaDecoder *aDecoder, const nsACString& aContentType) : @@ -170,7 +171,7 @@ bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip, currentImage = bufferCallback.GetImage(); int64_t pos = mDecoder->GetResource()->Tell(); nsIntRect picture = mPicture; - + nsAutoPtr v; if (currentImage) { gfx::IntSize frameSize = currentImage->GetSize(); @@ -338,33 +339,79 @@ MediaPluginReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::Ima void * MediaPluginReader::ImageBufferCallback::operator()(size_t aWidth, size_t aHeight, - MPAPI::ColorFormat aColorFormat) + MPAPI::ColorFormat aColorFormat) { if (!mImageContainer) { NS_WARNING("No image container to construct an image"); return nullptr; } - nsRefPtr rgbImage; + nsRefPtr image; switch(aColorFormat) { case MPAPI::RGB565: - rgbImage = mozilla::layers::CreateSharedRGBImage(mImageContainer, - nsIntSize(aWidth, aHeight), - gfxImageFormatRGB16_565); - if (!rgbImage) { + image = mozilla::layers::CreateSharedRGBImage(mImageContainer, + nsIntSize(aWidth, aHeight), + gfxImageFormatRGB16_565); + if (!image) { NS_WARNING("Could not create rgb image"); return nullptr; } - mImage = rgbImage; - return rgbImage->AsSharedImage()->GetBuffer(); - case MPAPI::YCbCr: + mImage = image; + return image->AsSharedImage()->GetBuffer(); + case MPAPI::I420: + return CreateI420Image(aWidth, aHeight); default: NS_NOTREACHED("Color format not supported"); return nullptr; } } +uint8_t * +MediaPluginReader::ImageBufferCallback::CreateI420Image(size_t aWidth, + size_t aHeight) +{ + ImageFormat format = PLANAR_YCBCR; + + mImage = mImageContainer->CreateImage(&format, 1 /* numFormats */); + PlanarYCbCrImage *yuvImage = static_cast(mImage.get()); + + if (!yuvImage) { + NS_WARNING("Could not create I420 image"); + return nullptr; + } + + size_t frameSize = aWidth * aHeight; + + // Allocate enough for one full resolution Y plane + // and two quarter resolution Cb/Cr planes. + uint8_t *buffer = yuvImage->AllocateAndGetNewBuffer(frameSize * 3 / 2); + + mozilla::layers::PlanarYCbCrData frameDesc; + + frameDesc.mYChannel = buffer; + frameDesc.mCbChannel = buffer + frameSize; + frameDesc.mCrChannel = buffer + frameSize * 5 / 4; + + frameDesc.mYSize = gfxIntSize(aWidth, aHeight); + frameDesc.mCbCrSize = gfxIntSize(aWidth / 2, aHeight / 2); + + frameDesc.mYStride = aWidth; + frameDesc.mCbCrStride = aWidth / 2; + + frameDesc.mYSkip = 0; + frameDesc.mCbSkip = 0; + frameDesc.mCrSkip = 0; + + frameDesc.mPicX = 0; + frameDesc.mPicY = 0; + frameDesc.mPicSize = gfxIntSize(aWidth, aHeight); + + yuvImage->SetDataNoCopy(frameDesc); + + return buffer; +} + already_AddRefed MediaPluginReader::ImageBufferCallback::GetImage() { diff --git a/content/media/plugins/MediaPluginReader.h b/content/media/plugins/MediaPluginReader.h index 2a48666e77f2..8143c0507277 100644 --- a/content/media/plugins/MediaPluginReader.h +++ b/content/media/plugins/MediaPluginReader.h @@ -65,17 +65,23 @@ public: virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags); virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); + class ImageBufferCallback : public MPAPI::BufferCallback { typedef mozilla::layers::Image Image; + public: ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer); void *operator()(size_t aWidth, size_t aHeight, MPAPI::ColorFormat aColorFormat) MOZ_OVERRIDE; already_AddRefed GetImage(); + private: + uint8_t *CreateI420Image(size_t aWidth, size_t aHeight); + mozilla::layers::ImageContainer *mImageContainer; nsRefPtr mImage; }; + }; } // namespace mozilla diff --git a/media/omx-plugin/Makefile.in b/media/omx-plugin/Makefile.in index 5774eb4310da..dbfdc216adce 100644 --- a/media/omx-plugin/Makefile.in +++ b/media/omx-plugin/Makefile.in @@ -53,6 +53,8 @@ EXTRA_DSO_LDOPTS += \ -lutils \ -L$(DEPTH)/media/omx-plugin/lib/ics/libstagefright \ -lstagefright \ + -L$(DEPTH)/media/omx-plugin/lib/ics/libvideoeditorplayer \ + -lvideoeditorplayer \ $(NULL) INCLUDES += \ diff --git a/media/omx-plugin/OmxPlugin.cpp b/media/omx-plugin/OmxPlugin.cpp index 305673880db7..c2ff759ef2fe 100644 --- a/media/omx-plugin/OmxPlugin.cpp +++ b/media/omx-plugin/OmxPlugin.cpp @@ -37,6 +37,14 @@ #define MOZ_ANDROID_V2_X_X #endif +#if !defined(MOZ_ANDROID_V2_X_X) && !defined(MOZ_ANDROID_HC) +#define MOZ_ANDROID_V4_OR_ABOVE +#endif + +#if defined(MOZ_ANDROID_V4_OR_ABOVE) +#include +#endif + using namespace MPAPI; #if !defined(MOZ_STAGEFRIGHT_OFF_T) @@ -68,6 +76,8 @@ class OmxDecoder { int32_t mVideoSliceHeight; int32_t mVideoCropLeft; int32_t mVideoCropTop; + int32_t mVideoCropRight; + int32_t mVideoCropBottom; int32_t mVideoRotation; int32_t mAudioChannels; int32_t mAudioSampleRate; @@ -92,6 +102,7 @@ class OmxDecoder { void ToVideoFrame_YVU420PackedSemiPlanar32m4ka(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); bool ToVideoFrame_RGB565(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback); bool ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback); + bool ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback); bool ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback); bool ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, int32_t aAudioChannels, int32_t aAudioSampleRate); @@ -139,6 +150,8 @@ OmxDecoder::OmxDecoder(PluginHost *aPluginHost, Decoder *aDecoder) : mVideoSliceHeight(0), mVideoCropLeft(0), mVideoCropTop(0), + mVideoCropRight(0), + mVideoCropBottom(0), mVideoRotation(0), mAudioChannels(-1), mAudioSampleRate(-1), @@ -226,11 +239,48 @@ static uint32_t GetVideoCreationFlags(PluginHost* aPluginHost) #endif } +static bool +IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat) +{ + switch (aColorFormat) { + case OMX_COLOR_FormatCbYCrY: + case OMX_COLOR_FormatYUV420Planar: + case OMX_COLOR_FormatYUV420SemiPlanar: + case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka: + case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: + case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: + LOG("Colour format %#x supported natively.", aColorFormat); + return true; + default: + break; + } + +#if !defined(MOZ_ANDROID_HC) + if (ColorConverter(aColorFormat, OMX_COLOR_Format16bitRGB565).isValid()) { + LOG("Colour format %#x supported by Android ColorConverter.", aColorFormat); + return true; + } +#endif + +#if defined(MOZ_ANDROID_V4_OR_ABOVE) + I420ColorConverter yuvConverter; + + if (yuvConverter.isLoaded() && + yuvConverter.getDecoderOutputFormat() == aColorFormat) { + LOG("Colour format %#x supported by Android I420ColorConverter.", aColorFormat); + return true; + } +#endif + + return false; +} + static sp CreateVideoSource(PluginHost* aPluginHost, const sp& aOmx, const sp& aVideoTrack) { uint32_t flags = GetVideoCreationFlags(aPluginHost); + if (flags == DEFAULT_STAGEFRIGHT_FLAGS) { // Let Stagefright choose hardware or software decoder. sp videoSource = OMXCodec::Create(aOmx, aVideoTrack->getFormat(), @@ -242,30 +292,14 @@ static sp CreateVideoSource(PluginHost* aPluginHost, // check whether we know how to decode this video. int32_t videoColorFormat; if (videoSource->getFormat()->findInt32(kKeyColorFormat, &videoColorFormat)) { - switch (videoColorFormat) { - // We know how to convert these color formats. - case OMX_COLOR_FormatCbYCrY: - case OMX_COLOR_FormatYUV420Planar: - case OMX_COLOR_FormatYUV420SemiPlanar: - case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka: - case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: - case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: - // Use the decoder Stagefright chose for us! - return videoSource; - // Use software decoder for color formats we don't know how to convert. - default: -#ifndef MOZ_ANDROID_HC - if (ColorConverter((OMX_COLOR_FORMATTYPE)videoColorFormat, - OMX_COLOR_Format16bitRGB565).isValid()) { - return videoSource; - } -#endif - // We need to implement a ToVideoFrame_*() color conversion - // function for this video color format. - LOG("Unknown video color format: %#x", videoColorFormat); - break; + if (IsColorFormatSupported((OMX_COLOR_FORMATTYPE)videoColorFormat)) { + return videoSource; } + + // We need to implement a ToVideoFrame_*() color conversion + // function for this video color format. + LOG("Unknown video color format: %#x", videoColorFormat); } else { LOG("Video color format not found"); } @@ -472,29 +506,28 @@ bool OmxDecoder::SetVideoFormat() { return false; } - int32_t cropRight, cropBottom; // Gingerbread does not support the kKeyCropRect key #if !defined(MOZ_ANDROID_V2_X_X) if (!format->findRect(kKeyCropRect, &mVideoCropLeft, &mVideoCropTop, - &cropRight, &cropBottom)) { + &mVideoCropRight, &mVideoCropBottom)) { #endif mVideoCropLeft = 0; mVideoCropTop = 0; - cropRight = mVideoStride - 1; - cropBottom = mVideoSliceHeight - 1; + mVideoCropRight = mVideoStride - 1; + mVideoCropBottom = mVideoSliceHeight - 1; LOG("crop rect not available, assuming no cropping"); #if !defined(MOZ_ANDROID_V2_X_X) } #endif - if (mVideoCropLeft < 0 || mVideoCropLeft >= cropRight || cropRight >= mVideoStride || - mVideoCropTop < 0 || mVideoCropTop >= cropBottom || cropBottom >= mVideoSliceHeight) { - LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, cropRight, cropBottom); + if (mVideoCropLeft < 0 || mVideoCropLeft >= mVideoCropRight || mVideoCropRight >= mVideoStride || + mVideoCropTop < 0 || mVideoCropTop >= mVideoCropBottom || mVideoCropBottom >= mVideoSliceHeight) { + LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom); return false; } - mVideoWidth = cropRight - mVideoCropLeft + 1; - mVideoHeight = cropBottom - mVideoCropTop + 1; + mVideoWidth = mVideoCropRight - mVideoCropLeft + 1; + mVideoHeight = mVideoCropBottom - mVideoCropTop + 1; MOZ_ASSERT(mVideoWidth > 0 && mVideoWidth <= mVideoStride); MOZ_ASSERT(mVideoHeight > 0 && mVideoHeight <= mVideoSliceHeight); @@ -515,7 +548,7 @@ bool OmxDecoder::SetVideoFormat() { LOG("width: %d height: %d component: %s format: %#x stride: %d sliceHeight: %d rotation: %d crop: %d,%d-%d,%d", mVideoWidth, mVideoHeight, componentName, mVideoColorFormat, mVideoStride, mVideoSliceHeight, mVideoRotation, - mVideoCropLeft, mVideoCropTop, cropRight, cropBottom); + mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom); return true; } @@ -682,6 +715,40 @@ bool OmxDecoder::ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs #endif } +bool OmxDecoder::ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) +{ +#if defined(MOZ_ANDROID_V4_OR_ABOVE) + I420ColorConverter yuvConverter; + + if (!yuvConverter.isLoaded()) { + return false; + } + + if (yuvConverter.getDecoderOutputFormat() != mVideoColorFormat) { + return false; + } + + void *buffer = (*aBufferCallback)(mVideoWidth, mVideoHeight, MPAPI::I420); + + ARect crop = { mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom }; + int result = yuvConverter.convertDecoderOutputToI420(aData, + mVideoWidth, + mVideoHeight, + crop, + buffer); + + // result is 0 on success, -1 otherwise. + if (result == OK) { + aFrame->mTimeUs = aTimeUs; + aFrame->mSize = mVideoWidth * mVideoHeight * 3 / 2; + } + + return result == OK; +#else + return false; +#endif +} + bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) { switch (mVideoColorFormat) { // Froyo support is best handled with the android color conversion code. I @@ -710,7 +777,8 @@ bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, break; #endif default: - if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) { + if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback) && + !ToVideoFrame_I420ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) { LOG("Unknown video color format: %#x", mVideoColorFormat); return false; } diff --git a/media/omx-plugin/include/ics/I420ColorConverter.h b/media/omx-plugin/include/ics/I420ColorConverter.h new file mode 100644 index 000000000000..8d48e44b4d02 --- /dev/null +++ b/media/omx-plugin/include/ics/I420ColorConverter.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef I420_COLOR_CONVERTER_H +#define I420_COLOR_CONVERTER_H + +#include + +// This is a wrapper around the I420 color converter functions in +// II420ColorConverter, which is loaded from a shared library. +class I420ColorConverter: public II420ColorConverter { +public: + I420ColorConverter(); + ~I420ColorConverter(); + + // Returns true if the converter functions are successfully loaded. + bool isLoaded(); +private: + void* mHandle; +}; + +#endif /* I420_COLOR_CONVERTER_H */ diff --git a/media/omx-plugin/include/ics/II420ColorConverter.h b/media/omx-plugin/include/ics/II420ColorConverter.h new file mode 100644 index 000000000000..0e3fe8285d7d --- /dev/null +++ b/media/omx-plugin/include/ics/II420ColorConverter.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef II420_COLOR_CONVERTER_H + +#define II420_COLOR_CONVERTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct II420ColorConverter { + + /* + * getDecoderOutputFormat + * Returns the color format (OMX_COLOR_FORMATTYPE) of the decoder output. + * If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed, + * and convertDecoderOutputToI420() can be a no-op. + */ + int (*getDecoderOutputFormat)(); + + /* + * convertDecoderOutputToI420 + * @Desc Converts from the decoder output format to I420 format. + * @note Caller (e.g. VideoEditor) owns the buffers + * @param decoderBits (IN) Pointer to the buffer contains decoder output + * @param decoderWidth (IN) Buffer width, as reported by the decoder + * metadata (kKeyWidth) + * @param decoderHeight (IN) Buffer height, as reported by the decoder + * metadata (kKeyHeight) + * @param decoderRect (IN) The rectangle of the actual frame, as + * reported by decoder metadata (kKeyCropRect) + * @param dstBits (OUT) Pointer to the output I420 buffer + * @return -1 Any error + * @return 0 No Error + */ + int (*convertDecoderOutputToI420)( + void* decoderBits, int decoderWidth, int decoderHeight, + ARect decoderRect, void* dstBits); + + /* + * getEncoderIntputFormat + * Returns the color format (OMX_COLOR_FORMATTYPE) of the encoder input. + * If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed, + * and convertI420ToEncoderInput() and getEncoderInputBufferInfo() can + * be no-ops. + */ + int (*getEncoderInputFormat)(); + + /* convertI420ToEncoderInput + * @Desc This function converts from I420 to the encoder input format + * @note Caller (e.g. VideoEditor) owns the buffers + * @param srcBits (IN) Pointer to the input I420 buffer + * @param srcWidth (IN) Width of the I420 frame + * @param srcHeight (IN) Height of the I420 frame + * @param encoderWidth (IN) Encoder buffer width, as calculated by + * getEncoderBufferInfo() + * @param encoderHeight (IN) Encoder buffer height, as calculated by + * getEncoderBufferInfo() + * @param encoderRect (IN) Rect coordinates of the actual frame inside + * the encoder buffer, as calculated by + * getEncoderBufferInfo(). + * @param encoderBits (OUT) Pointer to the output buffer. The size of + * this buffer is calculated by + * getEncoderBufferInfo() + * @return -1 Any error + * @return 0 No Error + */ + int (*convertI420ToEncoderInput)( + void* srcBits, int srcWidth, int srcHeight, + int encoderWidth, int encoderHeight, ARect encoderRect, + void* encoderBits); + + /* getEncoderInputBufferInfo + * @Desc This function returns metadata for the encoder input buffer + * based on the actual I420 frame width and height. + * @note This API should be be used to obtain the necessary information + * before calling convertI420ToEncoderInput(). + * VideoEditor knows only the width and height of the I420 buffer, + * but it also needs know the width, height, and size of the + * encoder input buffer. The encoder input buffer width and height + * are used to set the metadata for the encoder. + * @param srcWidth (IN) Width of the I420 frame + * @param srcHeight (IN) Height of the I420 frame + * @param encoderWidth (OUT) Encoder buffer width needed + * @param encoderHeight (OUT) Encoder buffer height needed + * @param encoderRect (OUT) Rect coordinates of the actual frame inside + * the encoder buffer + * @param encoderBufferSize (OUT) The size of the buffer that need to be + * allocated by the caller before invoking + * convertI420ToEncoderInput(). + * @return -1 Any error + * @return 0 No Error + */ + int (*getEncoderInputBufferInfo)( + int srcWidth, int srcHeight, + int* encoderWidth, int* encoderHeight, + ARect* encoderRect, int* encoderBufferSize); + +} II420ColorConverter; + +/* The only function that the shared library needs to expose: It fills the + function pointers in II420ColorConverter */ +void getI420ColorConverter(II420ColorConverter *converter); + +#if defined(__cplusplus) +} +#endif + +#endif // II420_COLOR_CONVERTER_H + diff --git a/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in b/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in new file mode 100644 index 000000000000..85c8662e331b --- /dev/null +++ b/media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in @@ -0,0 +1,25 @@ +# Copyright 2012 Mozilla Foundation and Mozilla contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Don't use STL wrappers; this isn't Gecko code +STL_FLAGS = + +# must link statically with the CRT; this isn't Gecko code +USE_STATIC_LIBS = 1 + +include $(topsrcdir)/config/rules.mk + +INCLUDES += \ + -I$(topsrcdir)/media/omx-plugin/include/ics \ + $(NULL) diff --git a/media/omx-plugin/lib/ics/libvideoeditorplayer/libvideoeditorplayer.cpp b/media/omx-plugin/lib/ics/libvideoeditorplayer/libvideoeditorplayer.cpp new file mode 100644 index 000000000000..2c491aeb9e35 --- /dev/null +++ b/media/omx-plugin/lib/ics/libvideoeditorplayer/libvideoeditorplayer.cpp @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "mozilla/Types.h" +#include "I420ColorConverter.h" + +MOZ_EXPORT +I420ColorConverter::I420ColorConverter() +{ +} + +MOZ_EXPORT +I420ColorConverter::~I420ColorConverter() +{ +} + +MOZ_EXPORT bool +I420ColorConverter::isLoaded() +{ + return false; +} diff --git a/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build b/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build new file mode 100644 index 000000000000..40e83bca89d6 --- /dev/null +++ b/media/omx-plugin/lib/ics/libvideoeditorplayer/moz.build @@ -0,0 +1,15 @@ +# -*- 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/. +NO_DIST_INSTALL = True + +if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': + SOURCES += [ + 'libvideoeditorplayer.cpp', + ] + +LIBRARY_NAME = 'videoeditorplayer' + +FORCE_SHARED_LIB = True diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index 1bfbee8e53a9..eeee4ec3045f 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -75,6 +75,7 @@ if CONFIG['MOZ_OMX_PLUGIN']: add_tier_dir('platform', [ 'media/omx-plugin/lib/ics/libutils', 'media/omx-plugin/lib/ics/libstagefright', + 'media/omx-plugin/lib/ics/libvideoeditorplayer', 'media/omx-plugin/lib/gb/libutils', 'media/omx-plugin/lib/gb/libstagefright', 'media/omx-plugin/lib/gb/libstagefright_color_conversion', From 78bf04b8e2794d7a368b0a07e67920c300db0928 Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Sat, 14 Dec 2013 15:30:00 -0500 Subject: [PATCH 21/34] Bug 863872 - If we have overdue TelemetryPings, try to send them all. r=nfroyd, feedback=irving. --- .../components/telemetry/TelemetryFile.jsm | 75 ++++- toolkit/components/telemetry/TelemetryPing.js | 26 +- .../tests/unit/test_TelemetryPing.js | 4 +- .../tests/unit/test_TelemetrySendOldPings.js | 265 ++++++++++++++++++ .../telemetry/tests/unit/xpcshell.ini | 2 + 5 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js diff --git a/toolkit/components/telemetry/TelemetryFile.jsm b/toolkit/components/telemetry/TelemetryFile.jsm index 7a21d5c2fd4e..8db9eb815b58 100644 --- a/toolkit/components/telemetry/TelemetryFile.jsm +++ b/toolkit/components/telemetry/TelemetryFile.jsm @@ -22,8 +22,13 @@ const PR_EXCL = 0x80; const RW_OWNER = parseInt("0600", 8); const RWX_OWNER = parseInt("0700", 8); -// Delete ping files that have been lying around for longer than this. -const MAX_PING_FILE_AGE = 7 * 24 * 60 * 60 * 1000; // 1 week +// Files that have been lying around for longer than MAX_PING_FILE_AGE are +// deleted without being loaded. +const MAX_PING_FILE_AGE = 14 * 24 * 60 * 60 * 1000; // 2 weeks + +// Files that are older than OVERDUE_PING_FILE_AGE, but younger than +// MAX_PING_FILE_AGE indicate that we need to send all of our pings ASAP. +const OVERDUE_PING_FILE_AGE = 7 * 24 * 60 * 60 * 1000; // 1 week // The number of outstanding saved pings that we have issued loading // requests for. @@ -32,6 +37,14 @@ let pingsLoaded = 0; // The number of those requests that have actually completed. let pingLoadsCompleted = 0; +// The number of pings that we have destroyed due to being older +// than MAX_PING_FILE_AGE. +let pingsDiscarded = 0; + +// The number of pings that are older than OVERDUE_PING_FILE_AGE +// but younger than MAX_PING_FILE_AGE. +let pingsOverdue = 0; + // If |true|, send notifications "telemetry-test-save-complete" // and "telemetry-test-load-complete" once save/load is complete. let shouldNotifyUponSave = false; @@ -41,6 +54,14 @@ let pendingPings = []; this.TelemetryFile = { + get MAX_PING_FILE_AGE() { + return MAX_PING_FILE_AGE; + }, + + get OVERDUE_PING_FILE_AGE() { + return OVERDUE_PING_FILE_AGE; + }, + /** * Save a single ping to a file. * @@ -142,7 +163,7 @@ this.TelemetryFile = { * ping. It is passed |true| in case of success, |false| in case of * format error. */ - loadSavedPings: function(sync, onLoad = null) { + loadSavedPings: function(sync, onLoad = null, onDone = null) { let directory = ensurePingDirectory(); let entries = directory.directoryEntries .QueryInterface(Ci.nsIDirectoryEnumerator); @@ -150,7 +171,7 @@ this.TelemetryFile = { pingLoadsCompleted = 0; try { while (entries.hasMoreElements()) { - this.loadHistograms(entries.nextFile, sync, onLoad); + this.loadHistograms(entries.nextFile, sync, onLoad, onDone); } } finally { entries.close(); @@ -169,20 +190,26 @@ this.TelemetryFile = { * ping. It is passed |true| in case of success, |false| in case of * format error. */ - loadHistograms: function loadHistograms(file, sync, onLoad = null) { - let now = new Date(); + loadHistograms: function loadHistograms(file, sync, onLoad = null, onDone = null) { + let now = Date.now(); if (now - file.lastModifiedTime > MAX_PING_FILE_AGE) { // We haven't had much luck in sending this file; delete it. file.remove(true); + pingsDiscarded++; return; } + // This file is a bit stale, and overdue for sending. + if (now - file.lastModifiedTime > OVERDUE_PING_FILE_AGE) { + pingsOverdue++; + } + pingsLoaded++; if (sync) { let stream = Cc["@mozilla.org/network/file-input-stream;1"] .createInstance(Ci.nsIFileInputStream); stream.init(file, -1, -1, 0); - addToPendingPings(file, stream, onLoad); + addToPendingPings(file, stream, onLoad, onDone); } else { let channel = NetUtil.newChannel(file); channel.contentType = "application/json"; @@ -191,7 +218,7 @@ this.TelemetryFile = { if (!Components.isSuccessCode(result)) { return; } - addToPendingPings(file, stream, onLoad); + addToPendingPings(file, stream, onLoad, onDone); }).bind(this)); } }, @@ -203,6 +230,22 @@ this.TelemetryFile = { return pingsLoaded; }, + /** + * The number of pings loaded that are older than OVERDUE_PING_FILE_AGE + * but younger than MAX_PING_FILE_AGE. + */ + get pingsOverdue() { + return pingsOverdue; + }, + + /** + * The number of pings that we just tossed out for being older than + * MAX_PING_FILE_AGE. + */ + get pingsDiscarded() { + return pingsDiscarded; + }, + /** * Iterate destructively through the pending pings. * @@ -249,7 +292,7 @@ function ensurePingDirectory() { return directory; }; -function addToPendingPings(file, stream, onLoad) { +function addToPendingPings(file, stream, onLoad, onDone) { let success = false; try { @@ -263,19 +306,25 @@ function addToPendingPings(file, stream, onLoad) { } pingLoadsCompleted++; pendingPings.push(ping); - if (shouldNotifyUponSave && - pingLoadsCompleted == pingsLoaded) { - Services.obs.notifyObservers(null, "telemetry-test-load-complete", null); - } success = true; } catch (e) { // An error reading the file, or an error parsing the contents. stream.close(); // close is idempotent. file.remove(true); // FIXME: Should be false, isn't it? } + if (onLoad) { onLoad(success); } + + if (pingLoadsCompleted == pingsLoaded) { + if (onDone) { + onDone(); + } + if (shouldNotifyUponSave) { + Services.obs.notifyObservers(null, "telemetry-test-load-complete", null); + } + } }; function finishTelemetrySave(ok, stream) { diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index 6a34661fb0e0..b265432610ac 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -39,6 +39,8 @@ const PREF_PREVIOUS_BUILDID = PREF_BRANCH + "previousBuildID"; const TELEMETRY_INTERVAL = 60000; // Delay before intializing telemetry (ms) const TELEMETRY_DELAY = 60000; +// Delay before initializing telemetry if we're testing (ms) +const TELEMETRY_TEST_DELAY = 100; // Seconds of idle time before pinging. // On idle-daily a gather-telemetry notification is fired, during it probes can @@ -218,6 +220,9 @@ TelemetryPing.prototype = { ret.savedPings = TelemetryFile.pingsLoaded; } + ret.pingsOverdue = TelemetryFile.pingsOverdue; + ret.pingsDiscarded = TelemetryFile.pingsDiscarded; + return ret; }, @@ -598,7 +603,9 @@ TelemetryPing.prototype = { popPayloads: function popPayloads(reason) { function payloadIter() { - yield this.getSessionPayloadAndSlug(reason); + if (reason != "overdue-flush") { + yield this.getSessionPayloadAndSlug(reason); + } let iterator = TelemetryFile.popPendingPings(reason); for (let data of iterator) { yield data; @@ -760,7 +767,7 @@ TelemetryPing.prototype = { /** * Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry. */ - setup: function setup() { + setup: function setup(aTesting) { // Initialize some probes that are kept in their own modules this._thirdPartyCookies = new ThirdPartyCookieProbe(); this._thirdPartyCookies.init(); @@ -823,7 +830,17 @@ TelemetryPing.prototype = { { let success_histogram = Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS"); success_histogram.add(success); - })); + }), () => + { + // If we have any TelemetryPings lying around, we'll be aggressive + // and try to send them all off ASAP. + if (TelemetryFile.pingsOverdue > 0) { + // It doesn't really matter what we pass to this.send as a reason, + // since it's never sent to the server. All that this.send does with + // the reason is check to make sure it's not a test-ping. + this.send("overdue-flush", this._server); + } + }); this.attachObservers(); this.gatherMemory(); @@ -831,7 +848,8 @@ TelemetryPing.prototype = { }); delete this._timer; } - this._timer.initWithCallback(timerCallback.bind(this), TELEMETRY_DELAY, + this._timer.initWithCallback(timerCallback.bind(this), + aTesting ? TELEMETRY_TEST_DELAY : TELEMETRY_DELAY, Ci.nsITimer.TYPE_ONE_SHOT); }, diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js index a9c70abaa70d..a7ecadcd8511 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js @@ -142,7 +142,7 @@ function decodeRequestPayload(request) { let observer = { buffer: "", onStreamComplete: function(loader, context, status, length, result) { - this.buffer = String.fromCharCode.apply(this, result); + this.buffer = String.fromCharCode.apply(this, result); } }; @@ -363,7 +363,7 @@ function runOldPingFileTest() { do_check_true(histogramsFile.exists()); let mtime = histogramsFile.lastModifiedTime; - histogramsFile.lastModifiedTime = mtime - 8 * 24 * 60 * 60 * 1000; // 8 days. + histogramsFile.lastModifiedTime = mtime - (14 * 24 * 60 * 60 * 1000 + 60000); // 14 days, 1m TelemetryPing.testLoadHistograms(histogramsFile, true); do_check_false(histogramsFile.exists()); } diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js new file mode 100644 index 000000000000..f840563b0fe9 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js @@ -0,0 +1,265 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ + +/** + * This test case populates the profile with some fake stored + * pings, and checks that: + * + * 1) Pings that are considered "expired" are deleted and never sent. + * 2) Pings that are considered "overdue" trigger a send of all + * overdue and recent pings. + */ + +Components.utils.import("resource://gre/modules/Services.jsm"); + +// Get the TelemetryPing definitions directly so we can test it without going through xpcom. +// That gives us Cc, Ci, Cr and Cu, as well as a number of consts like PREF_ENABLED, +// and PREF_SERVER. +Services.scriptloader.loadSubScript("resource://gre/components/TelemetryPing.js"); + +Cu.import("resource://testing-common/httpd.js"); +Cu.import("resource://gre/modules/Promise.jsm"); +Cu.import("resource://gre/modules/TelemetryFile.jsm"); + +// We increment TelemetryFile's MAX_PING_FILE_AGE and +// OVERDUE_PING_FILE_AGE by 1ms so that our test pings exceed +// those points in time. +const EXPIRED_PING_FILE_AGE = TelemetryFile.MAX_PING_FILE_AGE + 1; +const OVERDUE_PING_FILE_AGE = TelemetryFile.OVERDUE_PING_FILE_AGE + 1; + +const PING_SAVE_FOLDER = "saved-telemetry-pings"; +const PING_TIMEOUT_LENGTH = 5000; +const EXPIRED_PINGS = 5; +const OVERDUE_PINGS = 6; +const RECENT_PINGS = 4; + +const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS; + +let gHttpServer = new HttpServer(); +let gCreatedPings = 0; +let gSeenPings = 0; + +/** + * Creates some TelemetryPings for the current session and + * saves them to disk. Each ping gets a unique ID slug based on + * an incrementor. + * + * @param aNum the number of pings to create. + * @param aAge the age in milliseconds to offset from now. A value + * of 10 would make the ping 10ms older than now, for + * example. + * @returns an Array with the created pings. + */ +function createSavedPings(aNum, aAge) { + // Create a TelemetryPing service that we can generate payloads from. + // Luckily, the TelemetryPing constructor does nothing that we need to + // clean up. + let pingService = new TelemetryPing(); + let pings = []; + let age = Date.now() - aAge; + for (let i = 0; i < aNum; ++i) { + let payload = pingService.getPayload(); + let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload }; + TelemetryFile.savePing(ping); + if (aAge) { + // savePing writes to the file synchronously, so we're good to + // modify the lastModifedTime now. + let file = getSaveFileForPing(ping); + file.lastModifiedTime = age; + } + gCreatedPings++; + pings.push(ping); + } + return pings; +} + +/** + * Deletes locally saved pings in aPings if they + * exist. + * + * @param aPings an Array of pings to delete. + */ +function clearPings(aPings) { + for (let ping of aPings) { + let file = getSaveFileForPing(ping); + if (file.exists()) { + file.remove(false); + } + } +} + +/** + * Returns a handle for the file that aPing should be + * stored in locally. + * + * @returns nsILocalFile + */ +function getSaveFileForPing(aPing) { + let file = Services.dirsvc.get("ProfD", Ci.nsILocalFile).clone(); + file.append(PING_SAVE_FOLDER); + file.append(aPing.slug); + return file; +} + +/** + * Wait for PING_TIMEOUT_LENGTH ms, and make sure we didn't receive + * TelemetryPings in that time. + * + * @returns Promise + */ +function assertReceivedNoPings() { + let deferred = Promise.defer(); + + do_timeout(PING_TIMEOUT_LENGTH, function() { + if (gSeenPings > 0) { + deferred.reject(); + } else { + deferred.resolve(); + } + }); + + return deferred.promise; +} + +/** + * Returns a Promise that rejects if the number of TelemetryPings + * received by the HttpServer is not equal to aExpectedNum. + * + * @param aExpectedNum the number of pings we expect to receive. + * @returns Promise + */ +function assertReceivedPings(aExpectedNum) { + let deferred = Promise.defer(); + + do_timeout(PING_TIMEOUT_LENGTH, function() { + if (gSeenPings == aExpectedNum) { + deferred.resolve(); + } else { + deferred.reject("Saw " + gSeenPings + " TelemetryPings, " + + "but expected " + aExpectedNum); + } + }) + + return deferred.promise; +} + +/** + * Throws if any pings in aPings is saved locally. + * + * @param aPings an Array of pings to check. + */ +function assertNotSaved(aPings) { + let saved = 0; + for (let ping of aPings) { + let file = getSaveFileForPing(ping); + if (file.exists()) { + saved++; + } + } + if (saved > 0) { + do_throw("Found " + saved + " unexpected saved pings."); + } +} + +/** + * Our handler function for the HttpServer that simply + * increments the gSeenPings global when it successfully + * receives and decodes a TelemetryPing payload. + * + * @param aRequest the HTTP request sent from HttpServer. + */ +function pingHandler(aRequest) { + gSeenPings++; +} + +/** + * Returns a Promise that resolves when gHttpServer has been + * successfully shut down. + * + * @returns Promise + */ +function stopHttpServer() { + let deferred = Promise.defer(); + gHttpServer.stop(function() { + deferred.resolve(); + }) + return deferred.promise; +} + +/** + * Teardown a TelemetryPing instance and clear out any pending + * pings to put as back in the starting state. + */ +function resetTelemetry(aPingService) { + aPingService.uninstall(); + // Quick and dirty way to clear TelemetryFile's pendingPings + // collection, and put it back in its initial state. + let gen = TelemetryFile.popPendingPings(); + for (let item of gen) {}; +} + +/** + * Creates and returns a TelemetryPing instance in "testing" + * mode. + */ +function startTelemetry() { + let service = new TelemetryPing(); + service.setup(true); + return service; +} + +function run_test() { + gHttpServer.registerPrefixHandler("/submit/telemetry/", pingHandler); + gHttpServer.start(-1); + do_get_profile(); + Services.prefs.setBoolPref(PREF_ENABLED, true); + Services.prefs.setCharPref(PREF_SERVER, + "http://localhost:" + gHttpServer.identity.primaryPort); + run_next_test(); +} + +/** + * Test that pings that are considered too old are just chucked out + * immediately and never sent. + */ +add_task(function test_expired_pings_are_deleted() { + let expiredPings = createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE); + let pingService = startTelemetry(); + yield assertReceivedNoPings(); + assertNotSaved(expiredPings); + resetTelemetry(pingService); +}) + +/** + * Test that really recent pings are not sent on Telemetry initialization. + */ +add_task(function test_recent_pings_not_sent() { + let recentPings = createSavedPings(RECENT_PINGS); + let pingService = startTelemetry(); + yield assertReceivedNoPings(); + resetTelemetry(pingService); + clearPings(recentPings); +}); + +/** + * Create some recent, expired and overdue pings. The overdue pings should + * trigger a send of all recent and overdue pings, but the expired pings + * should just be deleted. + */ +add_task(function test_overdue_pings_trigger_send() { + let recentPings = createSavedPings(RECENT_PINGS); + let expiredPings = createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE); + let overduePings = createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE); + + let pingService = startTelemetry(); + yield assertReceivedPings(TOTAL_EXPECTED_PINGS); + + assertNotSaved(recentPings); + assertNotSaved(expiredPings); + assertNotSaved(overduePings); + resetTelemetry(pingService); +}) + +add_task(function teardown() { + yield stopHttpServer(); +}); diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.ini b/toolkit/components/telemetry/tests/unit/xpcshell.ini index 339219fedcdc..cccc7a40baa6 100644 --- a/toolkit/components/telemetry/tests/unit/xpcshell.ini +++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini @@ -12,3 +12,5 @@ tail = [test_TelemetryStopwatch.js] [test_TelemetryPingBuildID.js] [test_ThirdPartyCookieProbe.js] +[test_TelemetrySendOldPings.js] +skip-if = debug == true || os == "android" # Disabled due to intermittent orange on Android From 59305924cb330d06a1c01b9b0d741ec5daa8c43d Mon Sep 17 00:00:00 2001 From: Sean Stangl Date: Mon, 16 Dec 2013 14:40:05 -0800 Subject: [PATCH 22/34] Bug 949183 - Fix jsid static constructor explosion. r=Waldo --- dom/base/nsDOMClassInfo.cpp | 34 +++++++-------- dom/bindings/BindingUtils.cpp | 12 +++--- dom/bindings/BindingUtils.h | 4 +- dom/bindings/Codegen.py | 8 ++-- dom/bindings/DOMJSProxyHandler.cpp | 2 +- dom/plugins/base/nsNPAPIPlugin.h | 2 +- dom/workers/RuntimeService.cpp | 4 +- js/public/Class.h | 2 +- js/public/Id.h | 43 ++++++++++++------- js/src/builtin/Object.cpp | 2 +- js/src/gc/Barrier.h | 6 +-- js/src/gdb/mozilla/jsid.py | 2 +- js/src/gdb/tests/test-jsid.cpp | 2 +- js/src/gdb/tests/test-jsid.py | 2 +- js/src/jit/BaselineIC.cpp | 2 +- js/src/jit/IonAnalysis.cpp | 2 +- js/src/jit/IonBuilder.cpp | 4 +- js/src/jit/MCallOptimize.cpp | 10 ++--- js/src/jit/MIR.cpp | 12 +++--- js/src/jsapi.cpp | 4 +- js/src/jsarray.cpp | 2 +- js/src/jscompartment.cpp | 2 +- js/src/jsinfer.cpp | 24 +++++------ js/src/jsinfer.h | 10 ++--- js/src/jsinferinlines.h | 6 +-- js/src/jsobjinlines.h | 6 +-- js/src/jsproxy.cpp | 32 +++++++------- js/src/jsproxy.h | 2 +- js/src/vm/Debugger.cpp | 2 +- js/src/vm/Id.cpp | 6 +-- js/src/vm/Shape.cpp | 2 +- js/src/vm/Shape.h | 2 +- js/src/vm/String.h | 2 +- js/src/vm/StructuredClone.cpp | 2 +- js/xpconnect/src/XPCCallContext.cpp | 2 +- js/xpconnect/src/XPCJSRuntime.cpp | 6 +-- js/xpconnect/src/XPCQuickStubs.cpp | 4 +- js/xpconnect/src/dictionary_helper_gen.py | 2 +- js/xpconnect/src/xpcprivate.h | 4 +- js/xpconnect/wrappers/AccessCheck.cpp | 8 ++-- js/xpconnect/wrappers/ChromeObjectWrapper.cpp | 2 +- js/xpconnect/wrappers/FilteringWrapper.cpp | 8 ++-- js/xpconnect/wrappers/XrayWrapper.cpp | 8 ++-- xpcom/base/CycleCollectedJSRuntime.cpp | 2 +- 44 files changed, 158 insertions(+), 147 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index fdd4043450fa..c83c0b72505c 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -573,15 +573,15 @@ nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nullptr; bool nsDOMClassInfo::sIsInitialized = false; -jsid nsDOMClassInfo::sLocation_id = JSID_VOID; -jsid nsDOMClassInfo::sConstructor_id = JSID_VOID; -jsid nsDOMClassInfo::sLength_id = JSID_VOID; -jsid nsDOMClassInfo::sItem_id = JSID_VOID; -jsid nsDOMClassInfo::sNamedItem_id = JSID_VOID; -jsid nsDOMClassInfo::sEnumerate_id = JSID_VOID; -jsid nsDOMClassInfo::sTop_id = JSID_VOID; -jsid nsDOMClassInfo::sDocument_id = JSID_VOID; -jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID; +jsid nsDOMClassInfo::sLocation_id = jsid::voidId(); +jsid nsDOMClassInfo::sConstructor_id = jsid::voidId(); +jsid nsDOMClassInfo::sLength_id = jsid::voidId(); +jsid nsDOMClassInfo::sItem_id = jsid::voidId(); +jsid nsDOMClassInfo::sNamedItem_id = jsid::voidId(); +jsid nsDOMClassInfo::sEnumerate_id = jsid::voidId(); +jsid nsDOMClassInfo::sTop_id = jsid::voidId(); +jsid nsDOMClassInfo::sDocument_id = jsid::voidId(); +jsid nsDOMClassInfo::sWrappedJSObject_id = jsid::voidId(); static const JSClass *sObjectClass = nullptr; @@ -1945,14 +1945,14 @@ nsDOMClassInfo::ShutDown() } } - sLocation_id = JSID_VOID; - sConstructor_id = JSID_VOID; - sLength_id = JSID_VOID; - sItem_id = JSID_VOID; - sEnumerate_id = JSID_VOID; - sTop_id = JSID_VOID; - sDocument_id = JSID_VOID; - sWrappedJSObject_id = JSID_VOID; + sLocation_id = jsid::voidId(); + sConstructor_id = jsid::voidId(); + sLength_id = jsid::voidId(); + sItem_id = jsid::voidId(); + sEnumerate_id = jsid::voidId(); + sTop_id = jsid::voidId(); + sDocument_id = jsid::voidId(); + sWrappedJSObject_id = jsid::voidId(); NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sSecMan); diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 6dce37c1ed1b..9626aee1701d 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -941,7 +941,7 @@ XrayResolveAttribute(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = attributes->specs - attributeSpecs; - for ( ; attributeIds[i] != JSID_VOID; ++i) { + for ( ; attributeIds[i] != jsid::voidId(); ++i) { if (id == attributeIds[i]) { const JSPropertySpec& attrSpec = attributeSpecs[i]; // Because of centralization, we need to make sure we fault in the @@ -1020,7 +1020,7 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = method->specs - methodsSpecs; - for ( ; methodIds[i] != JSID_VOID; ++i) { + for ( ; methodIds[i] != jsid::voidId(); ++i) { if (id == methodIds[i]) { const JSFunctionSpec& methodSpec = methodsSpecs[i]; JSFunction *fun; @@ -1084,7 +1084,7 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = constant->specs - nativeProperties->constantSpecs; - for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { + for ( ; nativeProperties->constantIds[i] != jsid::voidId(); ++i) { if (id == nativeProperties->constantIds[i]) { desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); desc.object().set(wrapper); @@ -1226,7 +1226,7 @@ XrayEnumerateAttributes(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = attributes->specs - attributeSpecs; - for ( ; attributeIds[i] != JSID_VOID; ++i) { + for ( ; attributeIds[i] != jsid::voidId(); ++i) { if (((flags & JSITER_HIDDEN) || (attributeSpecs[i].flags & JSPROP_ENUMERATE)) && !props.append(attributeIds[i])) { @@ -1264,7 +1264,7 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = method->specs - methodsSpecs; - for ( ; methodIds[i] != JSID_VOID; ++i) { + for ( ; methodIds[i] != jsid::voidId(); ++i) { if (((flags & JSITER_HIDDEN) || (methodsSpecs[i].flags & JSPROP_ENUMERATE)) && !props.append(methodIds[i])) { @@ -1310,7 +1310,7 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = constant->specs - nativeProperties->constantSpecs; - for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { + for ( ; nativeProperties->constantIds[i] != jsid::voidId(); ++i) { if (!props.append(nativeProperties->constantIds[i])) { return false; } diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index de98b3cdf3d4..243f76a71e12 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1408,9 +1408,9 @@ InitIds(JSContext* cx, const Prefable* prefableSpecs, jsid* ids) } } while (++ids, (++spec)->name); - // We ran out of ids for that pref. Put a JSID_VOID in on the id + // We ran out of ids for that pref. Put a jsid::voidId() in on the id // corresponding to the list terminator for the pref. - *ids = JSID_VOID; + *ids = jsid::voidId(); ++ids; } while ((++prefableSpecs)->specs); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 47e964c98055..5b84e67fb2b0 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1426,7 +1426,7 @@ class PropertyDefiner: ',\n'.join(prefableSpecs) + "\n" + "};\n\n") % (specType, name, specType, name)) if doIdArrays: - arrays += ("static jsid %s_ids[%i] = { JSID_VOID };\n\n" % + arrays += ("static jsid %s_ids[%i] = { jsid::voidId() };\n\n" % (name, len(specs))) return arrays @@ -1832,14 +1832,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): if len(idsToInit) > 1: initIds = CGWrapper(initIds, pre="(", post=")", reindent=True) initIds = CGList( - [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), + [CGGeneric("%s_ids[0] == jsid::voidId() &&" % idsToInit[0]), CGGeneric("NS_IsMainThread() &&"), initIds], "\n") initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True) initIds = CGList( [initIds, - CGGeneric((" %s_ids[0] = JSID_VOID;\n" + CGGeneric((" %s_ids[0] = jsid::voidId();\n" " return;") % idsToInit[0]), CGGeneric("}")], "\n") @@ -11297,7 +11297,7 @@ class GlobalGenRoots(): classMembers = [ClassMember(m.identifier.name + "_id", "jsid", visibility="public", - body="JSID_VOID") for m in dictMembers] + body="jsid::voidId()") for m in dictMembers] structName = dict.identifier.name + "Atoms" structs.append((structName, diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 4bb115fbe1e3..57b1ea7e54e4 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -21,7 +21,7 @@ using namespace JS; namespace mozilla { namespace dom { -jsid s_length_id = JSID_VOID; +jsid s_length_id = jsid::voidId(); bool DefineStaticJSVals(JSContext* cx) diff --git a/dom/plugins/base/nsNPAPIPlugin.h b/dom/plugins/base/nsNPAPIPlugin.h index 636e460f0aa1..70429f74c04c 100644 --- a/dom/plugins/base/nsNPAPIPlugin.h +++ b/dom/plugins/base/nsNPAPIPlugin.h @@ -141,7 +141,7 @@ NPStringIdentifierIsPermanent(NPP npp, NPIdentifier id) return JS_StringHasBeenInterned(cx, NPIdentifierToString(id)); } -#define NPIdentifier_VOID (JSIdToNPIdentifier(JSID_VOID)) +#define NPIdentifier_VOID (JSIdToNPIdentifier(jsid::voidId())) NPObject* NP_CALLBACK _getwindowobject(NPP npp); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 9993feb43087..b936b6e0c68f 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -167,7 +167,7 @@ enum { }; // These are jsids for the main runtime. Only touched on the main thread. -jsid gStringIDs[ID_COUNT] = { JSID_VOID }; +jsid gStringIDs[ID_COUNT] = { jsid::voidId() }; const char* gStringChars[] = { "Worker", @@ -1050,7 +1050,7 @@ ResolveWorkerClasses(JSContext* aCx, JS::Handle aObj, JS::Handle) JSID_VOIDHANDLE; extern JS_PUBLIC_DATA(const JS::Handle) JSID_EMPTYHANDLE; @@ -168,7 +181,7 @@ IsPoisonedId(jsid iden) template <> struct GCMethods { - static jsid initial() { return JSID_VOID; } + static jsid initial() { return jsid::voidId(); } static ThingRootKind kind() { return THING_ROOT_ID; } static bool poisoned(jsid id) { return IsPoisonedId(id); } static bool needsPostBarrier(jsid id) { return false; } diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index c77625685982..8ba187365d94 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -605,7 +605,7 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp) if (!ValueToId(cx, args[0], &id)) return false; } else { - id = JSID_VOID; + id = jsid::voidId(); } if (!JSObject::unwatch(cx, obj, id)) diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 0205a3e1ed5b..4d2aa8bcf18d 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -995,7 +995,7 @@ class EncapsulatedId : public BarrieredId { public: explicit EncapsulatedId(jsid id) : BarrieredId(id) {} - explicit EncapsulatedId() : BarrieredId(JSID_VOID) {} + explicit EncapsulatedId() : BarrieredId(jsid::voidId()) {} EncapsulatedId &operator=(const EncapsulatedId &v) { if (v.value != value) @@ -1009,7 +1009,7 @@ class EncapsulatedId : public BarrieredId class RelocatableId : public BarrieredId { public: - explicit RelocatableId() : BarrieredId(JSID_VOID) {} + explicit RelocatableId() : BarrieredId(jsid::voidId()) {} explicit inline RelocatableId(jsid id) : BarrieredId(id) {} ~RelocatableId() { pre(); } @@ -1046,7 +1046,7 @@ class RelocatableId : public BarrieredId class HeapId : public BarrieredId { public: - explicit HeapId() : BarrieredId(JSID_VOID) {} + explicit HeapId() : BarrieredId(jsid::voidId()) {} explicit HeapId(jsid id) : BarrieredId(id) diff --git a/js/src/gdb/mozilla/jsid.py b/js/src/gdb/mozilla/jsid.py index aff1eab2c9e5..60106c07c63d 100644 --- a/js/src/gdb/mozilla/jsid.py +++ b/js/src/gdb/mozilla/jsid.py @@ -46,7 +46,7 @@ class jsid(object): elif tag & jsid.TYPE_INT: body = bits >> 1 elif tag == jsid.TYPE_VOID: - return "JSID_VOID" + return "jsid::voidId()" elif tag == jsid.TYPE_OBJECT: body = ((bits & ~jsid.TYPE_MASK) .cast(self.cache.JSObject_ptr_t)) diff --git a/js/src/gdb/tests/test-jsid.cpp b/js/src/gdb/tests/test-jsid.cpp index dcab84ef37da..ababd5da9536 100644 --- a/js/src/gdb/tests/test-jsid.cpp +++ b/js/src/gdb/tests/test-jsid.cpp @@ -6,7 +6,7 @@ FRAGMENT(jsid, simple) { JS::Rooted interned(cx, JS_InternJSString(cx, string)); JS::Rooted string_id(cx, INTERNED_STRING_TO_JSID(cx, interned)); jsid int_id = INT_TO_JSID(1729); - jsid void_id = JSID_VOID; + jsid void_id = jsid::voidId(); JS::Rooted object_id(cx, OBJECT_TO_JSID(JS::CurrentGlobalOrNull(cx))); breakpoint(); diff --git a/js/src/gdb/tests/test-jsid.py b/js/src/gdb/tests/test-jsid.py index 880abfc3cdb0..97cd8dc17d33 100644 --- a/js/src/gdb/tests/test-jsid.py +++ b/js/src/gdb/tests/test-jsid.py @@ -6,7 +6,7 @@ run_fragment('jsid.simple') assert_pretty('string_id', '$jsid("moon")') assert_pretty('int_id', '$jsid(1729)') -assert_pretty('void_id', 'JSID_VOID') +assert_pretty('void_id', 'jsid::voidId()') assert_pretty('object_id', '$jsid((JSObject *) [object global] delegate)') run_fragment('jsid.handles') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 0caa47353c9b..8731e71d039a 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1469,7 +1469,7 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H case ICStub::SetElem_Dense: case ICStub::SetElem_DenseAdd: { JS_ASSERT(obj->isNative()); - id = JSID_VOID; + id = jsid::voidId(); types::AddTypePropertyId(cx, obj, id, value); break; } diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index d70f534998bf..98364231f589 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2013,7 +2013,7 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type, // Don't use GetAtomId here, we need to watch for SETPROP on // integer properties and bail out. We can't mark the aggregate - // JSID_VOID type property as being in a definite slot. + // jsid::voidId() type property as being in a definite slot. if (setprop->name() == cx->names().prototype || setprop->name() == cx->names().proto || setprop->name() == cx->names().constructor) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 27d57b3609b2..7f9a2719a643 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5522,7 +5522,7 @@ IonBuilder::jsop_initelem_array() if (!initializer->hasFlags(constraints(), types::OBJECT_FLAG_NON_PACKED)) needStub = true; } else if (!initializer->unknownProperties()) { - types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID); + types::HeapTypeSetKey elemTypes = initializer->property(jsid::voidId()); if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) { elemTypes.freeze(constraints()); needStub = true; @@ -7627,7 +7627,7 @@ IonBuilder::jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion convers } // Determine whether a write barrier is required. - if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID)) + if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), jsid::voidId())) store->setNeedsBarrier(); if (elementType != MIRType_None && packed) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 2c649f5c758a..716abb92bd7e 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -213,7 +213,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject); if (!type->unknownProperties()) { - types::HeapTypeSetKey elemTypes = type->property(JSID_VOID); + types::HeapTypeSetKey elemTypes = type->property(jsid::voidId()); for (uint32_t i = 0; i < initLength; i++) { MDefinition *value = callInfo.getArg(i); @@ -468,7 +468,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) // Constraints modeling this concat have not been generated by inference, // so check that type information already reflects possible side effects of // this call. - types::HeapTypeSetKey thisElemTypes = thisType->property(JSID_VOID); + types::HeapTypeSetKey thisElemTypes = thisType->property(jsid::voidId()); types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet(); if (!resTypes->hasType(types::Type::ObjectType(thisType))) @@ -482,7 +482,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (argType->unknownProperties()) return InliningStatus_NotInlined; - types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID); + types::HeapTypeSetKey elemTypes = argType->property(jsid::voidId()); if (!elemTypes.knownSubset(constraints(), thisElemTypes)) return InliningStatus_NotInlined; } @@ -958,7 +958,7 @@ IonBuilder::inlineStringSplit(CallInfo &callInfo) if (retType->unknownProperties()) return InliningStatus_NotInlined; - types::HeapTypeSetKey key = retType->property(JSID_VOID); + types::HeapTypeSetKey key = retType->property(jsid::voidId()); if (!key.maybeTypes()) return InliningStatus_NotInlined; @@ -1178,7 +1178,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base) // - arr is a dense array // - idx < initialized length // Furthermore, note that inlineUnsafePutElements ensures the type of the - // value is reflected in the JSID_VOID property of the array. + // value is reflected in the jsid::voidId() property of the array. MDefinition *obj = callInfo.getArg(base + 0); MDefinition *id = callInfo.getArg(base + 1); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 92cff151ffb4..8b3a95cba007 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2870,7 +2870,7 @@ jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinit if (object->unknownProperties()) return MIRType_None; - types::HeapTypeSetKey elementTypes = object->property(JSID_VOID); + types::HeapTypeSetKey elementTypes = object->property(jsid::voidId()); MIRType type = MIRTypeFromValueType(elementTypes.knownTypeTag(constraints)); if (type == MIRType_None) @@ -2899,7 +2899,7 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints, if (object->unknownProperties() || observed->empty()) return true; - jsid id = name ? NameToId(name) : JSID_VOID; + jsid id = name ? NameToId(name) : jsid::voidId(); types::HeapTypeSetKey property = object->property(id); if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) return true; @@ -3073,7 +3073,7 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name, if (object->unknownProperties()) return observed->addType(types::Type::AnyObjectType(), alloc); - jsid id = name ? NameToId(name) : JSID_VOID; + jsid id = name ? NameToId(name) : jsid::voidId(); types::HeapTypeSetKey property = object->property(id); types::HeapTypeSet *types = property.maybeTypes(); if (!types) @@ -3114,7 +3114,7 @@ TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *c if (object->unknownProperties()) return false; - jsid id = name ? NameToId(name) : JSID_VOID; + jsid id = name ? NameToId(name) : jsid::voidId(); types::HeapTypeSetKey property = object->property(id); if (!property.maybeTypes()) return false; @@ -3224,7 +3224,7 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstrai if (IsTypedArrayClass(object->clasp())) continue; - jsid id = name ? NameToId(name) : JSID_VOID; + jsid id = name ? NameToId(name) : jsid::voidId(); types::HeapTypeSetKey property = object->property(id); if (!TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) { // Either pobj or pvalue needs to be modified to filter out the @@ -3256,7 +3256,7 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstrai if (IsTypedArrayClass(object->clasp())) continue; - jsid id = name ? NameToId(name) : JSID_VOID; + jsid id = name ? NameToId(name) : jsid::voidId(); types::HeapTypeSetKey property = object->property(id); if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) continue; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 722ec4ceb930..061859c3e2e4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3753,7 +3753,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) if (!shape->previous()) { JS_ASSERT(shape->isEmptyShape()); - *idp = JSID_VOID; + *idp = jsid::voidId(); } else { iterobj->setPrivateGCThing(const_cast(shape->previous().get())); *idp = shape->propid(); @@ -3764,7 +3764,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) JS_ASSERT(i <= ida->length); STATIC_ASSUME(i <= ida->length); if (i == 0) { - *idp = JSID_VOID; + *idp = jsid::voidId(); } else { *idp = ida->vector[--i]; iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i)); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 85b3f2b0b194..af8905f17cc5 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1200,7 +1200,7 @@ InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned co if (cx->typeInferenceEnabled() && !type->unknownProperties()) { AutoEnterAnalysis enter(cx); - HeapTypeSet *types = type->getProperty(cx, JSID_VOID); + HeapTypeSet *types = type->getProperty(cx, jsid::voidId()); if (!types) return false; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 326593b23ef6..257480d63526 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -373,7 +373,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin bool JSCompartment::wrapId(JSContext *cx, jsid *idp) { - MOZ_ASSERT(*idp != JSID_VOID, "JSID_VOID is an out-of-band sentinel value"); + MOZ_ASSERT(*idp != jsid::voidId(), "jsid::voidId() is an out-of-band sentinel value"); if (JSID_IS_INT(*idp)) return true; RootedValue value(cx, IdToValue(*idp)); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 44f7edef8dae..839565c99a68 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1255,7 +1255,7 @@ TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags fla return true; } - HeapTypeSetKey objectProperty = property(JSID_EMPTY); + HeapTypeSetKey objectProperty = property(jsid::emptyId()); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1299,7 +1299,7 @@ TypeObject::initialHeap(CompilerConstraintList *constraints) if (!canPreTenure()) return gc::DefaultHeap; - HeapTypeSetKey objectProperty = TypeObjectKey::get(this)->property(JSID_EMPTY); + HeapTypeSetKey objectProperty = TypeObjectKey::get(this)->property(jsid::emptyId()); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1406,7 +1406,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer void TypeObjectKey::watchStateChangeForInlinedCall(CompilerConstraintList *constraints) { - HeapTypeSetKey objectProperty = property(JSID_EMPTY); + HeapTypeSetKey objectProperty = property(jsid::emptyId()); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1417,7 +1417,7 @@ void TypeObjectKey::watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints) { JSObject *templateObject = asTypeObject()->newScript()->templateObject; - HeapTypeSetKey objectProperty = property(JSID_EMPTY); + HeapTypeSetKey objectProperty = property(jsid::emptyId()); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1429,7 +1429,7 @@ void TypeObjectKey::watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints) { void *viewData = asSingleObject()->as().viewData(); - HeapTypeSetKey objectProperty = property(JSID_EMPTY); + HeapTypeSetKey objectProperty = property(jsid::emptyId()); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1444,7 +1444,7 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno return; /* All constraints listening to state changes are on the empty id. */ - HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY); + HeapTypeSet *types = object->maybeGetProperty(jsid::emptyId()); /* Mark as unknown after getting the types, to avoid assertion. */ if (markingUnknown) { @@ -1556,7 +1556,7 @@ TemporaryTypeSet::convertDoubleElements(CompilerConstraintList *constraints) continue; } - HeapTypeSetKey property = type->property(JSID_VOID); + HeapTypeSetKey property = type->property(jsid::voidId()); property.freeze(constraints); // We can't convert to double elements for objects which do not have @@ -2035,7 +2035,7 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj) return true; if (type->unknownProperties()) return true; - HeapTypeSetKey index = type->property(JSID_VOID); + HeapTypeSetKey index = type->property(jsid::voidId()); if (index.configured(constraints) || index.isOwnProperty(constraints)) return true; if (!obj->hasTenuredProto()) @@ -2366,7 +2366,7 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx, obj->setType(objType); if (!objType->unknownProperties()) - objType->addPropertyType(cx, JSID_VOID, elementType); + objType->addPropertyType(cx, jsid::voidId(), elementType); key.proto = objProto; if (!p.add(*arrayTypeTable, key, objType)) { @@ -2716,7 +2716,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap /* * Don't add initial undefined types for properties of global objects - * that are not collated into the JSID_VOID property (see propertySet + * that are not collated into the jsid::voidId() property (see propertySet * comment). */ if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) { @@ -2872,7 +2872,7 @@ TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value) void TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type) { - jsid id = JSID_VOID; + jsid id = jsid::voidId(); if (name) { JSAtom *atom = Atomize(cx, name, strlen(name)); if (!atom) { @@ -2919,7 +2919,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg) return; AutoEnterAnalysis enter(cxArg); - HeapTypeSet *types = maybeGetProperty(JSID_EMPTY); + HeapTypeSet *types = maybeGetProperty(jsid::emptyId()); if (types) { if (JSContext *cx = cxArg->maybeJSContext()) { TypeConstraint *constraint = types->constraintList; diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index ff7c27970b00..69cdaeb663c7 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -330,7 +330,7 @@ public: virtual void newPropertyState(JSContext *cx, TypeSet *source) {} /* - * For constraints attached to the JSID_EMPTY type set on an object, + * For constraints attached to the jsid::emptyId() type set on an object, * indicate a change in one of the object's dynamic property flags or other * state. */ @@ -731,7 +731,7 @@ inline bool isInlinableCall(jsbytecode *pc); /* Type information about a property. */ struct Property { - /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ + /* Identifier for this property, jsid::voidId() for the aggregate integer index property. */ HeapId id; /* Possible types for this property, including types inherited from prototypes. */ @@ -1005,8 +1005,8 @@ struct TypeObject : gc::BarrieredCell private: /* - * Properties of this object. This may contain JSID_VOID, representing the - * types of all integer indexes of the object, and/or JSID_EMPTY, holding + * Properties of this object. This may contain jsid::voidId(), representing the + * types of all integer indexes of the object, and/or jsid::emptyId(), holding * constraints listening to changes to the object's state. * * The type sets in the properties of a type object describe the possible @@ -1381,7 +1381,7 @@ class HeapTypeSetKey public: HeapTypeSetKey() - : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr) + : object_(nullptr), id_(jsid::emptyId()), maybeTypes_(nullptr) {} TypeObjectKey *object() const { return object_; } diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index ab4186e83ef9..dc68d2c847ff 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -170,7 +170,7 @@ IdToTypeId(jsid id) * negative integers. */ if (JSID_IS_INT(id)) - return JSID_VOID; + return jsid::voidId(); /* * Check for numeric strings, as in js_StringIsIndex, but allow negative @@ -184,12 +184,12 @@ IdToTypeId(jsid id) if (!JS7_ISDEC(cp[i])) return id; } - return JSID_VOID; + return jsid::voidId(); } return id; } - return JSID_VOID; + return jsid::voidId(); } const char * TypeIdStringImpl(jsid id); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 674d4ea03c17..365d7016ea2c 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -153,7 +153,7 @@ JSObject::setShouldConvertDoubleElements() inline bool JSObject::setDenseElementIfHasType(uint32_t index, const js::Value &val) { - if (!js::types::HasTypePropertyId(this, JSID_VOID, val)) + if (!js::types::HasTypePropertyId(this, jsid::voidId(), val)) return false; setDenseElementMaybeConvertDouble(index, val); return true; @@ -167,7 +167,7 @@ JSObject::setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, // of the previous element. js::types::Type thisType = js::types::GetValueType(val); if (index == 0 || js::types::GetValueType(elements[index - 1]) != thisType) - js::types::AddTypePropertyId(cx, this, JSID_VOID, thisType); + js::types::AddTypePropertyId(cx, this, jsid::voidId(), thisType); setDenseElementMaybeConvertDouble(index, val); } @@ -176,7 +176,7 @@ JSObject::initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, const js::Value &val) { JS_ASSERT(!shouldConvertDoubleElements()); - js::types::AddTypePropertyId(cx, this, JSID_VOID, val); + js::types::AddTypePropertyId(cx, this, jsid::voidId(), val); initDenseElement(index, val); } diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 1b1582516c2b..1b096bae0151 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -226,7 +226,7 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver, bool BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); JS_ASSERT(props.length() == 0); if (!getOwnPropertyNames(cx, proxy, props)) @@ -255,7 +255,7 @@ BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) bool BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); AutoIdVector props(cx); if ((flags & JSITER_OWNONLY) @@ -318,7 +318,7 @@ BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl im bool BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedValue val(cx, ObjectValue(*proxy.get())); js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, JSDVG_SEARCH_STACK, val, NullPtr()); @@ -376,7 +376,7 @@ bool BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, HandleObject result) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedId id(cx); RootedValue value(cx); @@ -451,7 +451,7 @@ bool DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props); } @@ -468,7 +468,7 @@ bool DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, 0, &props); @@ -477,7 +477,7 @@ DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, bool DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedValue target(cx, proxy->as().private_()); return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval()); } @@ -485,7 +485,7 @@ DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args bool DirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedValue target(cx, proxy->as().private_()); return InvokeConstructor(cx, target, args.length(), args.array(), args.rval().address()); } @@ -507,7 +507,7 @@ bool DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); bool b; RootedObject target(cx, proxy->as().target()); if (!JS_HasInstance(cx, target, v, &b)) @@ -541,7 +541,7 @@ DirectProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue, const char * DirectProxyHandler::className(JSContext *cx, HandleObject proxy) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject target(cx, proxy->as().target()); return JSObject::className(cx, target); } @@ -550,7 +550,7 @@ JSString * DirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject target(cx, proxy->as().target()); return fun_toStringHelper(cx, target, indent); } @@ -620,7 +620,7 @@ DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver bool DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, JSITER_OWNONLY, &props); } @@ -629,7 +629,7 @@ bool DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. RootedObject target(cx, proxy->as().target()); return GetIterator(cx, target, flags, vp); @@ -1046,7 +1046,7 @@ ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigne bool ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject ccHolder(cx, &proxy->as().extra(0).toObject()); JS_ASSERT(ccHolder->getClass() == &CallConstructHolder); RootedValue call(cx, ccHolder->getReservedSlot(0)); @@ -1057,7 +1057,7 @@ ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const Call bool ScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); RootedObject ccHolder(cx, &proxy->as().extra(0).toObject()); JS_ASSERT(ccHolder->getClass() == &CallConstructHolder); RootedValue construct(cx, ccHolder->getReservedSlot(1)); @@ -1076,7 +1076,7 @@ ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, N JSString * ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) { - assertEnteredPolicy(cx, proxy, JSID_VOID); + assertEnteredPolicy(cx, proxy, jsid::voidId()); if (!proxy->isCallable()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index e463388fd8d7..d9ebaceb1d36 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -130,7 +130,7 @@ class JS_FRIEND_API(BaseProxyHandler) * * enter() allows the policy to specify whether the caller may perform |act| * on the proxy's |id| property. In the case when |act| is CALL, |id| is - * generally JSID_VOID. + * generally jsid::voidId(). * * The |act| parameter to enter() specifies the action being performed. * If |bp| is false, the trap suggests that the caller throw (though it diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index ed23898292ba..4abf8b3f199c 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4996,7 +4996,7 @@ DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp) ac.construct(cx, obj); RootedId id(cx); for (size_t i = 0; i < n; i++) { - if (!rewrappedIds.append(JSID_VOID) || !rewrappedDescs.append()) + if (!rewrappedIds.append(jsid::voidId()) || !rewrappedDescs.append()) return false; id = ids[i]; if (!unwrappedDescs[i].wrapInto(cx, obj, id, &rewrappedIds[i], &rewrappedDescs[i])) diff --git a/js/src/vm/Id.cpp b/js/src/vm/Id.cpp index 96360d098030..56255cc2bb3e 100644 --- a/js/src/vm/Id.cpp +++ b/js/src/vm/Id.cpp @@ -7,11 +7,9 @@ #include "js/Id.h" #include "js/RootingAPI.h" -const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) }; -const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) }; +static MOZ_CONSTEXPR_VAR jsid voidIdValue = jsid::voidId(); +static MOZ_CONSTEXPR_VAR jsid emptyIdValue = jsid::emptyId(); -static const jsid voidIdValue = JSID_VOID; -static const jsid emptyIdValue = JSID_EMPTY; const JS::HandleId JSID_VOIDHANDLE = JS::HandleId::fromMarkedLocation(&voidIdValue); const JS::HandleId JSID_EMPTYHANDLE = JS::HandleId::fromMarkedLocation(&emptyIdValue); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index f95670834921..9453be68019c 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -688,7 +688,7 @@ js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent, js::AutoIdVector ids(cx); { for (unsigned i = 0; i <= shape->slot(); i++) { - if (!ids.append(JSID_VOID)) + if (!ids.append(jsid::voidId())) return nullptr; } Shape *nshape = shape; diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 1599a18d7314..56e3b21dc272 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1594,7 +1594,7 @@ Shape::Shape(const StackShape &other, uint32_t nfixed) inline Shape::Shape(UnownedBaseShape *base, uint32_t nfixed) : base_(base), - propid_(JSID_EMPTY), + propid_(jsid::emptyId()), slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)), attrs(JSPROP_SHARED), flags(0), diff --git a/js/src/vm/String.h b/js/src/vm/String.h index ea4b7ca43638..651c7635af90 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -957,7 +957,7 @@ class StaticStrings * - uint32_t indexes, * - PropertyName strings which don't encode uint32_t indexes, and * - jsspecial special properties (non-ES5 properties like object-valued - * jsids, JSID_EMPTY, JSID_VOID, and maybe in the future Harmony-proposed + * jsids, EmptyId(), VoidId(), and maybe in the future Harmony-proposed * private names). */ class PropertyName : public JSAtom diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 171cf9238b19..4d8cef1c8fc5 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1456,7 +1456,7 @@ JSStructuredCloneReader::readId(jsid *idp) return true; } if (tag == SCTAG_NULL) { - *idp = JSID_VOID; + *idp = jsid::voidId(); return true; } JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index 6e9e837708d4..8a3f35b2c820 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -20,7 +20,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, JSContext* cx /* = GetDefaultJSContext() */, HandleObject obj /* = nullptr */, HandleObject funobj /* = nullptr */, - HandleId name /* = JSID_VOID */, + HandleId name /* = jsid::voidId() */, unsigned argc /* = NO_ARGS */, jsval *argv /* = nullptr */, jsval *rval /* = nullptr */) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 8a8d8391a7f5..14cb4d84cda4 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2908,7 +2908,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) mJSContextStack(new XPCJSContextStack()), mCallContext(nullptr), mAutoRoots(nullptr), - mResolveName(JSID_VOID), + mResolveName(jsid::voidId()), mResolvingWrapper(nullptr), mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)), mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)), @@ -2933,7 +2933,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) DOM_InitInterfaces(); // these jsids filled in later when we have a JSContext to work with. - mStrIDs[0] = JSID_VOID; + mStrIDs[0] = jsid::voidId(); MOZ_ASSERT(Runtime()); JSRuntime* runtime = Runtime(); @@ -3134,7 +3134,7 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx) for (unsigned i = 0; i < IDX_TOTAL_COUNT; i++) { str = JS_InternString(cx, mStrings[i]); if (!str) { - mStrIDs[0] = JSID_VOID; + mStrIDs[0] = jsid::voidId(); return false; } mStrIDs[i] = INTERNED_STRING_TO_JSID(cx, str); diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 67aa18a22b5f..8f785b2115e6 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -209,7 +209,7 @@ GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp MOZ_ASSERT(JS_ObjectIsFunction(cx, funobj), "JSNative callee should be Function object"); RootedString str(cx, JS_GetFunctionId(JS_GetObjectFunction(funobj))); - RootedId methodId(cx, str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID); + RootedId methodId(cx, str ? INTERNED_STRING_TO_JSID(cx, str) : jsid::voidId()); GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep); *memberIdp = methodId; } @@ -353,7 +353,7 @@ void xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, unsigned paramnum, const char *ifaceName, const char *memberName) { - ThrowBadArg(cx, rv, ifaceName, JSID_VOID, memberName, paramnum); + ThrowBadArg(cx, rv, ifaceName, jsid::voidId(), memberName, paramnum); } void diff --git a/js/xpconnect/src/dictionary_helper_gen.py b/js/xpconnect/src/dictionary_helper_gen.py index 40fea45456f3..8d0aa180ec66 100644 --- a/js/xpconnect/src/dictionary_helper_gen.py +++ b/js/xpconnect/src/dictionary_helper_gen.py @@ -196,7 +196,7 @@ def print_cpp_file(fd, conf): fd.write("\nusing namespace mozilla::idl;\n\n") for a in attrnames: - fd.write("static jsid %s = JSID_VOID;\n"% get_jsid(a)) + fd.write("static jsid %s = jsid::voidId();\n"% get_jsid(a)) fd.write("\n" "static bool\n" diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index fc8264b2fd33..4f7fd0272e1b 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3448,7 +3448,7 @@ public: CreateObjectInOptions(JSContext *cx = xpc_GetSafeJSContext(), JSObject* options = nullptr) : OptionsBase(cx, options) - , defineAs(cx, JSID_VOID) + , defineAs(cx, jsid::voidId()) { } virtual bool Parse() { return ParseId("defineAs", &defineAs); }; @@ -3461,7 +3461,7 @@ public: ExportOptions(JSContext *cx = xpc_GetSafeJSContext(), JSObject* options = nullptr) : OptionsBase(cx, options) - , defineAs(cx, JSID_VOID) + , defineAs(cx, jsid::voidId()) { } virtual bool Parse() { return ParseId("defineAs", &defineAs); }; diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index f84c9bb13fdc..b61d6bd5efaa 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -217,12 +217,12 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, j RootedObject wrapper(cx, wrapperArg); RootedObject obj(cx, Wrapper::wrappedObject(wrapper)); - // Enumerate-like operations pass JSID_VOID to |enter|, since there isn't + // Enumerate-like operations pass jsid::voidId() to |enter|, since there isn't // another sane value to pass. For XOWs, we generally want to deny such // operations but fail silently (see CrossOriginAccessiblePropertiesOnly:: // deny). We could just fall through here and rely on the fact that none - // of the whitelisted properties below will match JSID_VOID, but EIBTI. - if (id == JSID_VOID) + // of the whitelisted properties below will match jsid::voidId(), but EIBTI. + if (id == jsid::voidId()) return false; const char *name; @@ -315,7 +315,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wr return false; } - if (id == JSID_VOID) + if (id == jsid::voidId()) return true; RootedValue exposedProps(cx); diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp index e4b52e152fa2..4c8bdcf58158 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp @@ -178,7 +178,7 @@ ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper, // COWs fail silently for GETs, and that also happens to be the only case // where we might want to redirect the lookup to the home prototype chain. *bp = (act == Wrapper::GET); - if (!*bp || id == JSID_VOID) + if (!*bp || id == jsid::voidId()) return false; // Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index e7755b5f1c8f..f27ad192f561 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -87,7 +87,7 @@ bool FilteringWrapper::getOwnPropertyNames(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return Base::getOwnPropertyNames(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -97,7 +97,7 @@ bool FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return Base::enumerate(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -107,7 +107,7 @@ bool FilteringWrapper::keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return Base::keys(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -117,7 +117,7 @@ bool FilteringWrapper::iterate(JSContext *cx, HandleObject wrapper, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); // We refuse to trigger the iterator hook across chrome wrappers because // we don't know how to censor custom iterator objects. Instead we trigger // the default proxy iterate trap, which will ask enumerate() for the list diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 2610670ab612..9bbdd6b96fa5 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1648,7 +1648,7 @@ bool XrayWrapper::getOwnPropertyNames(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props); } @@ -1675,7 +1675,7 @@ bool XrayWrapper::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); if (!AccessCheck::wrapperSubsumes(wrapper)) { JS_ReportError(cx, "Not allowed to enumerate cross origin objects"); return false; @@ -1768,7 +1768,7 @@ template bool XrayWrapper::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return Traits::call(cx, wrapper, args, Base::singleton); } @@ -1776,7 +1776,7 @@ template bool XrayWrapper::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) { - assertEnteredPolicy(cx, wrapper, JSID_VOID); + assertEnteredPolicy(cx, wrapper, jsid::voidId()); return Traits::construct(cx, wrapper, args, Base::singleton); } diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 90d0dfe2543b..db2de8d60bec 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -785,7 +785,7 @@ struct ClearJSHolder : TraceCallbacks virtual void Trace(JS::Heap* aPtr, const char*, void*) const MOZ_OVERRIDE { - *aPtr = JSID_VOID; + *aPtr = jsid::voidId(); } virtual void Trace(JS::Heap* aPtr, const char*, void*) const MOZ_OVERRIDE From 82be7c91ecb65390906436a49705a907c25cf34b Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Mon, 16 Dec 2013 13:15:37 -0800 Subject: [PATCH 23/34] Bug 950736 - Part 2: Make build failures of codegen.pp fatal; r=glandium --HG-- extra : rebase_source : a2a815dd0342a8fdf2dacd7d643d4504e2f29eb5 extra : amend_source : 474af6a65c7ad26cdfc7d6eb26caf0b42fe741c3 --- config/baseconfig.mk | 4 ++-- dom/bindings/Makefile.in | 7 +++---- dom/bindings/mozwebidlcodegen/__init__.py | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/config/baseconfig.mk b/config/baseconfig.mk index b7adc7aa8c5b..78e50bbfbd40 100644 --- a/config/baseconfig.mk +++ b/config/baseconfig.mk @@ -29,7 +29,7 @@ endif endif # WINNT ifdef .PYMAKE -include_deps = $(eval -includedeps $(1)) +include_deps = $(eval $(if $(2),,-)includedeps $(1)) else -include_deps = $(eval -include $(1)) +include_deps = $(eval $(if $(2),,-)include $(1)) endif diff --git a/dom/bindings/Makefile.in b/dom/bindings/Makefile.in index 3f008078fd5c..f9da051c61f0 100644 --- a/dom/bindings/Makefile.in +++ b/dom/bindings/Makefile.in @@ -58,11 +58,10 @@ codegen_dependencies := \ $(GLOBAL_DEPS) \ $(NULL) -$(call include_deps,codegen.pp) +# The 1 is to make codegen.pp not optional. +$(call include_deps,codegen.pp,1) -codegen.pp: codegen.done - -codegen.done: $(codegen_dependencies) +codegen.pp: $(codegen_dependencies) $(call py_action,webidl,$(srcdir)) @$(TOUCH) $@ diff --git a/dom/bindings/mozwebidlcodegen/__init__.py b/dom/bindings/mozwebidlcodegen/__init__.py index 34b1f1bf8cbf..fdbb49164c94 100644 --- a/dom/bindings/mozwebidlcodegen/__init__.py +++ b/dom/bindings/mozwebidlcodegen/__init__.py @@ -546,7 +546,7 @@ def create_build_system_manager(topsrcdir, topobjdir, dist_dir): cache_dir=cache_dir, # The make rules include a codegen.pp file containing dependencies. make_deps_path=os.path.join(obj_dir, 'codegen.pp'), - make_deps_target='codegen.done', + make_deps_target='codegen.pp', ) From da11ad371a615ba84dc8de39c75051029476cd17 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Mon, 16 Dec 2013 17:01:55 -0700 Subject: [PATCH 24/34] Bug 944440 - Force test_no_arr_points.html to work on Android x86 emu; r=jgilbert --- .../test/webgl/non-conf-tests/test_no_arr_points.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/content/canvas/test/webgl/non-conf-tests/test_no_arr_points.html b/content/canvas/test/webgl/non-conf-tests/test_no_arr_points.html index a49ce5b0a20c..765d4287f674 100644 --- a/content/canvas/test/webgl/non-conf-tests/test_no_arr_points.html +++ b/content/canvas/test/webgl/non-conf-tests/test_no_arr_points.html @@ -116,11 +116,19 @@ void main(void) { checkGLError(ok, info); var elemTestFunc = todo; // We fail on most implementations. + var checkGLTestFunc = todo; if (DriverInfo.getDriver() == DriverInfo.DRIVER.ANGLE || DriverInfo.getOS() == DriverInfo.OS.ANDROID) { // ANGLE and Android slaves seem to work fine. elemTestFunc = ok; + checkGLTestFunc = ok; + } + if (DriverInfo.getDriver() == DriverInfo.DRIVER.ANDROID_X86_EMULATOR) + { + // ...but the Android 4.2 x86 emulator environment is different + elemTestFunc = todo; + checkGLTestFunc = ok; } // Now for drawElements: @@ -139,7 +147,7 @@ void main(void) { gl.drawElements(gl.POINTS, 1, indexType, 2*indexStride); elemTestFunc(!isScreenBlack(), '[' + info + '] drawElements[huge offset] should color pixels.'); - checkGLError(elemTestFunc, info); + checkGLError(checkGLTestFunc, info); } // Begin drawing From df8b1437b6c2111e0a6c9c774aaaafefbe155680 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Dec 2013 16:33:07 -0800 Subject: [PATCH 25/34] Backed out 6 changesets (bug 877115) for mochitest-1 and reftest orange on this CLOSED TREE Backed out changeset 65ad9d8860d6 (bug 877115) Backed out changeset bf8095c168fb (bug 877115) Backed out changeset 290ad5863615 (bug 877115) Backed out changeset 4488ec28910e (bug 877115) Backed out changeset 45f8859c6fd6 (bug 877115) Backed out changeset 111cc426fa9e (bug 877115) --- gfx/gl/GLBlitHelper.cpp | 32 +++++++++++++------------- gfx/gl/GLBlitHelper.h | 33 ++++++++++++++------------- gfx/gl/GLContext.cpp | 22 ++++++++---------- gfx/gl/GLContext.h | 16 ++++++------- gfx/gl/GLContextProviderCGL.mm | 6 ++--- gfx/gl/GLContextProviderEGL.cpp | 6 ++--- gfx/gl/GLContextProviderWGL.cpp | 6 ++--- gfx/gl/GLScreenBuffer.cpp | 22 +++++++++--------- gfx/gl/GLScreenBuffer.h | 26 ++++++++++----------- gfx/gl/GLUploadHelpers.h | 10 ++++---- gfx/gl/SharedSurface.h | 8 +++---- gfx/gl/SharedSurfaceANGLE.cpp | 4 ++-- gfx/gl/SharedSurfaceANGLE.h | 6 ++--- gfx/gl/SharedSurfaceEGL.cpp | 24 ++++++++----------- gfx/gl/SharedSurfaceEGL.h | 16 ++++++------- gfx/gl/SharedSurfaceGL.cpp | 33 ++++++++++++--------------- gfx/gl/SharedSurfaceGL.h | 23 ++++++++----------- gfx/gl/SharedSurfaceGralloc.cpp | 6 ++--- gfx/gl/SharedSurfaceGralloc.h | 6 ++--- gfx/gl/SharedSurfaceIO.cpp | 6 ++--- gfx/gl/SharedSurfaceIO.h | 4 ++-- gfx/gl/SurfaceFactory.cpp | 2 +- gfx/gl/SurfaceFactory.h | 4 ++-- gfx/gl/SurfaceStream.cpp | 10 ++++---- gfx/gl/SurfaceStream.h | 14 ++++++------ gfx/layers/CopyableCanvasLayer.cpp | 12 ++-------- gfx/layers/d3d10/CanvasLayerD3D10.cpp | 24 +++++++++++-------- gfx/layers/d3d9/CanvasLayerD3D9.cpp | 24 +++++++++++-------- gfx/layers/opengl/TextureHostOGL.cpp | 8 +++---- 29 files changed, 199 insertions(+), 214 deletions(-) diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index 3f54e9c335c4..4dcc90867500 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -14,7 +14,7 @@ namespace gl { static void RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, - GLenum aInternalFormat, const gfx::IntSize& aSize) + GLenum aInternalFormat, const gfxIntSize& aSize) { if (aSamples) { aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, @@ -31,7 +31,7 @@ RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfx::IntSize& aSize) + GLenum aType, const gfxIntSize& aSize) { GLuint tex = 0; aGL->fGenTextures(1, &tex); @@ -57,7 +57,7 @@ CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize) + const gfxIntSize& aSize) { MOZ_ASSERT(aFormats.color_texInternalFormat); MOZ_ASSERT(aFormats.color_texFormat); @@ -73,7 +73,7 @@ CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfx::IntSize& aSize) + const gfxIntSize& aSize) { GLuint rb = 0; aGL->fGenRenderbuffers(1, &rb); @@ -87,7 +87,7 @@ CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, void CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize, bool aMultisample, + const gfxIntSize& aSize, bool aMultisample, GLuint* aColorMSRB, GLuint* aDepthRB, GLuint* aStencilRB) { @@ -351,7 +351,7 @@ GLBlitHelper::InitTexQuadProgram(GLenum target) } bool -GLBlitHelper::UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize) +GLBlitHelper::UseTexQuadProgram(GLenum target, const gfxIntSize& srcSize) { if (!InitTexQuadProgram(target)) { return false; @@ -397,8 +397,8 @@ GLBlitHelper::DeleteTexBlitProgram() void GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize) + const gfxIntSize& srcSize, + const gfxIntSize& destSize) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); @@ -419,8 +419,8 @@ GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, void GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const gfxIntSize& srcSize, + const gfxIntSize& destSize, const GLFormats& srcFormats) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); @@ -443,8 +443,8 @@ GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const gfxIntSize& srcSize, + const gfxIntSize& destSize, GLenum srcTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); @@ -563,8 +563,8 @@ GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, void GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const gfxIntSize& srcSize, + const gfxIntSize& destSize, GLenum destTarget) { MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); @@ -590,8 +590,8 @@ GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, void GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const gfxIntSize& srcSize, + const gfxIntSize& destSize, GLenum srcTarget, GLenum destTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h index 987c4fdb586a..f46565cc429b 100644 --- a/gfx/gl/GLBlitHelper.h +++ b/gfx/gl/GLBlitHelper.h @@ -11,7 +11,8 @@ #include "GLConsts.h" #include "nsSize.h" #include "mozilla/Attributes.h" -#include "mozilla/gfx/Point.h" + +struct nsIntSize; namespace mozilla { namespace gl { @@ -25,7 +26,7 @@ class GLContext; * See mozilla::gl::CreateTexture. */ GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize); + const gfxIntSize& aSize); /** * Helper function that creates a 2D texture aSize.width x aSize.height with @@ -38,7 +39,7 @@ GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, * GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE */ GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfx::IntSize& aSize); + GLenum aType, const gfxIntSize& aSize); /** * Helper function to create, potentially, multisample render buffers suitable @@ -46,7 +47,7 @@ GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, * storage specified by aFormat. returns GL render buffer object id. */ GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfx::IntSize& aSize); + const gfxIntSize& aSize); /** * Helper function to create, potentially, multisample render buffers suitable @@ -55,7 +56,7 @@ GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, * aColorMSRB, aDepthRB, and aStencilRB */ void CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize, bool aMultisample, + const gfxIntSize& aSize, bool aMultisample, GLuint* aColorMSRB, GLuint* aDepthRB, GLuint* aStencilRB); @@ -76,7 +77,7 @@ class GLBlitHelper MOZ_FINAL void UseBlitProgram(); void SetBlitFramebufferForDestTexture(GLuint aTexture); - bool UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize); + bool UseTexQuadProgram(GLenum target, const nsIntSize& srcSize); bool InitTexQuadProgram(GLenum target = LOCAL_GL_TEXTURE_2D); void DeleteTexBlitProgram(); @@ -89,23 +90,23 @@ public: // then you'll need the framebuffer_blit extensions to use // the first BlitFramebufferToFramebuffer. void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize); + const nsIntSize& srcSize, + const nsIntSize& destSize); void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const nsIntSize& srcSize, + const nsIntSize& destSize, const GLFormats& srcFormats); void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const nsIntSize& srcSize, + const nsIntSize& destSize, GLenum srcTarget = LOCAL_GL_TEXTURE_2D); void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const nsIntSize& srcSize, + const nsIntSize& destSize, GLenum destTarget = LOCAL_GL_TEXTURE_2D); void BlitTextureToTexture(GLuint srcTex, GLuint destTex, - const gfx::IntSize& srcSize, - const gfx::IntSize& destSize, + const nsIntSize& srcSize, + const nsIntSize& destSize, GLenum srcTarget = LOCAL_GL_TEXTURE_2D, GLenum destTarget = LOCAL_GL_TEXTURE_2D); }; diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 72b883573e53..35203f814eaf 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -1495,7 +1495,7 @@ GLContext::PublishFrame() { MOZ_ASSERT(mScreen); - if (!mScreen->PublishFrame(ThebesIntSize(OffscreenSize()))) + if (!mScreen->PublishFrame(OffscreenSize())) return false; return true; @@ -2157,19 +2157,19 @@ GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) if (DebugMode()) { NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); } - SurfaceFormat readFormatGFX; + ImageFormat readFormatGFX; switch (readFormat) { case LOCAL_GL_RGBA: case LOCAL_GL_BGRA: { - readFormatGFX = hasAlpha ? FORMAT_B8G8R8A8 - : FORMAT_B8G8R8X8; + readFormatGFX = hasAlpha ? gfxImageFormatARGB32 + : gfxImageFormatRGB24; break; } case LOCAL_GL_RGB: { MOZ_ASSERT(readPixelSize == 2); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); - readFormatGFX = FORMAT_R5G6B5; + readFormatGFX = gfxImageFormatRGB16_565; break; } default: { @@ -2198,9 +2198,7 @@ GLContext::ReadPixelsIntoImageSurface(gfxImageSurface* dest) } } - tempSurf = new gfxImageSurface(dest->GetSize(), - gfxImageFormat(readFormatGFX), - false); + tempSurf = new gfxImageSurface(dest->GetSize(), readFormatGFX, false); readSurf = tempSurf; } else { readPixelSize = destPixelSize; @@ -2459,7 +2457,7 @@ GLContext::GuaranteeResolve() fFinish(); } -const gfx::IntSize& +const gfxIntSize& GLContext::OffscreenSize() const { MOZ_ASSERT(IsOffscreen()); @@ -2467,7 +2465,7 @@ GLContext::OffscreenSize() const } bool -GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps) +GLContext::CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps) { GLScreenBuffer* newScreen = GLScreenBuffer::Create(this, size, caps); if (!newScreen) @@ -2490,7 +2488,7 @@ GLContext::CreateScreenBufferImpl(const IntSize& size, const SurfaceCaps& caps) } bool -GLContext::ResizeScreenBuffer(const IntSize& size) +GLContext::ResizeScreenBuffer(const gfxIntSize& size) { if (!IsOffscreenSizeAllowed(size)) return false; @@ -2533,7 +2531,7 @@ GLContext::EmptyTexGarbageBin() } bool -GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const { +GLContext::IsOffscreenSizeAllowed(const gfxIntSize& aSize) const { int32_t biggerDimension = std::max(aSize.width, aSize.height); int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize); return biggerDimension <= maxAllowed; diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 6d1c5635afbc..4ebfe1bb3395 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -41,7 +41,6 @@ #include "GLContextSymbols.h" #include "mozilla/GenericRefCounted.h" #include "mozilla/Scoped.h" -#include "gfx2DGlue.h" #ifdef DEBUG #define MOZ_ENABLE_GL_TRACKING 1 @@ -2378,6 +2377,7 @@ protected: typedef class gfx::SharedSurface SharedSurface; typedef gfx::SharedSurfaceType SharedSurfaceType; + typedef gfxImageFormat ImageFormat; typedef gfx::SurfaceFormat SurfaceFormat; public: @@ -2493,7 +2493,7 @@ public: * * Only valid if IsOffscreen() returns true. */ - virtual bool ResizeOffscreen(const gfx::IntSize& size) { + virtual bool ResizeOffscreen(const gfxIntSize& size) { return ResizeScreenBuffer(size); } @@ -2502,7 +2502,7 @@ public: * * Only valid if IsOffscreen() returns true. */ - const gfx::IntSize& OffscreenSize() const; + const gfxIntSize& OffscreenSize() const; void BindFB(GLuint fb) { fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); @@ -2714,7 +2714,7 @@ public: return thisShared == otherShared; } - bool InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps) { + bool InitOffscreen(const gfxIntSize& size, const SurfaceCaps& caps) { if (!CreateScreenBuffer(size, caps)) return false; @@ -2735,7 +2735,7 @@ public: protected: // Note that it does -not- clear the resized buffers. - bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps) { + bool CreateScreenBuffer(const gfxIntSize& size, const SurfaceCaps& caps) { if (!IsOffscreenSizeAllowed(size)) return false; @@ -2757,11 +2757,11 @@ protected: return false; } - bool CreateScreenBufferImpl(const gfx::IntSize& size, + bool CreateScreenBufferImpl(const gfxIntSize& size, const SurfaceCaps& caps); public: - bool ResizeScreenBuffer(const gfx::IntSize& size); + bool ResizeScreenBuffer(const gfxIntSize& size); protected: SurfaceCaps mCaps; @@ -2861,7 +2861,7 @@ public: void EmptyTexGarbageBin(); - bool IsOffscreenSizeAllowed(const gfx::IntSize& aSize) const; + bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const; protected: GLuint mReadTextureImagePrograms[4]; diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index dd4d4d121bdd..e90392bf2e3c 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -188,16 +188,16 @@ public: return true; } - bool ResizeOffscreen(const gfx::IntSize& aNewSize); + bool ResizeOffscreen(const gfxIntSize& aNewSize); NSOpenGLContext *mContext; GLuint mTempTextureName; }; bool -GLContextCGL::ResizeOffscreen(const gfx::IntSize& aNewSize) +GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(ThebesIntSize(aNewSize)); + return ResizeScreenBuffer(aNewSize); } static GLContextCGL * diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 1fbda44c4483..570e7363f4ce 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -539,7 +539,7 @@ public: bool BindTex2DOffscreen(GLContext *aOffscreen); void UnbindTex2DOffscreen(GLContext *aOffscreen); - bool ResizeOffscreen(const gfx::IntSize& aNewSize); + bool ResizeOffscreen(const gfxIntSize& aNewSize); void BindOffscreenFramebuffer(); static already_AddRefed @@ -613,9 +613,9 @@ protected: }; bool -GLContextEGL::ResizeOffscreen(const gfx::IntSize& aNewSize) +GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(ThebesIntSize(aNewSize)); + return ResizeScreenBuffer(aNewSize); } static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index 130aeffe5ad7..b1715338563c 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -378,7 +378,7 @@ public: } } - bool ResizeOffscreen(const gfx::IntSize& aNewSize); + bool ResizeOffscreen(const gfxIntSize& aNewSize); HGLRC Context() { return mContext; } @@ -428,9 +428,9 @@ IsValidSizeForFormat(HDC hDC, int format, } bool -GLContextWGL::ResizeOffscreen(const gfx::IntSize& aNewSize) +GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize) { - return ResizeScreenBuffer(ThebesIntSize(aNewSize)); + return ResizeScreenBuffer(aNewSize); } static GLContextWGL * diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index 45bd0bd9ecbd..c94a7cc90c6a 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -27,7 +27,7 @@ namespace gl { GLScreenBuffer* GLScreenBuffer::Create(GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, const SurfaceCaps& caps) { if (caps.antialias && @@ -347,8 +347,8 @@ GLScreenBuffer::AssureBlitted() BindReadFB_Internal(drawFB); BindDrawFB_Internal(readFB); - const gfx::IntSize& srcSize = mDraw->Size(); - const gfx::IntSize& destSize = mRead->Size(); + const gfxIntSize& srcSize = mDraw->Size(); + const gfxIntSize& destSize = mRead->Size(); mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, 0, 0, destSize.width, destSize.height, @@ -381,7 +381,7 @@ GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamTyp } void -GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size) +GLScreenBuffer::Attach(SharedSurface* surface, const gfxIntSize& size) { ScopedBindFramebuffer autoFB(mGL); @@ -419,7 +419,7 @@ GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size) } bool -GLScreenBuffer::Swap(const gfx::IntSize& size) +GLScreenBuffer::Swap(const gfxIntSize& size) { SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size); if (!nextSurf) { @@ -438,7 +438,7 @@ GLScreenBuffer::Swap(const gfx::IntSize& size) } bool -GLScreenBuffer::PublishFrame(const gfx::IntSize& size) +GLScreenBuffer::PublishFrame(const gfxIntSize& size) { AssureBlitted(); @@ -447,7 +447,7 @@ GLScreenBuffer::PublishFrame(const gfx::IntSize& size) } bool -GLScreenBuffer::Resize(const gfx::IntSize& size) +GLScreenBuffer::Resize(const gfxIntSize& size) { SharedSurface* surface = mStream->Resize(mFactory, size); if (!surface) @@ -458,7 +458,7 @@ GLScreenBuffer::Resize(const gfx::IntSize& size) } DrawBuffer* -GLScreenBuffer::CreateDraw(const gfx::IntSize& size) +GLScreenBuffer::CreateDraw(const gfxIntSize& size) { GLContext* gl = mFactory->GL(); const GLFormats& formats = mFactory->Formats(); @@ -482,7 +482,7 @@ void GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) { MOZ_ASSERT(src && dest); - MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size()); + MOZ_ASSERT(dest->GetSize() == src->Size()); MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageFormatARGB32 : gfxImageFormatRGB24)); @@ -514,7 +514,7 @@ DrawBuffer* DrawBuffer::Create(GLContext* const gl, const SurfaceCaps& caps, const GLFormats& formats, - const gfx::IntSize& size) + const gfxIntSize& size) { if (!caps.color) { MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil); @@ -681,7 +681,7 @@ ReadBuffer::Attach(SharedSurface_GL* surf) mSurf = surf; } -const gfx::IntSize& +const gfxIntSize& ReadBuffer::Size() const { return mSurf->Size(); diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 2c37f1e7094c..593a48787450 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -18,7 +18,7 @@ #include "SurfaceTypes.h" #include "GLContextTypes.h" #include "GLDefs.h" -#include "mozilla/gfx/Point.h" +#include "gfxPoint.h" // Forwards: class gfxImageSurface; @@ -48,18 +48,18 @@ public: static DrawBuffer* Create(GLContext* const gl, const SurfaceCaps& caps, const GLFormats& formats, - const gfx::IntSize& size); + const gfxIntSize& size); protected: GLContext* const mGL; - const gfx::IntSize mSize; + const gfxIntSize mSize; const GLuint mFB; const GLuint mColorMSRB; const GLuint mDepthRB; const GLuint mStencilRB; DrawBuffer(GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, GLuint fb, GLuint colorMSRB, GLuint depthRB, @@ -75,7 +75,7 @@ protected: public: virtual ~DrawBuffer(); - const gfx::IntSize& Size() const { + const gfxIntSize& Size() const { return mSize; } @@ -124,7 +124,7 @@ public: // Cannot attach a surf of a different AttachType or Size than before. void Attach(SharedSurface_GL* surf); - const gfx::IntSize& Size() const; + const gfxIntSize& Size() const; GLuint FB() const { return mFB; @@ -148,7 +148,7 @@ protected: public: // Infallible. static GLScreenBuffer* Create(GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, const SurfaceCaps& caps); protected: @@ -231,7 +231,7 @@ public: void DeletingFB(GLuint fb); - const gfx::IntSize& Size() const { + const gfxIntSize& Size() const { MOZ_ASSERT(mRead); MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); return mRead->Size(); @@ -270,19 +270,19 @@ public: protected: // Returns false on error or inability to resize. - bool Swap(const gfx::IntSize& size); + bool Swap(const gfxIntSize& size); public: - bool PublishFrame(const gfx::IntSize& size); + bool PublishFrame(const gfxIntSize& size); - bool Resize(const gfx::IntSize& size); + bool Resize(const gfxIntSize& size); void Readback(SharedSurface_GL* src, gfxImageSurface* dest); protected: - void Attach(SharedSurface* surface, const gfx::IntSize& size); + void Attach(SharedSurface* surface, const gfxIntSize& size); - DrawBuffer* CreateDraw(const gfx::IntSize& size); + DrawBuffer* CreateDraw(const gfxIntSize& size); ReadBuffer* CreateRead(SharedSurface_GL* surf); public: diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h index 1c314dba0b02..af6a2bcf1faf 100644 --- a/gfx/gl/GLUploadHelpers.h +++ b/gfx/gl/GLUploadHelpers.h @@ -89,11 +89,11 @@ UploadSurfaceToTexture(GLContext* gl, gfx::DataSourceSurface *aSurface, const nsIntRegion& aDstRegion, GLuint& aTexture, - bool aOverwrite = false, - const nsIntPoint& aSrcPoint = nsIntPoint(0, 0), - bool aPixelBuffer = false, - GLenum aTextureUnit = LOCAL_GL_TEXTURE0, - GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D); + bool aOverwrite, + const nsIntPoint& aSrcPoint, + bool aPixelBuffer, + GLenum aTextureUnit, + GLenum aTextureTarget); bool CanUploadSubTextures(GLContext* gl); bool CanUploadNonPowerOfTwo(GLContext* gl); diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index e4e8845287c8..82d597a37213 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -18,7 +18,7 @@ #include #include "mozilla/Attributes.h" #include "GLDefs.h" -#include "mozilla/gfx/Point.h" +#include "gfxPoint.h" #include "SurfaceTypes.h" namespace mozilla { @@ -32,14 +32,14 @@ protected: const SharedSurfaceType mType; const APITypeT mAPI; const AttachmentType mAttachType; - const gfx::IntSize mSize; + const gfxIntSize mSize; const bool mHasAlpha; bool mIsLocked; SharedSurface(SharedSurfaceType type, APITypeT api, AttachmentType attachType, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha) : mType(type) , mAPI(api) @@ -93,7 +93,7 @@ public: return mAttachType; } - const gfx::IntSize& Size() const { + const gfxIntSize& Size() const { return mSize; } diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp index d6eb11ef4d39..abc5308a2b2f 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -176,7 +176,7 @@ ChooseConfig(GLContext* gl, static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, EGLDisplay display, EGLConfig config, - const gfx::IntSize& size) + const gfxIntSize& size) { EGLint attribs[] = { LOCAL_EGL_WIDTH, size.width, @@ -192,7 +192,7 @@ static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, SharedSurface_ANGLEShareHandle* SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, EGLContext context, EGLConfig config, - const gfx::IntSize& size, bool hasAlpha) + const gfxIntSize& size, bool hasAlpha) { GLLibraryEGL* egl = gl->GetLibraryEGL(); MOZ_ASSERT(egl); diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h index d398f30e1f39..d6bedfd51a90 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -25,7 +25,7 @@ class SharedSurface_ANGLEShareHandle public: static SharedSurface_ANGLEShareHandle* Create(GLContext* gl, ID3D10Device1* d3d, EGLContext context, EGLConfig config, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha); static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) { @@ -43,7 +43,7 @@ protected: SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, EGLContext context, EGLSurface pbuffer, @@ -101,7 +101,7 @@ protected: ID3D10Device1* d3d, const SurfaceCaps& caps); - virtual SharedSurface* CreateShared(const gfx::IntSize& size) { + virtual SharedSurface* CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConsD3D, mContext, mConfig, diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index 4178f81bd957..153ab7bd25a8 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -21,7 +21,7 @@ namespace gl { SharedSurface_EGLImage* SharedSurface_EGLImage::Create(GLContext* prodGL, const GLFormats& formats, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, EGLContext context) { @@ -52,7 +52,7 @@ SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, const GLFormats& formats, GLuint prodTex) @@ -123,7 +123,7 @@ SharedSurface_EGLImage::LockProdImpl() static bool CreateTexturePipe(GLLibraryEGL* const egl, GLContext* const gl, - const GLFormats& formats, const gfx::IntSize& size, + const GLFormats& formats, const gfxIntSize& size, GLuint* const out_tex, EGLImage* const out_image) { MOZ_ASSERT(out_tex && out_image); @@ -170,18 +170,14 @@ SharedSurface_EGLImage::Fence() } if (!mPixels) { - SurfaceFormat format = - HasAlpha() ? FORMAT_B8G8R8A8 - : FORMAT_B8G8R8X8; - mPixels = Factory::CreateDataSourceSurface(Size(), format); + gfxImageFormat format = + HasAlpha() ? gfxImageFormatARGB32 + : gfxImageFormatRGB24; + mPixels = new gfxImageSurface(Size(), format); } - nsRefPtr wrappedData = - new gfxImageSurface(mPixels->GetData(), - ThebesIntSize(mPixels->GetSize()), - mPixels->Stride(), - SurfaceFormatToImageFormat(mPixels->GetFormat())); - mGL->ReadScreenIntoImageSurface(wrappedData); + mPixels->Flush(); + mGL->ReadScreenIntoImageSurface(mPixels); mPixels->MarkDirty(); return; } @@ -274,7 +270,7 @@ SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL) return 0; } -DataSourceSurface* +gfxImageSurface* SharedSurface_EGLImage::GetPixels() const { MutexAutoLock lock(mMutex); diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 03339f44bb75..0824e6680e60 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -24,10 +24,10 @@ class SharedSurface_EGLImage { public: static SharedSurface_EGLImage* Create(GLContext* prodGL, - const GLFormats& formats, - const gfx::IntSize& size, - bool hasAlpha, - EGLContext context); + const GLFormats& formats, + const gfxIntSize& size, + bool hasAlpha, + EGLContext context); static SharedSurface_EGLImage* Cast(SharedSurface* surf) { MOZ_ASSERT(surf->Type() == SharedSurfaceType::EGLImageShare); @@ -40,7 +40,7 @@ protected: GLLibraryEGL* const mEGL; const GLFormats mFormats; GLuint mProdTex; - RefPtr mPixels; + nsRefPtr mPixels; GLuint mProdTexForPipe; // Moves to mProdTex when mPipeActive becomes true. EGLImage mImage; GLContext* mCurConsGL; @@ -53,7 +53,7 @@ protected: SharedSurface_EGLImage(GLContext* gl, GLLibraryEGL* egl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, const GLFormats& formats, GLuint prodTex); @@ -82,7 +82,7 @@ public: GLuint AcquireConsumerTexture(GLContext* consGL); // Will be void if AcquireConsumerTexture returns non-zero. - gfx::DataSourceSurface* GetPixels() const; + gfxImageSurface* GetPixels() const; }; @@ -106,7 +106,7 @@ protected: {} public: - virtual SharedSurface* CreateShared(const gfx::IntSize& size) { + virtual SharedSurface* CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext); } diff --git a/gfx/gl/SharedSurfaceGL.cpp b/gfx/gl/SharedSurfaceGL.cpp index 859106642b8b..46b83f2adef1 100644 --- a/gfx/gl/SharedSurfaceGL.cpp +++ b/gfx/gl/SharedSurfaceGL.cpp @@ -8,7 +8,6 @@ #include "GLBlitHelper.h" #include "ScopedGLHelpers.h" #include "gfxImageSurface.h" -#include "mozilla/gfx/2D.h" using namespace mozilla::gfx; @@ -244,7 +243,7 @@ SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps, SharedSurface_Basic* SharedSurface_Basic::Create(GLContext* gl, const GLFormats& formats, - const IntSize& size, + const gfxIntSize& size, bool hasAlpha) { gl->MakeCurrent(); @@ -253,18 +252,18 @@ SharedSurface_Basic::Create(GLContext* gl, formats.color_texType, size); - SurfaceFormat format = FORMAT_B8G8R8X8; + gfxImageFormat format = gfxImageFormatRGB24; switch (formats.color_texInternalFormat) { case LOCAL_GL_RGB: case LOCAL_GL_RGB8: if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) - format = FORMAT_R5G6B5; + format = gfxImageFormatRGB16_565; else - format = FORMAT_B8G8R8X8; + format = gfxImageFormatRGB24; break; case LOCAL_GL_RGBA: case LOCAL_GL_RGBA8: - format = FORMAT_B8G8R8A8; + format = gfxImageFormatARGB32; break; default: MOZ_CRASH("Unhandled Tex format."); @@ -273,9 +272,9 @@ SharedSurface_Basic::Create(GLContext* gl, } SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, - const IntSize& size, + const gfxIntSize& size, bool hasAlpha, - SurfaceFormat format, + gfxImageFormat format, GLuint tex) : SharedSurface_GL(SharedSurfaceType::Basic, AttachmentType::GLTexture, @@ -284,7 +283,7 @@ SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, hasAlpha) , mTex(tex) { - mData = Factory::CreateDataSourceSurface(size, format); + mData = new gfxImageSurface(size, format); } SharedSurface_Basic::~SharedSurface_Basic() @@ -302,12 +301,8 @@ SharedSurface_Basic::Fence() MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize()); mGL->MakeCurrent(); - nsRefPtr wrappedData = - new gfxImageSurface(mData->GetData(), - ThebesIntSize(mData->GetSize()), - mData->Stride(), - SurfaceFormatToImageFormat(mData->GetFormat())); - mGL->ReadScreenIntoImageSurface(wrappedData); + mData->Flush(); + mGL->ReadScreenIntoImageSurface(mData); mData->MarkDirty(); } @@ -315,10 +310,10 @@ SharedSurface_Basic::Fence() SharedSurface_GLTexture* SharedSurface_GLTexture::Create(GLContext* prodGL, - GLContext* consGL, - const GLFormats& formats, - const gfx::IntSize& size, - bool hasAlpha) + GLContext* consGL, + const GLFormats& formats, + const gfxIntSize& size, + bool hasAlpha) { MOZ_ASSERT(prodGL); MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL)); diff --git a/gfx/gl/SharedSurfaceGL.h b/gfx/gl/SharedSurfaceGL.h index 70221aa2e7df..25bb00e53ac8 100644 --- a/gfx/gl/SharedSurfaceGL.h +++ b/gfx/gl/SharedSurfaceGL.h @@ -22,9 +22,6 @@ namespace mozilla { namespace gl { class GLContext; } - namespace gfx { - class DataSourceSurface; - } } namespace mozilla { @@ -46,7 +43,7 @@ protected: SharedSurface_GL(SharedSurfaceType type, AttachmentType attachType, GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha) : SharedSurface(type, APITypeT::OpenGL, attachType, size, hasAlpha) , mGL(gl) @@ -124,7 +121,7 @@ class SharedSurface_Basic public: static SharedSurface_Basic* Create(GLContext* gl, const GLFormats& formats, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha); static SharedSurface_Basic* Cast(SharedSurface* surf) { @@ -135,12 +132,12 @@ public: protected: const GLuint mTex; - RefPtr mData; + nsRefPtr mData; SharedSurface_Basic(GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, - gfx::SurfaceFormat format, + gfxImageFormat format, GLuint tex); public: @@ -163,7 +160,7 @@ public: } // Implementation-specific functions below: - gfx::DataSourceSurface* GetData() { + gfxImageSurface* GetData() { return mData; } }; @@ -176,7 +173,7 @@ public: : SurfaceFactory_GL(gl, SharedSurfaceType::Basic, caps) {} - virtual SharedSurface* CreateShared(const gfx::IntSize& size) { + virtual SharedSurface* CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha); } @@ -191,7 +188,7 @@ public: static SharedSurface_GLTexture* Create(GLContext* prodGL, GLContext* consGL, const GLFormats& formats, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha); static SharedSurface_GLTexture* Cast(SharedSurface* surf) { @@ -208,7 +205,7 @@ protected: SharedSurface_GLTexture(GLContext* prodGL, GLContext* consGL, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, GLuint tex) : SharedSurface_GL(SharedSurfaceType::GLTextureShare, @@ -261,7 +258,7 @@ public: MOZ_ASSERT(consGL != prodGL); } - virtual SharedSurface* CreateShared(const gfx::IntSize& size) { + virtual SharedSurface* CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; return SharedSurface_GLTexture::Create(mGL, mConsGL, mFormats, size, hasAlpha); } diff --git a/gfx/gl/SharedSurfaceGralloc.cpp b/gfx/gl/SharedSurfaceGralloc.cpp index 214d94f98a90..d34044a1ad61 100644 --- a/gfx/gl/SharedSurfaceGralloc.cpp +++ b/gfx/gl/SharedSurfaceGralloc.cpp @@ -17,8 +17,6 @@ #include "../layers/ipc/ShadowLayers.h" #include "ScopedGLHelpers.h" -#include "gfx2DGlue.h" - #define DEBUG_GRALLOC #ifdef DEBUG_GRALLOC #define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0) @@ -52,7 +50,7 @@ SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, SharedSurface_Gralloc* SharedSurface_Gralloc::Create(GLContext* prodGL, const GLFormats& formats, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, ISurfaceAllocator* allocator) { @@ -77,7 +75,7 @@ SharedSurface_Gralloc::Create(GLContext* prodGL, gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA : GFX_CONTENT_COLOR; - if (!allocator->AllocSurfaceDescriptorWithCaps(ThebesIntSize(size), type, USING_GL_RENDERING_ONLY, &baseDesc)) + if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc)) return false; if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) { diff --git a/gfx/gl/SharedSurfaceGralloc.h b/gfx/gl/SharedSurfaceGralloc.h index a13f624bf333..3a78da7bf406 100644 --- a/gfx/gl/SharedSurfaceGralloc.h +++ b/gfx/gl/SharedSurfaceGralloc.h @@ -26,7 +26,7 @@ class SharedSurface_Gralloc public: static SharedSurface_Gralloc* Create(GLContext* prodGL, const GLFormats& formats, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, layers::ISurfaceAllocator* allocator); @@ -52,7 +52,7 @@ protected: const GLuint mProdTex; SharedSurface_Gralloc(GLContext* prodGL, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha, GLLibraryEGL* egl, layers::ISurfaceAllocator* allocator, @@ -100,7 +100,7 @@ public: const SurfaceCaps& caps, layers::ISurfaceAllocator* allocator = nullptr); - virtual SharedSurface* CreateShared(const gfx::IntSize& size) { + virtual SharedSurface* CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; if (!mAllocator) { return nullptr; diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index 9298f9389eeb..4da90f837583 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -21,7 +21,7 @@ SharedSurface_IOSurface::Create(MacIOSurface* surface, GLContext *gl, bool hasAl MOZ_ASSERT(surface); MOZ_ASSERT(gl); - gfx::IntSize size(surface->GetWidth(), surface->GetHeight()); + gfxIntSize size(surface->GetWidth(), surface->GetHeight()); return new SharedSurface_IOSurface(surface, gl, size, hasAlpha); } @@ -57,7 +57,7 @@ SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei hei SharedSurface_IOSurface::SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, - const gfx::IntSize& size, + const gfxIntSize& size, bool hasAlpha) : SharedSurface_GL(SharedSurfaceType::IOSurface, AttachmentType::GLTexture, gl, size, hasAlpha) , mSurface(surface) @@ -96,7 +96,7 @@ SharedSurface_IOSurface::~SharedSurface_IOSurface() } SharedSurface* -SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size) +SurfaceFactory_IOSurface::CreateShared(const gfxIntSize& size) { bool hasAlpha = mReadCaps.alpha; RefPtr surf = diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index d153b809a525..8f3bcbb36072 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -48,7 +48,7 @@ public: MacIOSurface* GetIOSurface() { return mSurface; } private: - SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, const gfx::IntSize& size, bool hasAlpha); + SharedSurface_IOSurface(MacIOSurface* surface, GLContext* gl, const gfxIntSize& size, bool hasAlpha); RefPtr mSurface; nsRefPtr mImageSurface; @@ -65,7 +65,7 @@ public: } protected: - virtual SharedSurface* CreateShared(const gfx::IntSize& size) MOZ_OVERRIDE; + virtual SharedSurface* CreateShared(const gfxIntSize& size) MOZ_OVERRIDE; }; } /* namespace gfx */ diff --git a/gfx/gl/SurfaceFactory.cpp b/gfx/gl/SurfaceFactory.cpp index 885f447ed64c..9a00f2988fdb 100644 --- a/gfx/gl/SurfaceFactory.cpp +++ b/gfx/gl/SurfaceFactory.cpp @@ -21,7 +21,7 @@ SurfaceFactory::~SurfaceFactory() } SharedSurface* -SurfaceFactory::NewSharedSurface(const gfx::IntSize& size) +SurfaceFactory::NewSharedSurface(const gfxIntSize& size) { // Attempt to reuse an old surface. while (!mScraps.empty()) { diff --git a/gfx/gl/SurfaceFactory.h b/gfx/gl/SurfaceFactory.h index 4209d4628a0d..56f52324d26c 100644 --- a/gfx/gl/SurfaceFactory.h +++ b/gfx/gl/SurfaceFactory.h @@ -30,12 +30,12 @@ public: virtual ~SurfaceFactory(); protected: - virtual SharedSurface* CreateShared(const gfx::IntSize& size) = 0; + virtual SharedSurface* CreateShared(const gfxIntSize& size) = 0; std::queue mScraps; public: - SharedSurface* NewSharedSurface(const gfx::IntSize& size); + SharedSurface* NewSharedSurface(const gfxIntSize& size); // Auto-deletes surfs of the wrong type. void Recycle(SharedSurface*& surf); diff --git a/gfx/gl/SurfaceStream.cpp b/gfx/gl/SurfaceStream.cpp index 1b55ded14d0e..4048fe78abe0 100644 --- a/gfx/gl/SurfaceStream.cpp +++ b/gfx/gl/SurfaceStream.cpp @@ -57,7 +57,7 @@ SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glC } void -SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size, +SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& size, SharedSurface*& surf) { MOZ_ASSERT(!surf); @@ -170,7 +170,7 @@ SurfaceStream::SwapConsumer() } SharedSurface* -SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size) +SurfaceStream::Resize(SurfaceFactory* factory, const gfxIntSize& size) { MonitorAutoLock lock(mMonitor); @@ -220,7 +220,7 @@ SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size) + const gfxIntSize& size) { MonitorAutoLock lock(mMonitor); if (mConsumer) { @@ -313,7 +313,7 @@ SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size) + const gfxIntSize& size) { MonitorAutoLock lock(mMonitor); @@ -407,7 +407,7 @@ SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer, SharedSurface* SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size) + const gfxIntSize& size) { PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer"); diff --git a/gfx/gl/SurfaceStream.h b/gfx/gl/SurfaceStream.h index a597f614b650..b39af35d9b65 100644 --- a/gfx/gl/SurfaceStream.h +++ b/gfx/gl/SurfaceStream.h @@ -10,7 +10,7 @@ #include #include "mozilla/Monitor.h" #include "mozilla/Attributes.h" -#include "mozilla/gfx/Point.h" +#include "gfxPoint.h" #include "SurfaceTypes.h" namespace mozilla { @@ -89,7 +89,7 @@ protected: from = nullptr; } - void New(SurfaceFactory* factory, const gfx::IntSize& size, + void New(SurfaceFactory* factory, const gfxIntSize& size, SharedSurface*& surf); void Delete(SharedSurface*& surf); void Recycle(SurfaceFactory* factory, SharedSurface*& surf); @@ -117,9 +117,9 @@ public: * One common failure is asking for a too-large |size|. */ virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size) = 0; + const gfxIntSize& size) = 0; - virtual SharedSurface* Resize(SurfaceFactory* factory, const gfx::IntSize& size); + virtual SharedSurface* Resize(SurfaceFactory* factory, const gfxIntSize& size); protected: // SwapCons will return the same surface more than once, @@ -148,7 +148,7 @@ public: * SwapCons being called in Render. */ virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size); + const gfxIntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); @@ -168,7 +168,7 @@ public: virtual ~SurfaceStream_TripleBuffer_Copy(); virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size); + const gfxIntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); @@ -200,7 +200,7 @@ private: public: // Done writing to prod, swap prod and staging virtual SharedSurface* SwapProducer(SurfaceFactory* factory, - const gfx::IntSize& size); + const gfxIntSize& size); virtual SharedSurface* SwapConsumer_NoWait(); diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index ec6fb6f808b1..ef0b90c04ed1 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -16,7 +16,6 @@ #include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat #include "gfxRect.h" // for gfxRect #include "gfxUtils.h" // for gfxUtils -#include "gfx2DGlue.h" // for ThebesIntSize, etc #include "mozilla/gfx/BaseSize.h" // for BaseSize #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc @@ -98,7 +97,6 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) if (mGLContext) { nsRefPtr readSurf; - RefPtr readDSurf; nsRefPtr resultSurf; SharedSurface* sharedSurf = mGLContext->RequestFrame(); @@ -107,7 +105,7 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) return; } - gfxIntSize readSize(ThebesIntSize(sharedSurf->Size())); + gfxIntSize readSize(sharedSurf->Size()); gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? gfxImageFormatRGB24 : gfxImageFormatARGB32; @@ -127,14 +125,8 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); if (surfGL->Type() == SharedSurfaceType::Basic) { - // sharedSurf_Basic->mData must outlive readSurf and readDSurf. Alas, - // readSurf and readDSurf may not leave the scope they were declared in. SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); - readDSurf = sharedSurf_Basic->GetData(); - readSurf = new gfxImageSurface(readDSurf->GetData(), - ThebesIntSize(readDSurf->GetSize()), - readDSurf->Stride(), - SurfaceFormatToImageFormat(readDSurf->GetFormat())); + readSurf = sharedSurf_Basic->GetData(); } else { if (resultSurf->GetSize() != readSize || !(readSurf = resultSurf->GetAsImageSurface()) || diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.cpp b/gfx/layers/d3d10/CanvasLayerD3D10.cpp index 3ed02faf451f..dca2fd4e35da 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp +++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp @@ -159,17 +159,21 @@ CanvasLayerD3D10::UpdateSurface() return; } - gfx::DataSourceSurface* frameData = shareSurf->GetData(); - // Scope for DrawTarget, so it's destroyed before Unmap. + gfxImageSurface* frameData = shareSurf->GetData(); + // Scope for gfxContext, so it's destroyed before Unmap. { - RefPtr dt = Factory::CreateDrawTargetForData(BACKEND_CAIRO, - (uint8_t*)map.pData, - shareSurf->Size(), - map.RowPitch, - FORMAT_B8G8R8A8); - Rect drawRect(0, 0, shareSurf->Size().width, shareSurf->Size().height); - dt->DrawSurface(frameData, drawRect, drawRect); - dt->Flush(); + nsRefPtr mapSurf = + new gfxImageSurface((uint8_t*)map.pData, + shareSurf->Size(), + map.RowPitch, + gfxImageFormatARGB32); + + nsRefPtr ctx = new gfxContext(mapSurf); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(frameData); + ctx->Paint(); + + mapSurf->Flush(); } mTexture->Unmap(0); diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp index eb592d4bed2c..04dfc199b068 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -101,17 +101,21 @@ CanvasLayerD3D9::UpdateSurface() D3DLOCKED_RECT rect = textureLock.GetLockRect(); - gfx::DataSourceSurface* frameData = shareSurf->GetData(); - // Scope for DrawTarget, so it's destroyed early. + gfxImageSurface* frameData = shareSurf->GetData(); + // Scope for gfxContext, so it's destroyed early. { - RefPtr mapDt = Factory::CreateDrawTargetForData(BACKEND_CAIRO, - (uint8_t*)rect.pBits, - shareSurf->Size(), - rect.Pitch, - FORMAT_B8G8R8A8); - Rect drawRect(0, 0, shareSurf->Size().width, shareSurf->Size().height); - mapDt->DrawSurface(frameData, drawRect, drawRect); - mapDt->Flush(); + nsRefPtr mapSurf = + new gfxImageSurface((uint8_t*)rect.pBits, + shareSurf->Size(), + rect.Pitch, + gfxImageFormatARGB32); + + gfxContext ctx(mapSurf); + ctx.SetOperator(gfxContext::OPERATOR_SOURCE); + ctx.SetSource(frameData); + ctx.Paint(); + + mapSurf->Flush(); } } else { RECT r; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 58c35e52f639..7207de68d859 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -483,7 +483,7 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - gfx::DataSourceSurface* toUpload = nullptr; + gfxImageSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf); @@ -532,7 +532,7 @@ StreamTextureSourceOGL::RetrieveTextureFromStream() if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(ThebesIntSize(toUpload->GetSize())); + nsIntSize size(toUpload->GetSize()); nsIntRect rect(nsIntPoint(0,0), size); nsIntRegion bounds(rect); mFormat = UploadSurfaceToTexture(gl(), @@ -949,7 +949,7 @@ SurfaceStreamHostOGL::Lock() mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height); - DataSourceSurface* toUpload = nullptr; + gfxImageSurface* toUpload = nullptr; switch (sharedSurf->Type()) { case SharedSurfaceType::GLTextureShare: { SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf); @@ -998,7 +998,7 @@ SurfaceStreamHostOGL::Lock() if (toUpload) { // mBounds seems to end up as (0,0,0,0) a lot, so don't use it? - nsIntSize size(ThebesIntSize(toUpload->GetSize())); + nsIntSize size(toUpload->GetSize()); nsIntRect rect(nsIntPoint(0,0), size); nsIntRegion bounds(rect); mFormat = UploadSurfaceToTexture(mGL, From 81ddca1c405b252d0a85d9c2bac483007d9466cd Mon Sep 17 00:00:00 2001 From: Steve Workman Date: Mon, 16 Dec 2013 16:46:09 -0800 Subject: [PATCH 26/34] Bug 444328 - Add PRFileDescAutoLock and LockedPRFileDesc to automate and enforce calls to Get|ReleaseFD_Locked r=mcmanus --- netwerk/base/src/nsSocketTransport2.cpp | 118 ++++++++---------------- netwerk/base/src/nsSocketTransport2.h | 86 ++++++++++++++++- 2 files changed, 118 insertions(+), 86 deletions(-) diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp index 34d2e9a2a728..15478bcfebdd 100644 --- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -748,7 +748,7 @@ nsSocketTransport::nsSocketTransport() , mResolving(false) , mNetAddrIsSet(false) , mLock("nsSocketTransport.mLock") - , mFD(nullptr) + , mFD(MOZ_THIS_IN_INITIALIZER_LIST()) , mFDref(0) , mFDconnected(false) , mInput(MOZ_THIS_IN_INITIALIZER_LIST()) @@ -891,7 +891,7 @@ nsSocketTransport::InitWithFilename(const char *filename) nsresult nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr) { - NS_ASSERTION(!mFD, "already initialized"); + NS_ASSERTION(!mFD.IsInitialized(), "already initialized"); char buf[kNetAddrMaxCStrBufSize]; NetAddrToString(addr, buf, sizeof(buf)); @@ -913,15 +913,19 @@ nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr) mState = STATE_TRANSFERRING; mNetAddrIsSet = true; - mFD = fd; - mFDref = 1; - mFDconnected = 1; + { + MutexAutoLock lock(mLock); + + mFD = fd; + mFDref = 1; + mFDconnected = 1; + } // make sure new socket is non-blocking PRSocketOptionData opt; opt.option = PR_SockOpt_Nonblocking; opt.value.non_blocking = true; - PR_SetSocketOption(mFD, &opt); + PR_SetSocketOption(fd, &opt); SOCKET_LOG(("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n", this, mHost.get(), mPort)); @@ -1209,7 +1213,7 @@ nsSocketTransport::InitiateSocket() // // if we already have a connected socket, then just attach and return. // - if (mFD) { + if (mFD.IsInitialized()) { rv = gSocketTransportService->AttachSocket(mFD, this); if (NS_SUCCEEDED(rv)) mAttached = true; @@ -1533,7 +1537,7 @@ nsSocketTransport::OnSocketConnected() // to trample over mFDref if mFD is already set. { MutexAutoLock lock(mLock); - NS_ASSERTION(mFD, "no socket"); + NS_ASSERTION(mFD.IsInitialized(), "no socket"); NS_ASSERTION(mFDref == 1, "wrong socket ref count"); mFDconnected = true; } @@ -1546,11 +1550,13 @@ nsSocketTransport::OnSocketConnected() PRFileDesc * nsSocketTransport::GetFD_Locked() { + mLock.AssertCurrentThreadOwns(); + // mFD is not available to the streams while disconnected. if (!mFDconnected) return nullptr; - if (mFD) + if (mFD.IsInitialized()) mFDref++; return mFD; @@ -1587,6 +1593,8 @@ STS_PRCloseOnSocketTransport(PRFileDesc *fd) void nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd) { + mLock.AssertCurrentThreadOwns(); + NS_ASSERTION(mFD == fd, "wrong fd"); SOCKET_LOG(("JIMB: ReleaseFD_Locked: mFDref = %d\n", mFDref)); @@ -1855,7 +1863,7 @@ nsSocketTransport::OnSocketDetached(PRFileDesc *fd) nsCOMPtr ourEventSink; { MutexAutoLock lock(mLock); - if (mFD) { + if (mFD.IsInitialized()) { ReleaseFD_Locked(mFD); // flag mFD as unusable; this prevents other consumers from // acquiring a reference to mFD. @@ -2074,14 +2082,10 @@ nsSocketTransport::IsAlive(bool *result) { *result = false; - PRFileDesc* fd = nullptr; - { - MutexAutoLock lock(mLock); - if (NS_FAILED(mCondition)) - return NS_OK; - fd = GetFD_Locked(); - if (!fd) - return NS_OK; + nsresult conditionWhileLocked = NS_OK; + PRFileDescAutoLock fd(this, &conditionWhileLocked); + if (NS_FAILED(conditionWhileLocked) || !fd.IsInitialized()) { + return NS_OK; } // XXX do some idle-time based checks?? @@ -2092,10 +2096,6 @@ nsSocketTransport::IsAlive(bool *result) if ((rval > 0) || (rval < 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR)) *result = true; - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } return NS_OK; } @@ -2138,13 +2138,8 @@ nsSocketTransport::GetSelfAddr(NetAddr *addr) // while holding mLock since those methods might re-enter // socket transport code. - PRFileDesc *fd; - { - MutexAutoLock lock(mLock); - fd = GetFD_Locked(); - } - - if (!fd) { + PRFileDescAutoLock fd(this); + if (!fd.IsInitialized()) { return NS_ERROR_NOT_CONNECTED; } @@ -2163,11 +2158,6 @@ nsSocketTransport::GetSelfAddr(NetAddr *addr) (PR_GetSockName(fd, &prAddr) == PR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; PRNetAddrToNetAddr(&prAddr, addr); - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } - return rv; } @@ -2244,106 +2234,70 @@ nsSocketTransport::GetQoSBits(uint8_t *aQoSBits) NS_IMETHODIMP nsSocketTransport::GetRecvBufferSize(uint32_t *aSize) { - PRFileDesc *fd; - { - MutexAutoLock lock(mLock); - fd = GetFD_Locked(); - } - - if (!fd) + PRFileDescAutoLock fd(this); + if (!fd.IsInitialized()) return NS_ERROR_NOT_CONNECTED; nsresult rv = NS_OK; PRSocketOptionData opt; opt.option = PR_SockOpt_RecvBufferSize; - if (PR_GetSocketOption(mFD, &opt) == PR_SUCCESS) + if (PR_GetSocketOption(fd, &opt) == PR_SUCCESS) *aSize = opt.value.recv_buffer_size; else rv = NS_ERROR_FAILURE; - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } return rv; } NS_IMETHODIMP nsSocketTransport::GetSendBufferSize(uint32_t *aSize) { - PRFileDesc *fd; - { - MutexAutoLock lock(mLock); - fd = GetFD_Locked(); - } - - if (!fd) + PRFileDescAutoLock fd(this); + if (!fd.IsInitialized()) return NS_ERROR_NOT_CONNECTED; nsresult rv = NS_OK; PRSocketOptionData opt; opt.option = PR_SockOpt_SendBufferSize; - if (PR_GetSocketOption(mFD, &opt) == PR_SUCCESS) + if (PR_GetSocketOption(fd, &opt) == PR_SUCCESS) *aSize = opt.value.send_buffer_size; else rv = NS_ERROR_FAILURE; - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } return rv; } NS_IMETHODIMP nsSocketTransport::SetRecvBufferSize(uint32_t aSize) { - PRFileDesc *fd; - { - MutexAutoLock lock(mLock); - fd = GetFD_Locked(); - } - - if (!fd) + PRFileDescAutoLock fd(this); + if (!fd.IsInitialized()) return NS_ERROR_NOT_CONNECTED; nsresult rv = NS_OK; PRSocketOptionData opt; opt.option = PR_SockOpt_RecvBufferSize; opt.value.recv_buffer_size = aSize; - if (PR_SetSocketOption(mFD, &opt) != PR_SUCCESS) + if (PR_SetSocketOption(fd, &opt) != PR_SUCCESS) rv = NS_ERROR_FAILURE; - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } return rv; } NS_IMETHODIMP nsSocketTransport::SetSendBufferSize(uint32_t aSize) { - PRFileDesc *fd; - { - MutexAutoLock lock(mLock); - fd = GetFD_Locked(); - } - - if (!fd) + PRFileDescAutoLock fd(this); + if (!fd.IsInitialized()) return NS_ERROR_NOT_CONNECTED; nsresult rv = NS_OK; PRSocketOptionData opt; opt.option = PR_SockOpt_SendBufferSize; opt.value.send_buffer_size = aSize; - if (PR_SetSocketOption(mFD, &opt) != PR_SUCCESS) + if (PR_SetSocketOption(fd, &opt) != PR_SUCCESS) rv = NS_ERROR_FAILURE; - { - MutexAutoLock lock(mLock); - ReleaseFD_Locked(fd); - } return rv; } diff --git a/netwerk/base/src/nsSocketTransport2.h b/netwerk/base/src/nsSocketTransport2.h index c957336ae16d..70b6ed8918cb 100644 --- a/netwerk/base/src/nsSocketTransport2.h +++ b/netwerk/base/src/nsSocketTransport2.h @@ -172,6 +172,84 @@ private: STATE_TRANSFERRING }; + // Safer way to get and automatically release PRFileDesc objects. + class MOZ_STACK_CLASS PRFileDescAutoLock + { + public: + typedef mozilla::MutexAutoLock MutexAutoLock; + + PRFileDescAutoLock(nsSocketTransport *aSocketTransport, + nsresult *aConditionWhileLocked = nullptr) + : mSocketTransport(aSocketTransport) + , mFd(nullptr) + { + MOZ_ASSERT(aSocketTransport); + MutexAutoLock lock(mSocketTransport->mLock); + if (aConditionWhileLocked) { + *aConditionWhileLocked = mSocketTransport->mCondition; + if (NS_FAILED(mSocketTransport->mCondition)) { + return; + } + } + mFd = mSocketTransport->GetFD_Locked(); + NS_WARN_IF_FALSE(mFd, "PRFileDescAutoLock cannot get fd!"); + } + ~PRFileDescAutoLock() { + MutexAutoLock lock(mSocketTransport->mLock); + if (mFd) { + mSocketTransport->ReleaseFD_Locked(mFd); + } + } + bool IsInitialized() { + return mFd; + } + operator PRFileDesc*() { + return mFd; + } + private: + operator PRFileDescAutoLock*() { return nullptr; } + // Weak ptr to nsSocketTransport since this is a stack class only. + nsSocketTransport *mSocketTransport; + PRFileDesc *mFd; + }; + friend class PRFileDescAutoLock; + + class LockedPRFileDesc + { + public: + LockedPRFileDesc(nsSocketTransport *aSocketTransport) + : mSocketTransport(aSocketTransport) + , mFd(nullptr) + { + MOZ_ASSERT(aSocketTransport); + } + ~LockedPRFileDesc() {} + bool IsInitialized() { + return mFd; + } + LockedPRFileDesc& operator=(PRFileDesc *aFd) { + mSocketTransport->mLock.AssertCurrentThreadOwns(); + mFd = aFd; + return *this; + } + operator PRFileDesc*() { + if (mSocketTransport->mAttached) { + mSocketTransport->mLock.AssertCurrentThreadOwns(); + } + return mFd; + } + bool operator==(PRFileDesc *aFd) { + mSocketTransport->mLock.AssertCurrentThreadOwns(); + return mFd == aFd; + } + private: + operator LockedPRFileDesc*() { return nullptr; } + // Weak ptr to nsSocketTransport since it owns this class. + nsSocketTransport *mSocketTransport; + PRFileDesc *mFd; + }; + friend class LockedPRFileDesc; + //------------------------------------------------------------------------- // these members are "set" at initialization time and are never modified // afterwards. this allows them to be safely accessed from any thread. @@ -242,10 +320,10 @@ private: // socket input/output objects. these may be accessed on any thread with // the exception of some specific methods (XXX). - Mutex mLock; // protects members in this section - PRFileDesc *mFD; - nsrefcnt mFDref; // mFD is closed when mFDref goes to zero. - bool mFDconnected; // mFD is available to consumer when TRUE. + Mutex mLock; // protects members in this section. + LockedPRFileDesc mFD; + nsrefcnt mFDref; // mFD is closed when mFDref goes to zero. + bool mFDconnected; // mFD is available to consumer when TRUE. nsCOMPtr mCallbacks; nsCOMPtr mEventSink; From f3f1364e6e5f99d96c5dcc00c0923df4ff3ab645 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 16 Dec 2013 14:28:35 -0800 Subject: [PATCH 27/34] Bug 950923 - Fix an exact rooting hazard in GlobalObject::getIntrinsicValue; r=sfink --HG-- extra : rebase_source : f49223dbfb97147d43bbf3720098b97e516c406a --- js/src/builtin/Intl.cpp | 10 +++++----- js/src/jit/VMFunctions.cpp | 2 +- js/src/vm/GlobalObject.h | 8 +++++--- js/src/vm/Interpreter-inl.h | 2 +- js/src/vm/SelfHosting.cpp | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index da65a0eba838..c4b9b602ad08 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -397,7 +397,7 @@ IntlInitialize(JSContext *cx, HandleObject obj, Handle initialize HandleValue locales, HandleValue options) { RootedValue initializerValue(cx); - if (!cx->global()->getIntrinsicValue(cx, initializer, &initializerValue)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), initializer, &initializerValue)) return false; JS_ASSERT(initializerValue.isObject()); JS_ASSERT(initializerValue.toObject().is()); @@ -463,7 +463,7 @@ static bool GetInternals(JSContext *cx, HandleObject obj, MutableHandleObject internals) { RootedValue getInternalsValue(cx); - if (!cx->global()->getIntrinsicValue(cx, cx->names().getInternals, &getInternalsValue)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().getInternals, &getInternalsValue)) return false; JS_ASSERT(getInternalsValue.isObject()); JS_ASSERT(getInternalsValue.toObject().is()); @@ -690,7 +690,7 @@ InitCollatorClass(JSContext *cx, HandleObject Intl, Handle global * passing to methods like Array.prototype.sort). */ RootedValue getter(cx); - if (!cx->global()->getIntrinsicValue(cx, cx->names().CollatorCompareGet, &getter)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().CollatorCompareGet, &getter)) return nullptr; RootedValue undefinedValue(cx, UndefinedValue()); if (!JSObject::defineProperty(cx, proto, cx->names().compare, undefinedValue, @@ -1178,7 +1178,7 @@ InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle gl * for passing to methods like Array.prototype.map). */ RootedValue getter(cx); - if (!cx->global()->getIntrinsicValue(cx, cx->names().NumberFormatFormatGet, &getter)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().NumberFormatFormatGet, &getter)) return nullptr; RootedValue undefinedValue(cx, UndefinedValue()); if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue, @@ -1635,7 +1635,7 @@ InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle * (suitable for passing to methods like Array.prototype.map). */ RootedValue getter(cx); - if (!cx->global()->getIntrinsicValue(cx, cx->names().DateTimeFormatFormatGet, &getter)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().DateTimeFormatFormatGet, &getter)) return nullptr; RootedValue undefinedValue(cx, UndefinedValue()); if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue, diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 061f84714bb1..4f87d172c995 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -552,7 +552,7 @@ OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out) bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval) { - if (!cx->global()->getIntrinsicValue(cx, name, rval)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval)) return false; // This function is called when we try to compile a cold getintrinsic diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index efac12ea59b9..57c13a4c6791 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -526,13 +526,15 @@ class GlobalObject : public JSObject return maybeGetIntrinsicValue(NameToId(name), vp); } - bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) { - if (maybeGetIntrinsicValue(name, value.address())) + static bool getIntrinsicValue(JSContext *cx, Handle global, + HandlePropertyName name, MutableHandleValue value) + { + if (global->maybeGetIntrinsicValue(name, value.address())) return true; if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) return false; RootedId id(cx, NameToId(name)); - return addIntrinsicValue(cx, id, value); + return global->addIntrinsicValue(cx, id, value); } bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value); diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 328c96580bc0..cefe234bc064 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -210,7 +210,7 @@ inline bool GetIntrinsicOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp) { RootedPropertyName name(cx, cx->currentScript()->getName(pc)); - return cx->global()->getIntrinsicValue(cx, name, vp); + return GlobalObject::getIntrinsicValue(cx, cx->global(), name, vp); } inline bool diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 8e46237b5d99..eb1105f6c905 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1011,7 +1011,7 @@ JSFunction * js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName) { RootedValue func(cx); - if (!cx->global()->getIntrinsicValue(cx, propName, &func)) + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func)) return nullptr; JS_ASSERT(func.isObject()); From f399e6999349ef054015d78d703e6f69c5e40955 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 16 Dec 2013 15:41:54 -0800 Subject: [PATCH 28/34] Bug 950950 - Fix some exact rooting hazards in the bytecode emitter; r=sfink --HG-- extra : rebase_source : a316b1cf10c7a251ef04fb0c3526a5320d40661e --- js/src/frontend/BytecodeEmitter.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index ddf2ca9c9e9f..51f39034c3e5 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -709,18 +709,18 @@ AllLocalsAliased(StaticBlockObject &obj) #endif static bool -ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, StaticBlockObject &blockObj) +ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, Handle blockObj) { - uint32_t depthPlusFixed = blockObj.stackDepth(); + uint32_t depthPlusFixed = blockObj->stackDepth(); if (!AdjustBlockSlot(cx, bce, &depthPlusFixed)) return false; - for (unsigned i = 0; i < blockObj.slotCount(); i++) { - Definition *dn = blockObj.maybeDefinitionParseNode(i); + for (unsigned i = 0; i < blockObj->slotCount(); i++) { + Definition *dn = blockObj->maybeDefinitionParseNode(i); /* Beware the empty destructuring dummy. */ if (!dn) { - blockObj.setAliased(i, bce->sc->allLocalsAliased()); + blockObj->setAliased(i, bce->sc->allLocalsAliased()); continue; } @@ -738,10 +738,10 @@ ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, StaticBlockObjec } #endif - blockObj.setAliased(i, bce->isAliasedName(dn)); + blockObj->setAliased(i, bce->isAliasedName(dn)); } - JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(blockObj)); + JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(*blockObj)); return true; } @@ -809,18 +809,18 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O parent = stmt->blockScopeIndex; } - StaticBlockObject &blockObj = objbox->object->as(); + Rooted blockObj(cx, &objbox->object->as()); uint32_t scopeObjectIndex = bce->objectList.add(objbox); - int depth = bce->stackDepth - (blockObj.slotCount() + extraSlots); + int depth = bce->stackDepth - (blockObj->slotCount() + extraSlots); JS_ASSERT(depth >= 0); - blockObj.setStackDepth(depth); + blockObj->setStackDepth(depth); if (!ComputeAliasedSlots(cx, bce, blockObj)) return false; - if (blockObj.needsClone()) { + if (blockObj->needsClone()) { if (!EmitInternedObjectOp(cx, scopeObjectIndex, JSOP_PUSHBLOCKSCOPE, bce)) return false; } @@ -830,8 +830,8 @@ EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, O return false; PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset()); - blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce)); - FinishPushBlockScope(bce, stmt, blockObj); + blockObj->initEnclosingStaticScope(EnclosingStaticScope(bce)); + FinishPushBlockScope(bce, stmt, *blockObj); JS_ASSERT(stmt->isBlockScope); @@ -2384,7 +2384,7 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) * If there are hoisted let declarations, their stack slots go under the * discriminant's value so push their slots now and enter the block later. */ - StaticBlockObject *blockObj = nullptr; + Rooted blockObj(cx, nullptr); if (pn2->isKind(PNK_LEXICALSCOPE)) { blockObj = &pn2->pn_objbox->object->as(); for (uint32_t i = 0; i < blockObj->slotCount(); ++i) { From a8e58b22679360a578be3933c7d9a94cb2c64405 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Mon, 16 Dec 2013 16:24:44 +1300 Subject: [PATCH 29/34] Bug 950120 - Use audio reader if no video reader available, and handle zero reader case. r=doublec --- content/media/mediasource/MediaSourceDecoder.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/media/mediasource/MediaSourceDecoder.cpp b/content/media/mediasource/MediaSourceDecoder.cpp index beeb3f3624ad..83f197995fd1 100644 --- a/content/media/mediasource/MediaSourceDecoder.cpp +++ b/content/media/mediasource/MediaSourceDecoder.cpp @@ -85,7 +85,11 @@ public: nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE { // XXX: Merge result with audio reader. - return GetVideoReader()->GetBuffered(aBuffered, aStartTime); + MediaDecoderReader* reader = GetVideoReader() ? GetVideoReader() : GetAudioReader(); + if (reader) { + return reader->GetBuffered(aBuffered, aStartTime); + } + return NS_OK; } MediaQueue& AudioQueue() MOZ_OVERRIDE From 295bf5d6789cc1b1d16fd4f618527a476b42134b Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Dec 2013 17:46:30 -0800 Subject: [PATCH 30/34] Backed out changeset a70f5add1982 (bug 950658) for breaking Windows builds --- js/src/jsinfer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 839565c99a68..04197729e663 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -884,10 +884,8 @@ HeapTypeSetKey::instantiate(JSContext *cx) { if (maybeTypes()) return true; - if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx)) { - cx->clearPendingException(); + if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx)) return false; - } maybeTypes_ = object()->maybeType()->getProperty(cx, id()); return maybeTypes_ != nullptr; } From 2e75b22c850435d98f366796bf05c13791df36c5 Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Thu, 14 Nov 2013 10:06:21 -0800 Subject: [PATCH 31/34] Bug 914762 - Allow nsThread to be subclassed, r=bsmedberg. --HG-- extra : transplant_source : %BD%C5%CB%7Fx%82q%FC%B6%AA%8B%8E%9Fo%BE%82%DE%09h%FF --- xpcom/threads/nsThread.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index 402a4cdaa97d..714fef38ec65 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -18,8 +18,8 @@ #include "nsAutoPtr.h" // A native thread -class nsThread MOZ_FINAL : public nsIThreadInternal, - public nsISupportsPriority +class nsThread : public nsIThreadInternal, + public nsISupportsPriority { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -54,7 +54,7 @@ public: static nsresult SetMainThreadObserver(nsIThreadObserver* aObserver); -private: +protected: static nsIThreadObserver* sMainThreadObserver; class nsChainedEventQueue; @@ -64,7 +64,7 @@ private: friend class nsThreadShutdownEvent; - ~nsThread(); + virtual ~nsThread(); bool ShuttingDown() { return mShutdownContext != nullptr; } From 357b12898a29f7189984bc804b624952285edb76 Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Wed, 23 Oct 2013 06:16:49 -0700 Subject: [PATCH 32/34] Bug 914762 - Switch Workers to use a normal nsThread event loop, r=mrbkap. --HG-- extra : transplant_source : /%93%60%CC%3A%16%B16%A1%5Bmx%9F%FA%7B%10JD%F0%E7 --- dom/promise/Promise.cpp | 7 +- dom/workers/MessagePort.cpp | 24 +- dom/workers/RuntimeService.cpp | 697 +++++++--- dom/workers/RuntimeService.h | 15 +- dom/workers/ScriptLoader.cpp | 122 +- dom/workers/URL.cpp | 70 +- dom/workers/WorkerPrivate.cpp | 2354 +++++++++++++++++++------------- dom/workers/WorkerPrivate.h | 400 ++---- dom/workers/WorkerRunnable.cpp | 480 +++++++ dom/workers/WorkerRunnable.h | 319 +++++ dom/workers/Workers.h | 63 +- dom/workers/XMLHttpRequest.cpp | 1381 ++++++++++--------- dom/workers/XMLHttpRequest.h | 11 +- dom/workers/moz.build | 3 + 14 files changed, 3684 insertions(+), 2262 deletions(-) create mode 100644 dom/workers/WorkerRunnable.cpp create mode 100644 dom/workers/WorkerRunnable.h diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index c48df3993060..7b2ddb2be277 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -15,6 +15,7 @@ #include "nsContentUtils.h" #include "nsPIDOMWindow.h" #include "WorkerPrivate.h" +#include "WorkerRunnable.h" #include "nsJSPrincipals.h" #include "nsJSUtils.h" #include "nsPIDOMWindow.h" @@ -60,8 +61,7 @@ class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable { public: WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise) - : WorkerRunnable(aWorkerPrivate, WorkerThread, - UnchangedBusyCount, SkipWhenClearing) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) , mPromise(aPromise) { MOZ_ASSERT(aPromise); @@ -169,8 +169,7 @@ public: Promise* aPromise, JS::Handle aValue, Promise::PromiseState aState) - : WorkerRunnable(aWorkerPrivate, WorkerThread, - UnchangedBusyCount, SkipWhenClearing), + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), PromiseResolverMixin(aPromise, aValue, aState) {} diff --git a/dom/workers/MessagePort.cpp b/dom/workers/MessagePort.cpp index bf8012d0e0b9..f476d79d0ab7 100644 --- a/dom/workers/MessagePort.cpp +++ b/dom/workers/MessagePort.cpp @@ -11,6 +11,7 @@ #include "SharedWorker.h" #include "WorkerPrivate.h" +#include "WorkerRunnable.h" using mozilla::dom::EventHandlerNonNull; using mozilla::dom::MessagePortBase; @@ -28,13 +29,10 @@ class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable public: DelayedEventRunnable(WorkerPrivate* aWorkerPrivate, - Target aTarget, + TargetAndBusyBehavior aBehavior, MessagePort* aMessagePort, nsTArray>& aEvents) - : WorkerRunnable(aWorkerPrivate, aTarget, - aTarget == WorkerThread ? ModifyBusyCount : UnchangedBusyCount, - SkipWhenClearing), - mMessagePort(aMessagePort) + : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort) { AssertIsOnMainThread(); MOZ_ASSERT(aMessagePort); @@ -109,16 +107,22 @@ MessagePort::Start() mStarted = true; if (!mQueuedEvents.IsEmpty()) { - WorkerRunnable::Target target = WorkerRunnable::WorkerThread; - WorkerPrivate* workerPrivate = mWorkerPrivate; + WorkerPrivate* workerPrivate; + WorkerRunnable::TargetAndBusyBehavior behavior; - if (!workerPrivate) { - target = WorkerRunnable::ParentThread; + if (mWorkerPrivate) { + workerPrivate = mWorkerPrivate; + behavior = WorkerRunnable::WorkerThreadModifyBusyCount; + } + else { workerPrivate = mSharedWorker->GetWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + behavior = WorkerRunnable::ParentThreadUnchangedBusyCount; } nsRefPtr runnable = - new DelayedEventRunnable(workerPrivate, target, this, mQueuedEvents); + new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents); runnable->Dispatch(nullptr); } } diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index b936b6e0c68f..4a8f96b0c2c4 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -43,6 +43,7 @@ #include "nsLayoutStatics.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" +#include "nsThread.h" #include "nsThreadUtils.h" #include "nsTraceRefcnt.h" #include "nsXPCOM.h" @@ -50,13 +51,18 @@ #include "OSFileConstants.h" #include "xpcpublic.h" -#include "SharedWorker.h" -#include "WorkerPrivate.h" - #ifdef MOZ_NUWA_PROCESS #include "ipc/Nuwa.h" #endif +#ifdef DEBUG +#include "nsThreadManager.h" +#endif + +#include "SharedWorker.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" + using namespace mozilla; using namespace mozilla::dom; @@ -593,6 +599,8 @@ void ErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aReport) { WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(worker); + return worker->ReportError(aCx, aMessage, aReport); } @@ -600,6 +608,7 @@ bool OperationCallback(JSContext* aCx) { WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(worker); // Now is a good time to turn on profiling if it's pending. profiler_js_operation_callback(); @@ -607,98 +616,42 @@ OperationCallback(JSContext* aCx) return worker->OperationCallback(aCx); } -class LogViolationDetailsRunnable : public nsRunnable +class LogViolationDetailsRunnable MOZ_FINAL : public nsRunnable { WorkerPrivate* mWorkerPrivate; + nsCOMPtr mSyncLoopTarget; nsString mFileName; uint32_t mLineNum; - uint32_t mSyncQueueKey; - -private: - class LogViolationDetailsResponseRunnable : public WorkerSyncRunnable - { - uint32_t mSyncQueueKey; - - public: - LogViolationDetailsResponseRunnable(WorkerPrivate* aWorkerPrivate, - uint32_t aSyncQueueKey) - : WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, false), - mSyncQueueKey(aSyncQueueKey) - { - NS_ASSERTION(aWorkerPrivate, "Don't hand me a null WorkerPrivate!"); - } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true); - return true; - } - - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - AssertIsOnMainThread(); - return true; - } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - AssertIsOnMainThread(); - } - }; public: LogViolationDetailsRunnable(WorkerPrivate* aWorker, const nsString& aFileName, uint32_t aLineNum) - : mWorkerPrivate(aWorker), - mFileName(aFileName), - mLineNum(aLineNum), - mSyncQueueKey(0) + : mWorkerPrivate(aWorker), mFileName(aFileName), mLineNum(aLineNum) { - NS_ASSERTION(aWorker, "WorkerPrivate cannot be null"); + MOZ_ASSERT(aWorker); } + NS_DECL_ISUPPORTS_INHERITED + bool Dispatch(JSContext* aCx) { AutoSyncLoopHolder syncLoop(mWorkerPrivate); - mSyncQueueKey = syncLoop.SyncQueueKey(); + + mSyncLoopTarget = syncLoop.EventTarget(); + MOZ_ASSERT(mSyncLoopTarget); if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { JS_ReportError(aCx, "Failed to dispatch to main thread!"); return false; } - return syncLoop.RunAndForget(aCx); + return syncLoop.Run(); } - NS_IMETHOD - Run() - { - AssertIsOnMainThread(); - - nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP(); - if (csp) { - NS_NAMED_LITERAL_STRING(scriptSample, - "Call to eval() or related function blocked by CSP."); - if (mWorkerPrivate->GetReportCSPViolations()) { - csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, - mFileName, scriptSample, mLineNum, EmptyString()); - } - } - - nsRefPtr response = - new LogViolationDetailsResponseRunnable(mWorkerPrivate, mSyncQueueKey); - if (!response->Dispatch(nullptr)) { - NS_WARNING("Failed to dispatch response!"); - } - - return NS_OK; - } +private: + NS_DECL_NSIRUNNABLE }; bool @@ -715,7 +668,7 @@ ContentSecurityPolicyAllows(JSContext* aCx) const char* file; if (JS_DescribeScriptedCaller(aCx, &script, &lineNum) && (file = JS_GetScriptFilename(aCx, script))) { - fileName.AssignASCII(file); + fileName = NS_ConvertUTF8toUTF16(file); } else { JS_ReportPendingException(aCx); } @@ -959,81 +912,158 @@ private: WorkerPrivate* mWorkerPrivate; }; -class WorkerThreadRunnable : public nsRunnable +class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable { WorkerPrivate* mWorkerPrivate; + nsRefPtr mThread; + + class FinishedRunnable MOZ_FINAL : public nsRunnable + { + nsRefPtr mThread; + + public: + FinishedRunnable(already_AddRefed aThread) + : mThread(aThread) + { + MOZ_ASSERT(mThread); + } + + NS_DECL_ISUPPORTS_INHERITED + + private: + ~FinishedRunnable() + { } + + NS_DECL_NSIRUNNABLE + }; public: - WorkerThreadRunnable(WorkerPrivate* aWorkerPrivate) - : mWorkerPrivate(aWorkerPrivate) + WorkerThreadPrimaryRunnable(WorkerPrivate* aWorkerPrivate, + RuntimeService::WorkerThread* aThread) + : mWorkerPrivate(aWorkerPrivate), mThread(aThread) { - NS_ASSERTION(mWorkerPrivate, "This should never be null!"); + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aThread); } - NS_IMETHOD - Run() + NS_DECL_ISUPPORTS_INHERITED + +private: + ~WorkerThreadPrimaryRunnable() + { } + + NS_DECL_NSIRUNNABLE +}; + +class WorkerTaskRunnable MOZ_FINAL : public WorkerRunnable +{ + nsRefPtr mTask; + +public: + WorkerTaskRunnable(WorkerPrivate* aWorkerPrivate, WorkerTask* aTask) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mTask(aTask) { -#ifdef MOZ_NUWA_PROCESS - if (IsNuwaProcess()) { - NS_ASSERTION(NuwaMarkCurrentThread != nullptr, - "NuwaMarkCurrentThread is undefined!"); - NuwaMarkCurrentThread(nullptr, nullptr); - NuwaFreezeCurrentThread(); - } -#endif - WorkerPrivate* workerPrivate = mWorkerPrivate; - mWorkerPrivate = nullptr; + MOZ_ASSERT(aTask); + } - workerPrivate->AssertIsOnWorkerThread(); +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + // May be called on any thread! + return true; + } - { - nsCycleCollector_startup(); + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE + { + // May be called on any thread! + } - WorkerJSRuntime runtime(workerPrivate); - JSRuntime* rt = runtime.Runtime(); - JSContext* cx = CreateJSContextForWorker(workerPrivate, rt); - if (!cx) { - // XXX need to fire an error at parent. - NS_ERROR("Failed to create runtime and context!"); - return NS_ERROR_FAILURE; - } - - char aLocal; - profiler_register_thread("WebWorker", &aLocal); - #ifdef MOZ_ENABLE_PROFILER_SPS - if (PseudoStack* stack = mozilla_get_pseudo_stack()) - stack->sampleRuntime(rt); - #endif - - { - JSAutoRequest ar(cx); - workerPrivate->DoRunLoop(cx); - } - - // Destroy the main context. This will unroot the main worker global and - // GC. This is not the last JSContext (WorkerJSRuntime maintains an - // internal JSContext). - JS_DestroyContext(cx); - - // Now WorkerJSRuntime goes out of scope and its destructor will shut - // down the cycle collector and destroy the final JSContext. This - // breaks any remaining cycles and collects the C++ and JS objects - // participating. - } - -#ifdef MOZ_ENABLE_PROFILER_SPS - if (PseudoStack* stack = mozilla_get_pseudo_stack()) - stack->sampleRuntime(nullptr); -#endif - - workerPrivate->ScheduleDeletion(false); - profiler_unregister_thread(); - return NS_OK; + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + return mTask->RunTask(aCx); } }; } /* anonymous namespace */ +class RuntimeService::WorkerThread MOZ_FINAL : public nsThread +{ + class Observer MOZ_FINAL : public nsIThreadObserver + { + WorkerPrivate* mWorkerPrivate; + + public: + Observer(WorkerPrivate* aWorkerPrivate) + : mWorkerPrivate(aWorkerPrivate) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + + NS_DECL_THREADSAFE_ISUPPORTS + + private: + ~Observer() + { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + + NS_DECL_NSITHREADOBSERVER + }; + + WorkerPrivate* mWorkerPrivate; + nsRefPtr mObserver; + +#ifdef DEBUG + // Protected by nsThread::mLock. + bool mAcceptingNonWorkerRunnables; +#endif + +public: + static already_AddRefed + Create(); + + void + SetWorker(WorkerPrivate* aWorkerPrivate); + + NS_DECL_ISUPPORTS_INHERITED + + NS_IMETHOD + Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) MOZ_OVERRIDE; + +#ifdef DEBUG + bool + IsAcceptingNonWorkerRunnables() + { + MutexAutoLock lock(mLock); + return mAcceptingNonWorkerRunnables; + } + + void + SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables) + { + MutexAutoLock lock(mLock); + mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables; + } +#endif + +private: + WorkerThread() + : nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE), + mWorkerPrivate(nullptr) +#ifdef DEBUG + , mAcceptingNonWorkerRunnables(true) +#endif + { } + + ~WorkerThread() + { } +}; + BEGIN_WORKERS_NAMESPACE // Entry point for main thread non-window globals. @@ -1113,71 +1143,64 @@ ResumeWorkersForWindow(nsPIDOMWindow* aWindow) } } -namespace { - -class WorkerTaskRunnable : public WorkerRunnable +WorkerCrossThreadDispatcher::WorkerCrossThreadDispatcher( + WorkerPrivate* aWorkerPrivate) +: mMutex("WorkerCrossThreadDispatcher::mMutex"), + mWorkerPrivate(aWorkerPrivate) { -public: - WorkerTaskRunnable(WorkerPrivate* aPrivate, WorkerTask* aTask) - : WorkerRunnable(aPrivate, WorkerThread, UnchangedBusyCount, - SkipWhenClearing), - mTask(aTask) - { } - - virtual bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { - return true; - } - - virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { } - - virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate); - -private: - nsRefPtr mTask; -}; - -bool -WorkerTaskRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) -{ - return mTask->RunTask(aCx); -} - + MOZ_ASSERT(aWorkerPrivate); } bool WorkerCrossThreadDispatcher::PostTask(WorkerTask* aTask) { - mozilla::MutexAutoLock lock(mMutex); - if (!mPrivate) { + MOZ_ASSERT(aTask); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + NS_WARNING("Posted a task to a WorkerCrossThreadDispatcher that is no " + "longer accepting tasks!"); return false; } - nsRefPtr runnable = new WorkerTaskRunnable(mPrivate, aTask); - runnable->Dispatch(nullptr); - return true; + nsRefPtr runnable = + new WorkerTaskRunnable(mWorkerPrivate, aTask); + return runnable->Dispatch(nullptr); } WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) { - NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); - return static_cast(JS_GetRuntimePrivate(JS_GetRuntime(aCx)))->mWorkerPrivate; + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aCx); + + JSRuntime* rt = JS_GetRuntime(aCx); + MOZ_ASSERT(rt); + + void* rtPrivate = JS_GetRuntimePrivate(rt); + MOZ_ASSERT(rtPrivate); + + return static_cast(rtPrivate)->mWorkerPrivate; } WorkerPrivate* GetCurrentThreadWorkerPrivate() { - MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!NS_IsMainThread()); + CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get(); if (!ccrt) { return nullptr; } JSRuntime* rt = ccrt->Runtime(); - return static_cast(JS_GetRuntimePrivate(rt))-> - mWorkerPrivate; + MOZ_ASSERT(rt); + + void* rtPrivate = JS_GetRuntimePrivate(rt); + MOZ_ASSERT(rtPrivate); + + return static_cast(rtPrivate)->mWorkerPrivate; } bool @@ -1427,7 +1450,7 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate) } if (!domainInfo->ActiveWorkerCount()) { - NS_ASSERTION(domainInfo->mQueuedWorkers.IsEmpty(), "Huh?!"); + MOZ_ASSERT(domainInfo->mQueuedWorkers.IsEmpty()); mDomainMap.Remove(domain); } } @@ -1455,16 +1478,11 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate) nsPIDOMWindow* window = aWorkerPrivate->GetWindow(); nsTArray* windowArray; - if (!mWindowMap.Get(window, &windowArray)) { - MOZ_ASSERT(false, "Don't have an entry for this window!"); - } + MOZ_ALWAYS_TRUE(mWindowMap.Get(window, &windowArray)); - if (!windowArray->RemoveElement(aWorkerPrivate)) { - MOZ_ASSERT(false, "Worker wasn't in the correct window array!"); - } + MOZ_ALWAYS_TRUE(windowArray->RemoveElement(aWorkerPrivate)); if (windowArray->IsEmpty()) { - MOZ_ASSERT(!queuedWorker, "queuedWorker should be in this array!"); mWindowMap.Remove(window); } } @@ -1482,7 +1500,7 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate) return true; } - nsCOMPtr thread; + nsRefPtr thread; { MutexAutoLock lock(mMutex); if (!mIdleThreadArray.IsEmpty()) { @@ -1493,35 +1511,36 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate) } if (!thread) { - if (NS_FAILED(NS_NewNamedThread("DOM Worker", - getter_AddRefs(thread), nullptr, - WORKER_STACK_SIZE))) { + thread = WorkerThread::Create(); + if (!thread) { UnregisterWorker(aCx, aWorkerPrivate); JS_ReportError(aCx, "Could not create new thread!"); return false; } } + MOZ_ASSERT(thread->IsAcceptingNonWorkerRunnables()); + int32_t priority = aWorkerPrivate->IsChromeWorker() ? nsISupportsPriority::PRIORITY_NORMAL : nsISupportsPriority::PRIORITY_LOW; - nsCOMPtr threadPriority = do_QueryInterface(thread); - if (!threadPriority || NS_FAILED(threadPriority->SetPriority(priority))) { + if (NS_FAILED(thread->SetPriority(priority))) { NS_WARNING("Could not set the thread's priority!"); } -#ifdef DEBUG - aWorkerPrivate->SetThread(thread); -#endif - - nsCOMPtr runnable = new WorkerThreadRunnable(aWorkerPrivate); + nsCOMPtr runnable = + new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread); if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) { UnregisterWorker(aCx, aWorkerPrivate); JS_ReportError(aCx, "Could not dispatch to thread!"); return false; } +#ifdef DEBUG + thread->SetAcceptingNonWorkerRunnables(false); +#endif + return true; } @@ -1541,7 +1560,7 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */) TimeStamp nextExpiration; - nsAutoTArray, 20> expiredThreads; + nsAutoTArray, 20> expiredThreads; { MutexAutoLock lock(runtime->mMutex); @@ -1553,7 +1572,7 @@ RuntimeService::ShutdownIdleThreads(nsITimer* aTimer, void* /* aClosure */) break; } - nsCOMPtr* thread = expiredThreads.AppendElement(); + nsRefPtr* thread = expiredThreads.AppendElement(); thread->swap(info.mThread); } @@ -1756,7 +1775,6 @@ RuntimeService::Shutdown() mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers); if (!workers.IsEmpty()) { - // Cancel all top-level workers. { MutexAutoUnlock unlock(mMutex); @@ -1803,7 +1821,7 @@ RuntimeService::Cleanup() // Shut down any idle threads. if (!mIdleThreadArray.IsEmpty()) { - nsAutoTArray, 20> idleThreads; + nsAutoTArray, 20> idleThreads; uint32_t idleThreadCount = mIdleThreadArray.Length(); idleThreads.SetLength(idleThreadCount); @@ -2186,10 +2204,14 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate) } void -RuntimeService::NoteIdleThread(nsIThread* aThread) +RuntimeService::NoteIdleThread(WorkerThread* aThread) { AssertIsOnMainThread(); - NS_ASSERTION(aThread, "Null pointer!"); + MOZ_ASSERT(aThread); + +#ifdef DEBUG + aThread->SetAcceptingNonWorkerRunnables(true); +#endif static TimeDuration timeout = TimeDuration::FromSeconds(IDLE_THREAD_TIMEOUT_SEC); @@ -2216,19 +2238,15 @@ RuntimeService::NoteIdleThread(nsIThread* aThread) // Too many idle threads, just shut this one down. if (shutdown) { - if (NS_FAILED(aThread->Shutdown())) { - NS_WARNING("Failed to shutdown thread!"); - } + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aThread->Shutdown())); return; } // Schedule timer. - if (NS_FAILED(mIdleThreadTimer-> - InitWithFuncCallback(ShutdownIdleThreads, nullptr, - IDLE_THREAD_TIMEOUT_SEC * 1000, - nsITimer::TYPE_ONE_SHOT))) { - NS_ERROR("Can't schedule timer!"); - } + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mIdleThreadTimer->InitWithFuncCallback( + ShutdownIdleThreads, nullptr, + IDLE_THREAD_TIMEOUT_SEC * 1000, + nsITimer::TYPE_ONE_SHOT))); } void @@ -2354,3 +2372,272 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure JS::CompartmentOptions& options = sDefaultJSSettings.content.compartmentOptions; options.setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT); } + +// static +already_AddRefed +RuntimeService::WorkerThread::Create() +{ + MOZ_ASSERT(nsThreadManager::get()); + + nsRefPtr thread = new WorkerThread(); + if (NS_FAILED(thread->Init())) { + NS_WARNING("Failed to create new thread!"); + return nullptr; + } + + NS_SetThreadName(thread, "DOM Worker"); + + return thread.forget(); +} + +void +RuntimeService::WorkerThread::SetWorker(WorkerPrivate* aWorkerPrivate) +{ + MOZ_ASSERT(PR_GetCurrentThread() == mThread); + MOZ_ASSERT_IF(aWorkerPrivate, !mWorkerPrivate); + MOZ_ASSERT_IF(!aWorkerPrivate, mWorkerPrivate); + + // No need to lock here because mWorkerPrivate is only modified on mThread. + + if (mWorkerPrivate) { + MOZ_ASSERT(mObserver); + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(RemoveObserver(mObserver))); + + mObserver = nullptr; + mWorkerPrivate->SetThread(nullptr); + } + + mWorkerPrivate = aWorkerPrivate; + + if (mWorkerPrivate) { + mWorkerPrivate->SetThread(this); + + nsRefPtr observer = new Observer(mWorkerPrivate); + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(AddObserver(observer))); + + mObserver.swap(observer); + } +} + +NS_IMPL_ISUPPORTS_INHERITED0(RuntimeService::WorkerThread, nsThread) + +NS_IMETHODIMP +RuntimeService::WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) +{ + // May be called on any thread! + +#ifdef DEBUG + if (PR_GetCurrentThread() == mThread) { + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + } + else if (aRunnable && !IsAcceptingNonWorkerRunnables()) { + // Only enforce cancelable runnables after we've started the worker loop. + nsCOMPtr cancelable = do_QueryInterface(aRunnable); + MOZ_ASSERT(cancelable, + "Should have been wrapped by the worker's event target!"); + } +#endif + + // Workers only support asynchronous dispatch for now. + if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) { + return NS_ERROR_UNEXPECTED; + } + + nsIRunnable* runnableToDispatch; + nsRefPtr workerRunnable; + + if (aRunnable && PR_GetCurrentThread() == mThread) { + // No need to lock here because mWorkerPrivate is only modified on mThread. + workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable); + runnableToDispatch = workerRunnable; + } + else { + runnableToDispatch = aRunnable; + } + + nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(RuntimeService::WorkerThread::Observer, nsIThreadObserver) + +NS_IMETHODIMP +RuntimeService::WorkerThread::Observer::OnDispatchedEvent( + nsIThreadInternal* /*aThread */) +{ + MOZ_ASSUME_UNREACHABLE("This should never be called!"); +} + +NS_IMETHODIMP +RuntimeService::WorkerThread::Observer::OnProcessNextEvent( + nsIThreadInternal* /* aThread */, + bool aMayWait, + uint32_t aRecursionDepth) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(!aMayWait); + + mWorkerPrivate->OnProcessNextEvent(aRecursionDepth); + return NS_OK; +} + +NS_IMETHODIMP +RuntimeService::WorkerThread::Observer::AfterProcessNextEvent( + nsIThreadInternal* /* aThread */, + uint32_t aRecursionDepth, + bool /* aEventWasProcessed */) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + mWorkerPrivate->AfterProcessNextEvent(aRecursionDepth); + return NS_OK; +} + +NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, nsRunnable) + +NS_IMETHODIMP +LogViolationDetailsRunnable::Run() +{ + AssertIsOnMainThread(); + + nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP(); + if (csp) { + NS_NAMED_LITERAL_STRING(scriptSample, + "Call to eval() or related function blocked by CSP."); + if (mWorkerPrivate->GetReportCSPViolations()) { + csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, + mFileName, scriptSample, mLineNum, + EmptyString()); + } + } + + nsRefPtr response = + new MainThreadStopSyncLoopRunnable(mWorkerPrivate, mSyncLoopTarget.forget(), + true); + MOZ_ALWAYS_TRUE(response->Dispatch(nullptr)); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable) + +NS_IMETHODIMP +WorkerThreadPrimaryRunnable::Run() +{ +#ifdef MOZ_NUWA_PROCESS + if (IsNuwaProcess()) { + NS_ASSERTION(NuwaMarkCurrentThread != nullptr, + "NuwaMarkCurrentThread is undefined!"); + NuwaMarkCurrentThread(nullptr, nullptr); + NuwaFreezeCurrentThread(); + } +#endif + + char stackBaseGuess; + + nsAutoCString threadName; + threadName.AssignLiteral("WebWorker '"); + threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL())); + threadName.Append('\''); + + profiler_register_thread(threadName.get(), &stackBaseGuess); + + mThread->SetWorker(mWorkerPrivate); + + mWorkerPrivate->AssertIsOnWorkerThread(); + + { + nsCycleCollector_startup(); + + WorkerJSRuntime runtime(mWorkerPrivate); + JSRuntime* rt = runtime.Runtime(); + + JSContext* cx = CreateJSContextForWorker(mWorkerPrivate, rt); + if (!cx) { + // XXX need to fire an error at parent. + NS_ERROR("Failed to create runtime and context!"); + return NS_ERROR_FAILURE; + } + + { +#ifdef MOZ_ENABLE_PROFILER_SPS + PseudoStack* stack = mozilla_get_pseudo_stack(); + if (stack) { + stack->sampleRuntime(rt); + } +#endif + + { + JSAutoRequest ar(cx); + + mWorkerPrivate->DoRunLoop(cx); + + JS_ReportPendingException(cx); + } + +#ifdef MOZ_ENABLE_PROFILER_SPS + if (stack) { + stack->sampleRuntime(nullptr); + } +#endif + } + + // Destroy the main context. This will unroot the main worker global and + // GC. This is not the last JSContext (WorkerJSRuntime maintains an + // internal JSContext). + JS_DestroyContext(cx); + + // Now WorkerJSRuntime goes out of scope and its destructor will shut + // down the cycle collector and destroy the final JSContext. This + // breaks any remaining cycles and collects the C++ and JS objects + // participating. + } + + mThread->SetWorker(nullptr); + + mWorkerPrivate->ScheduleDeletion(); + + // It is no longer safe to touch mWorkerPrivate. + mWorkerPrivate = nullptr; + + // Now recycle this thread. + nsCOMPtr mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + + nsRefPtr finishedRunnable = + new FinishedRunnable(mThread.forget()); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread->Dispatch(finishedRunnable, + NS_DISPATCH_NORMAL))); + + profiler_unregister_thread(); + return NS_OK; +} + +NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable, + nsRunnable) + +NS_IMETHODIMP +WorkerThreadPrimaryRunnable::FinishedRunnable::Run() +{ + AssertIsOnMainThread(); + + nsRefPtr thread; + mThread.swap(thread); + + RuntimeService* rts = RuntimeService::GetService(); + if (rts) { + rts->NoteIdleThread(thread); + } + else if (thread->ShutdownRequired()) { + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Shutdown())); + } + + return NS_OK; +} diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h index 79fe6139ce0d..57a17a59c33e 100644 --- a/dom/workers/RuntimeService.h +++ b/dom/workers/RuntimeService.h @@ -11,18 +11,13 @@ #include "nsIObserver.h" -#include "mozilla/Attributes.h" -#include "mozilla/Mutex.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/BindingDeclarations.h" -#include "nsAutoPtr.h" #include "nsClassHashtable.h" -#include "nsCOMPtr.h" -#include "nsCycleCollectionParticipant.h" #include "nsHashKeys.h" -#include "nsString.h" #include "nsTArray.h" +class nsIRunnable; class nsIThread; class nsITimer; class nsPIDOMWindow; @@ -34,6 +29,10 @@ class WorkerPrivate; class RuntimeService MOZ_FINAL : public nsIObserver { +public: + class WorkerThread; + +private: struct SharedWorkerInfo { WorkerPrivate* mWorkerPrivate; @@ -68,7 +67,7 @@ class RuntimeService MOZ_FINAL : public nsIObserver struct IdleThreadInfo { - nsCOMPtr mThread; + nsRefPtr mThread; mozilla::TimeStamp mExpirationTime; }; @@ -173,7 +172,7 @@ public: } void - NoteIdleThread(nsIThread* aThread); + NoteIdleThread(WorkerThread* aThread); static void GetDefaultJSSettings(JSSettings& aSettings) diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index edee86a8eada..5d1fae8dada4 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -35,6 +35,7 @@ #include "Principal.h" #include "WorkerFeature.h" #include "WorkerPrivate.h" +#include "WorkerRunnable.h" #define MAX_CONCURRENT_SCRIPTS 1000 @@ -131,8 +132,6 @@ ChannelFromScriptURL(nsIPrincipal* principal, return rv; } -class ScriptLoaderRunnable; - struct ScriptLoadInfo { ScriptLoadInfo() @@ -155,7 +154,9 @@ struct ScriptLoadInfo bool mExecutionResult; }; -class ScriptExecutorRunnable : public WorkerSyncRunnable +class ScriptLoaderRunnable; + +class ScriptExecutorRunnable MOZ_FINAL : public MainThreadWorkerSyncRunnable { ScriptLoaderRunnable& mScriptLoader; uint32_t mFirstIndex; @@ -163,38 +164,29 @@ class ScriptExecutorRunnable : public WorkerSyncRunnable public: ScriptExecutorRunnable(ScriptLoaderRunnable& aScriptLoader, - uint32_t aSyncQueueKey, uint32_t aFirstIndex, + nsIEventTarget* aSyncLoopTarget, uint32_t aFirstIndex, uint32_t aLastIndex); - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - AssertIsOnMainThread(); - return true; - } +private: + ~ScriptExecutorRunnable() + { } - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - AssertIsOnMainThread(); - } + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate); - - void - PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); + virtual void + PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) + MOZ_OVERRIDE; }; -class ScriptLoaderRunnable : public WorkerFeature, - public nsIRunnable, - public nsIStreamLoaderObserver +class ScriptLoaderRunnable MOZ_FINAL : public WorkerFeature, + public nsIRunnable, + public nsIStreamLoaderObserver { friend class ScriptExecutorRunnable; WorkerPrivate* mWorkerPrivate; - uint32_t mSyncQueueKey; + nsCOMPtr mSyncLoopTarget; nsTArray mLoadInfos; bool mIsWorkerScript; bool mCanceled; @@ -204,21 +196,26 @@ public: NS_DECL_THREADSAFE_ISUPPORTS ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate, - uint32_t aSyncQueueKey, + nsIEventTarget* aSyncLoopTarget, nsTArray& aLoadInfos, bool aIsWorkerScript) - : mWorkerPrivate(aWorkerPrivate), mSyncQueueKey(aSyncQueueKey), + : mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget), mIsWorkerScript(aIsWorkerScript), mCanceled(false), mCanceledMainThread(false) { aWorkerPrivate->AssertIsOnWorkerThread(); - NS_ASSERTION(!aIsWorkerScript || aLoadInfos.Length() == 1, "Bad args!"); + MOZ_ASSERT(aSyncLoopTarget); + MOZ_ASSERT_IF(aIsWorkerScript, aLoadInfos.Length() == 1); mLoadInfos.SwapElements(aLoadInfos); } +private: + ~ScriptLoaderRunnable() + { } + NS_IMETHOD - Run() + Run() MOZ_OVERRIDE { AssertIsOnMainThread(); @@ -232,7 +229,7 @@ public: NS_IMETHOD OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext, nsresult aStatus, uint32_t aStringLen, - const uint8_t* aString) + const uint8_t* aString) MOZ_OVERRIDE { AssertIsOnMainThread(); @@ -256,8 +253,8 @@ public: return NS_OK; } - bool - Notify(JSContext* aCx, Status aStatus) + virtual bool + Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE { mWorkerPrivate->AssertIsOnWorkerThread(); @@ -587,9 +584,10 @@ public: if (firstIndex != UINT32_MAX && lastIndex != UINT32_MAX) { nsRefPtr runnable = - new ScriptExecutorRunnable(*this, mSyncQueueKey, firstIndex, lastIndex); + new ScriptExecutorRunnable(*this, mSyncLoopTarget, firstIndex, + lastIndex); if (!runnable->Dispatch(nullptr)) { - NS_ERROR("This should never fail!"); + MOZ_ASSERT(false, "This should never fail!"); } } } @@ -597,45 +595,26 @@ public: NS_IMPL_ISUPPORTS2(ScriptLoaderRunnable, nsIRunnable, nsIStreamLoaderObserver) -class StopSyncLoopRunnable MOZ_FINAL : public MainThreadSyncRunnable -{ -public: - StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate, - uint32_t aSyncQueueKey) - : MainThreadSyncRunnable(aWorkerPrivate, SkipWhenClearing, aSyncQueueKey, - false) - { } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE - { - aWorkerPrivate->AssertIsOnWorkerThread(); - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true); - return true; - } -}; - class ChannelGetterRunnable MOZ_FINAL : public nsRunnable { WorkerPrivate* mParentWorker; - uint32_t mSyncQueueKey; + nsCOMPtr mSyncLoopTarget; const nsAString& mScriptURL; nsIChannel** mChannel; nsresult mResult; public: ChannelGetterRunnable(WorkerPrivate* aParentWorker, - uint32_t aSyncQueueKey, + nsIEventTarget* aSyncLoopTarget, const nsAString& aScriptURL, nsIChannel** aChannel) - : mParentWorker(aParentWorker), mSyncQueueKey(aSyncQueueKey), + : mParentWorker(aParentWorker), mSyncLoopTarget(aSyncLoopTarget), mScriptURL(aScriptURL), mChannel(aChannel), mResult(NS_ERROR_FAILURE) { aParentWorker->AssertIsOnWorkerThread(); + MOZ_ASSERT(aSyncLoopTarget); } - virtual ~ChannelGetterRunnable() { } - NS_IMETHOD Run() MOZ_OVERRIDE { @@ -660,8 +639,9 @@ public: channel.forget(mChannel); } - nsRefPtr runnable = - new StopSyncLoopRunnable(mParentWorker, mSyncQueueKey); + nsRefPtr runnable = + new MainThreadStopSyncLoopRunnable(mParentWorker, + mSyncLoopTarget.forget(), true); if (!runnable->Dispatch(nullptr)) { NS_ERROR("This should never fail!"); } @@ -675,19 +655,21 @@ public: return mResult; } +private: + virtual ~ChannelGetterRunnable() + { } }; ScriptExecutorRunnable::ScriptExecutorRunnable( ScriptLoaderRunnable& aScriptLoader, - uint32_t aSyncQueueKey, + nsIEventTarget* aSyncLoopTarget, uint32_t aFirstIndex, uint32_t aLastIndex) -: WorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncQueueKey), +: MainThreadWorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncLoopTarget), mScriptLoader(aScriptLoader), mFirstIndex(aFirstIndex), mLastIndex(aLastIndex) { - NS_ASSERTION(aFirstIndex <= aLastIndex, "Bad first index!"); - NS_ASSERTION(aLastIndex < aScriptLoader.mLoadInfos.Length(), - "Bad last index!"); + MOZ_ASSERT(aFirstIndex <= aLastIndex); + MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length()); } bool @@ -759,7 +741,7 @@ ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, } aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader); - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, result); + aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, result); } } @@ -773,7 +755,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate, AutoSyncLoopHolder syncLoop(aWorkerPrivate); nsRefPtr loader = - new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.SyncQueueKey(), + new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(), aLoadInfos, aIsWorkerScript); NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!"); @@ -789,7 +771,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate, return false; } - return syncLoop.RunAndForget(aCx); + return syncLoop.Run(); } } /* anonymous namespace */ @@ -832,15 +814,15 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx, AutoSyncLoopHolder syncLoop(aParent); nsRefPtr getter = - new ChannelGetterRunnable(aParent, syncLoop.SyncQueueKey(), - aScriptURL, aChannel); + new ChannelGetterRunnable(aParent, syncLoop.EventTarget(), aScriptURL, + aChannel); if (NS_FAILED(NS_DispatchToMainThread(getter, NS_DISPATCH_NORMAL))) { NS_ERROR("Failed to dispatch!"); return NS_ERROR_FAILURE; } - if (!syncLoop.RunAndForget(aCx)) { + if (!syncLoop.Run()) { return NS_ERROR_FAILURE; } diff --git a/dom/workers/URL.cpp b/dom/workers/URL.cpp index d9b69ff67978..96bc2a826714 100644 --- a/dom/workers/URL.cpp +++ b/dom/workers/URL.cpp @@ -4,24 +4,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "URL.h" -#include "File.h" - -#include "WorkerPrivate.h" -#include "nsThreadUtils.h" - -#include "nsPIDOMWindow.h" -#include "nsGlobalWindow.h" -#include "nsHostObjectProtocolHandler.h" -#include "nsServiceManagerUtils.h" #include "nsIDocument.h" #include "nsIDOMFile.h" +#include "nsIIOService.h" +#include "nsPIDOMWindow.h" #include "mozilla/dom/URL.h" #include "mozilla/dom/URLBinding.h" #include "mozilla/dom/URLSearchParams.h" -#include "nsIIOService.h" +#include "nsGlobalWindow.h" +#include "nsHostObjectProtocolHandler.h" #include "nsNetCID.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" + +#include "File.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" BEGIN_WORKERS_NAMESPACE using mozilla::dom::GlobalObject; @@ -67,43 +67,7 @@ class URLRunnable : public nsRunnable { protected: WorkerPrivate* mWorkerPrivate; - uint32_t mSyncQueueKey; - -private: - class ResponseRunnable : public WorkerSyncRunnable - { - uint32_t mSyncQueueKey; - - public: - ResponseRunnable(WorkerPrivate* aWorkerPrivate, - uint32_t aSyncQueueKey) - : WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, false), - mSyncQueueKey(aSyncQueueKey) - { - NS_ASSERTION(aWorkerPrivate, "Don't hand me a null WorkerPrivate!"); - } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true); - return true; - } - - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - AssertIsOnMainThread(); - return true; - } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - AssertIsOnMainThread(); - } - }; + nsCOMPtr mSyncLoopTarget; protected: URLRunnable(WorkerPrivate* aWorkerPrivate) @@ -117,15 +81,17 @@ public: Dispatch(JSContext* aCx) { mWorkerPrivate->AssertIsOnWorkerThread(); + AutoSyncLoopHolder syncLoop(mWorkerPrivate); - mSyncQueueKey = syncLoop.SyncQueueKey(); + + mSyncLoopTarget = syncLoop.EventTarget(); if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { JS_ReportError(aCx, "Failed to dispatch to main thread!"); return false; } - return syncLoop.RunAndForget(aCx); + return syncLoop.Run(); } private: @@ -135,8 +101,10 @@ private: MainThreadRun(); - nsRefPtr response = - new ResponseRunnable(mWorkerPrivate, mSyncQueueKey); + nsRefPtr response = + new MainThreadStopSyncLoopRunnable(mWorkerPrivate, + mSyncLoopTarget.forget(), + true); if (!response->Dispatch(nullptr)) { NS_WARNING("Failed to dispatch response!"); } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index f89f14a88165..bd8f60bea70d 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -23,6 +23,7 @@ #include "nsIScriptSecurityManager.h" #include "nsPIDOMWindow.h" #include "nsITextToSubURI.h" +#include "nsIThreadInternal.h" #include "nsITimer.h" #include "nsIURI.h" #include "nsIURL.h" @@ -32,11 +33,13 @@ #include "jsfriendapi.h" #include "js/OldDebugAPI.h" #include "js/MemoryMetrics.h" +#include "mozilla/Assertions.h" #include "mozilla/ContentEvents.h" #include "mozilla/Likely.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ErrorEvent.h" #include "mozilla/dom/ErrorEventBinding.h" +#include "mozilla/dom/Exceptions.h" #include "mozilla/dom/FunctionBinding.h" #include "mozilla/dom/ImageData.h" #include "mozilla/dom/ImageDataBinding.h" @@ -64,7 +67,10 @@ #include #endif -#include "mozilla/dom/Exceptions.h" +#ifdef DEBUG +#include "nsThreadManager.h" +#endif + #include "File.h" #include "MessagePort.h" #include "Principal.h" @@ -72,32 +78,53 @@ #include "ScriptLoader.h" #include "SharedWorker.h" #include "WorkerFeature.h" +#include "WorkerRunnable.h" #include "WorkerScope.h" -// GC will run once every thirty seconds during normal execution. -#define NORMAL_GC_TIMER_DELAY_MS 30000 +// JS_MaybeGC will run once every second during normal execution. +#define PERIODIC_GC_TIMER_DELAY_SEC 1 -// GC will run five seconds after the last event is processed. -#define IDLE_GC_TIMER_DELAY_MS 5000 +// A shrinking GC will run five seconds after the last event is processed. +#define IDLE_GC_TIMER_DELAY_SEC 5 #define PREF_WORKERS_ENABLED "dom.workers.enabled" -using mozilla::InternalScriptErrorEvent; -using mozilla::MutexAutoLock; -using mozilla::TimeDuration; -using mozilla::TimeStamp; -using mozilla::dom::Throw; -using mozilla::AutoCxPusher; -using mozilla::AutoPushJSContext; -using mozilla::AutoSafeJSContext; +#ifdef WORKER_LOGGING +#define LOG(_args) do { printf _args ; fflush(stdout); } while (0) +#else +#define LOG(_args) do { } while (0) +#endif -USING_WORKERS_NAMESPACE +using namespace mozilla; using namespace mozilla::dom; +USING_WORKERS_NAMESPACE MOZ_DEFINE_MALLOC_SIZE_OF(JsWorkerMallocSizeOf) +#ifdef DEBUG + +BEGIN_WORKERS_NAMESPACE + +void +AssertIsOnMainThread() +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); +} + +END_WORKERS_NAMESPACE + +#endif + namespace { +#ifdef DEBUG + +const nsIID kDEBUGWorkerEventTargetIID = { + 0xccaba3fa, 0x5be2, 0x4de2, { 0xba, 0x87, 0x3b, 0x3b, 0x5b, 0x1d, 0x5, 0xfb } +}; + +#endif + template class AutoPtrComparator { @@ -142,6 +169,51 @@ SwapToISupportsArray(SmartPtr& aSrc, dest->swap(rawSupports); } +// This class is used to wrap any runnables that the worker receives via the +// nsIEventTarget::Dispatch() method (either from NS_DispatchToCurrentThread or +// from the worker's EventTarget). +class ExternalRunnableWrapper MOZ_FINAL : public WorkerRunnable +{ + nsCOMPtr mWrappedRunnable; + +public: + ExternalRunnableWrapper(WorkerPrivate* aWorkerPrivate, + nsICancelableRunnable* aWrappedRunnable) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), + mWrappedRunnable(aWrappedRunnable) + { + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aWrappedRunnable); + } + + NS_DECL_ISUPPORTS_INHERITED + +private: + ~ExternalRunnableWrapper() + { } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + nsresult rv = mWrappedRunnable->Run(); + if (NS_FAILED(rv)) { + if (!JS_IsExceptionPending(aCx)) { + Throw(aCx, rv); + } + return false; + } + return true; + } + + NS_IMETHOD + Cancel() MOZ_OVERRIDE + { + nsresult rv = mWrappedRunnable->Cancel(); + nsresult rv2 = WorkerRunnable::Cancel(); + return NS_FAILED(rv) ? rv : rv2; + } +}; + struct WindowAction { nsPIDOMWindow* mWindow; @@ -623,87 +695,75 @@ JSStructuredCloneCallbacks gMainThreadChromeWorkerStructuredCloneCallbacks = { MainThreadChromeWorkerStructuredCloneCallbacks::Error }; -class MainThreadReleaseRunnable : public nsRunnable +class MainThreadReleaseRunnable MOZ_FINAL : public nsRunnable { - nsCOMPtr mThread; - nsTArray > mDoomed; + nsTArray> mDoomed; nsTArray mHostObjectURIs; public: - MainThreadReleaseRunnable(nsCOMPtr& aThread, - nsTArray >& aDoomed, + MainThreadReleaseRunnable(nsTArray>& aDoomed, nsTArray& aHostObjectURIs) { - mThread.swap(aThread); mDoomed.SwapElements(aDoomed); mHostObjectURIs.SwapElements(aHostObjectURIs); } - MainThreadReleaseRunnable(nsTArray >& aDoomed, - nsTArray& aHostObjectURIs) - { - mDoomed.SwapElements(aDoomed); - mHostObjectURIs.SwapElements(aHostObjectURIs); - } + NS_DECL_ISUPPORTS_INHERITED NS_IMETHOD - Run() + Run() MOZ_OVERRIDE { mDoomed.Clear(); - if (mThread) { - RuntimeService* runtime = RuntimeService::GetService(); - NS_ASSERTION(runtime, "This should never be null!"); - - runtime->NoteIdleThread(mThread); - } - - for (uint32_t i = 0, len = mHostObjectURIs.Length(); i < len; ++i) { - nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs[i]); + for (uint32_t index = 0; index < mHostObjectURIs.Length(); index++) { + nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs[index]); } return NS_OK; } + +private: + ~MainThreadReleaseRunnable() + { } }; -class WorkerFinishedRunnable : public WorkerControlRunnable +class WorkerFinishedRunnable MOZ_FINAL : public WorkerControlRunnable { WorkerPrivate* mFinishedWorker; - nsCOMPtr mThread; public: WorkerFinishedRunnable(WorkerPrivate* aWorkerPrivate, - WorkerPrivate* aFinishedWorker, - nsIThread* aFinishedThread) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), - mFinishedWorker(aFinishedWorker), mThread(aFinishedThread) + WorkerPrivate* aFinishedWorker) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), + mFinishedWorker(aFinishedWorker) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // Silence bad assertions. return true; } - void + virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) + bool aDispatchResult) MOZ_OVERRIDE { // Silence bad assertions. } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { - nsTArray > doomed; + nsTArray> doomed; mFinishedWorker->ForgetMainThreadObjects(doomed); nsTArray hostObjectURIs; mFinishedWorker->StealHostObjectURIs(hostObjectURIs); nsRefPtr runnable = - new MainThreadReleaseRunnable(mThread, doomed, hostObjectURIs); + new MainThreadReleaseRunnable(doomed, hostObjectURIs); if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) { NS_WARNING("Failed to dispatch, going to leak!"); } @@ -720,21 +780,22 @@ public: } }; -class TopLevelWorkerFinishedRunnable : public nsRunnable +class TopLevelWorkerFinishedRunnable MOZ_FINAL : public nsRunnable { WorkerPrivate* mFinishedWorker; - nsCOMPtr mThread; public: - TopLevelWorkerFinishedRunnable(WorkerPrivate* aFinishedWorker, - nsIThread* aFinishedThread) - : mFinishedWorker(aFinishedWorker), mThread(aFinishedThread) + TopLevelWorkerFinishedRunnable(WorkerPrivate* aFinishedWorker) + : mFinishedWorker(aFinishedWorker) { aFinishedWorker->AssertIsOnWorkerThread(); } + NS_DECL_ISUPPORTS_INHERITED + +private: NS_IMETHOD - Run() + Run() MOZ_OVERRIDE { AssertIsOnMainThread(); @@ -760,34 +821,32 @@ public: NS_WARNING("Failed to dispatch, going to leak!"); } - if (mThread) { - runtime->NoteIdleThread(mThread); - } - mFinishedWorker->Release(); return NS_OK; } }; -class ModifyBusyCountRunnable : public WorkerControlRunnable +class ModifyBusyCountRunnable MOZ_FINAL : public WorkerControlRunnable { bool mIncrease; public: ModifyBusyCountRunnable(WorkerPrivate* aWorkerPrivate, bool aIncrease) - : WorkerControlRunnable(aWorkerPrivate, ParentThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), mIncrease(aIncrease) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { return aWorkerPrivate->ModifyBusyCount(aCx, mIncrease); } - void + virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) + MOZ_OVERRIDE { if (mIncrease) { WorkerControlRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); @@ -798,16 +857,16 @@ public: } }; -class CompileScriptRunnable : public WorkerRunnable +class CompileScriptRunnable MOZ_FINAL : public WorkerRunnable { public: CompileScriptRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerRunnable(aWorkerPrivate, WorkerThread, ModifyBusyCount, - SkipWhenClearing) + : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { JS::Rooted global(aCx, aWorkerPrivate->CreateGlobalScope(aCx)); @@ -821,16 +880,29 @@ public: } }; -class CloseEventRunnable : public WorkerRunnable +class CloseEventRunnable MOZ_FINAL : public WorkerRunnable { public: CloseEventRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount, - SkipWhenClearing) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + MOZ_ASSUME_UNREACHABLE("Don't call Dispatch() on CloseEventRunnable!"); + } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE + { + MOZ_ASSUME_UNREACHABLE("Don't call Dispatch() on CloseEventRunnable!"); + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { JS::Rooted target(aCx, JS::CurrentGlobalOrNull(aCx)); NS_ASSERTION(target, "This must never be null!"); @@ -842,10 +914,16 @@ public: nsCOMPtr event; nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, false); + if (NS_FAILED(rv)) { + Throw(aCx, rv); + return false; + } rv = event->InitEvent(NS_LITERAL_STRING("close"), false, false); - NS_ENSURE_SUCCESS(rv, false); + if (NS_FAILED(rv)) { + Throw(aCx, rv); + return false; + } event->SetTrusted(true); @@ -854,8 +932,9 @@ public: return true; } - void + virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) + MOZ_OVERRIDE { // Report errors. WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); @@ -869,7 +948,7 @@ public: } }; -class MessageEventRunnable : public WorkerRunnable +class MessageEventRunnable MOZ_FINAL : public WorkerRunnable { JSAutoStructuredCloneBuffer mBuffer; nsTArray > mClonedObjects; @@ -877,14 +956,12 @@ class MessageEventRunnable : public WorkerRunnable bool mToMessagePort; public: - MessageEventRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget, + MessageEventRunnable(WorkerPrivate* aWorkerPrivate, + TargetAndBusyBehavior aBehavior, JSAutoStructuredCloneBuffer& aData, nsTArray >& aClonedObjects, bool aToMessagePort, uint64_t aMessagePortSerial) - : WorkerRunnable(aWorkerPrivate, aTarget, aTarget == WorkerThread ? - ModifyBusyCount : - UnchangedBusyCount, - SkipWhenClearing), + : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePortSerial(aMessagePortSerial), mToMessagePort(aToMessagePort) { mBuffer.swap(aData); @@ -931,12 +1008,13 @@ public: return true; } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { MOZ_ASSERT_IF(mToMessagePort, aWorkerPrivate->IsSharedWorker()); - if (mTarget == ParentThread) { + if (mBehavior == ParentThreadUnchangedBusyCount) { // Don't fire this event if the JS object has been disconnected from the // private object. if (!aWorkerPrivate->IsAcceptingEvents()) { @@ -963,6 +1041,7 @@ public: } MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx)); + if (mToMessagePort) { nsRefPtr port = aWorkerPrivate->GetMessagePort(mMessagePortSerial); @@ -976,43 +1055,33 @@ public: return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(), false); } - - void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) - { - WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); - } }; -class NotifyRunnable : public WorkerControlRunnable +class NotifyRunnable MOZ_FINAL : public WorkerControlRunnable { Status mStatus; public: NotifyRunnable(WorkerPrivate* aWorkerPrivate, Status aStatus) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mStatus(aStatus) { - NS_ASSERTION(aStatus == Terminating || aStatus == Canceling || - aStatus == Killing, "Bad status!"); + MOZ_ASSERT(aStatus == Terminating || aStatus == Canceling || + aStatus == Killing); } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // Modify here, but not in PostRun! This busy count addition will be matched // by the CloseEventRunnable. return aWorkerPrivate->ModifyBusyCount(aCx, true); } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - return aWorkerPrivate->NotifyInternal(aCx, mStatus); - } - - void + virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) + bool aDispatchResult) MOZ_OVERRIDE { if (!aDispatchResult) { // We couldn't dispatch to the worker, which means it's already dead. @@ -1020,17 +1089,24 @@ public: aWorkerPrivate->ModifyBusyCount(aCx, false); } } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + return aWorkerPrivate->NotifyInternal(aCx, mStatus); + } }; class CloseRunnable MOZ_FINAL : public WorkerControlRunnable { public: CloseRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerControlRunnable(aWorkerPrivate, ParentThread, UnchangedBusyCount) + : WorkerControlRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // This busy count will be matched by the CloseEventRunnable. return aWorkerPrivate->ModifyBusyCount(aCx, true) && @@ -1038,35 +1114,37 @@ public: } }; -class SuspendRunnable : public WorkerControlRunnable +class SuspendRunnable MOZ_FINAL : public WorkerControlRunnable { public: SuspendRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { return aWorkerPrivate->SuspendInternal(aCx); } }; -class ResumeRunnable : public WorkerControlRunnable +class ResumeRunnable MOZ_FINAL : public WorkerControlRunnable { public: ResumeRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { return aWorkerPrivate->ResumeInternal(aCx); } }; -class ReportErrorRunnable : public WorkerRunnable +class ReportErrorRunnable MOZ_FINAL : public WorkerRunnable { nsString mMessage; nsString mFilename; @@ -1077,77 +1155,6 @@ class ReportErrorRunnable : public WorkerRunnable uint32_t mErrorNumber; public: - ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage, - const nsString& aFilename, const nsString& aLine, - uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags, uint32_t aErrorNumber) - : WorkerRunnable(aWorkerPrivate, ParentThread, UnchangedBusyCount, - SkipWhenClearing), - mMessage(aMessage), mFilename(aFilename), mLine(aLine), - mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), - mErrorNumber(aErrorNumber) - { } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - aWorkerPrivate->AssertIsOnWorkerThread(); - - // Dispatch may fail if the worker was canceled, no need to report that as - // an error, so don't call base class PostDispatch. - } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - // Don't fire this event if the JS object has been disconnected from the - // private object. - if (!aWorkerPrivate->IsAcceptingEvents()) { - return true; - } - - JS::Rooted target(aCx, aWorkerPrivate->GetWrapper()); - - uint64_t innerWindowId; - bool fireAtScope = true; - - WorkerPrivate* parent = aWorkerPrivate->GetParent(); - if (parent) { - innerWindowId = 0; - } - else { - AssertIsOnMainThread(); - - if (aWorkerPrivate->IsSuspended()) { - aWorkerPrivate->QueueRunnable(this); - return true; - } - - if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, - mLine, mLineNumber, - mColumnNumber, mFlags); - return true; - } - - aWorkerPrivate->AssertInnerWindowIsCorrect(); - - innerWindowId = aWorkerPrivate->GetInnerWindowId(); - } - - return ReportErrorRunnable::ReportError(aCx, parent, fireAtScope, - aWorkerPrivate, mMessage, - mFilename, mLine, mLineNumber, - mColumnNumber, mFlags, - mErrorNumber, innerWindowId); - } - - void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) - { - WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); - } - // aWorkerPrivate is the worker thread we're on (or the main thread, if null) // aTarget is the worker object that we are going to fire an error at // (if any). @@ -1263,32 +1270,96 @@ public: aFlags, aInnerWindowId); return true; } + +private: + ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage, + const nsString& aFilename, const nsString& aLine, + uint32_t aLineNumber, uint32_t aColumnNumber, + uint32_t aFlags, uint32_t aErrorNumber) + : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), + mMessage(aMessage), mFilename(aFilename), mLine(aLine), + mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), + mErrorNumber(aErrorNumber) + { } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE + { + aWorkerPrivate->AssertIsOnWorkerThread(); + + // Dispatch may fail if the worker was canceled, no need to report that as + // an error, so don't call base class PostDispatch. + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + // Don't fire this event if the JS object has been disconnected from the + // private object. + if (!aWorkerPrivate->IsAcceptingEvents()) { + return true; + } + + JS::Rooted target(aCx, aWorkerPrivate->GetWrapper()); + + uint64_t innerWindowId; + bool fireAtScope = true; + + WorkerPrivate* parent = aWorkerPrivate->GetParent(); + if (parent) { + innerWindowId = 0; + } + else { + AssertIsOnMainThread(); + + if (aWorkerPrivate->IsSuspended()) { + aWorkerPrivate->QueueRunnable(this); + return true; + } + + if (aWorkerPrivate->IsSharedWorker()) { + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, + mLine, mLineNumber, + mColumnNumber, mFlags); + return true; + } + + aWorkerPrivate->AssertInnerWindowIsCorrect(); + + innerWindowId = aWorkerPrivate->GetInnerWindowId(); + } + + return ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage, + mFilename, mLine, mLineNumber, mColumnNumber, mFlags, + mErrorNumber, innerWindowId); + } }; -class TimerRunnable : public WorkerRunnable +class TimerRunnable MOZ_FINAL : public WorkerRunnable { public: TimerRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount, - SkipWhenClearing) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // Silence bad assertions. return true; } - void + virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) + bool aDispatchResult) MOZ_OVERRIDE { // Silence bad assertions. } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { return aWorkerPrivate->RunExpiredTimeouts(aCx); } @@ -1300,24 +1371,31 @@ DummyCallback(nsITimer* aTimer, void* aClosure) // Nothing! } -class WorkerRunnableEventTarget MOZ_FINAL : public nsIEventTarget +class TimerThreadEventTarget MOZ_FINAL : public nsIEventTarget { -protected: + WorkerPrivate* mWorkerPrivate; nsRefPtr mWorkerRunnable; public: - WorkerRunnableEventTarget(WorkerRunnable* aWorkerRunnable) - : mWorkerRunnable(aWorkerRunnable) - { } + TimerThreadEventTarget(WorkerPrivate* aWorkerPrivate, + WorkerRunnable* aWorkerRunnable) + : mWorkerPrivate(aWorkerPrivate), mWorkerRunnable(aWorkerRunnable) + { + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aWorkerRunnable); + } NS_DECL_THREADSAFE_ISUPPORTS +protected: NS_IMETHOD - Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) + Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) MOZ_OVERRIDE { - NS_ASSERTION(aFlags == nsIEventTarget::DISPATCH_NORMAL, "Don't call me!"); + // This should only happen on the timer thread. + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aFlags == nsIEventTarget::DISPATCH_NORMAL); - nsRefPtr kungFuDeathGrip = this; + nsRefPtr kungFuDeathGrip = this; // Run the runnable we're given now (should just call DummyCallback()), // otherwise the timer thread will leak it... If we run this after @@ -1332,42 +1410,47 @@ public: } NS_IMETHOD - IsOnCurrentThread(bool* aIsOnCurrentThread) + IsOnCurrentThread(bool* aIsOnCurrentThread) MOZ_OVERRIDE { - *aIsOnCurrentThread = false; + MOZ_ASSERT(aIsOnCurrentThread); + + nsresult rv = mWorkerPrivate->IsOnCurrentThread(aIsOnCurrentThread); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; } }; -NS_IMPL_ISUPPORTS1(WorkerRunnableEventTarget, nsIEventTarget) - -class KillCloseEventRunnable : public WorkerRunnable +class KillCloseEventRunnable MOZ_FINAL : public WorkerRunnable { nsCOMPtr mTimer; - class KillScriptRunnable : public WorkerControlRunnable + class KillScriptRunnable MOZ_FINAL : public WorkerControlRunnable { public: KillScriptRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { - // Silence bad assertions. + // Silence bad assertions, this is dispatched from the timer thread. return true; } - void + virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) + bool aDispatchResult) MOZ_OVERRIDE { - // Silence bad assertions. + // Silence bad assertions, this is dispatched from the timer thread. } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // Kill running script. return false; @@ -1376,24 +1459,9 @@ class KillCloseEventRunnable : public WorkerRunnable public: KillCloseEventRunnable(WorkerPrivate* aWorkerPrivate) - : WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount, - SkipWhenClearing) + : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) { } - ~KillCloseEventRunnable() - { - if (mTimer) { - mTimer->Cancel(); - } - } - - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - NS_NOTREACHED("Not meant to be dispatched!"); - return false; - } - bool SetTimeout(JSContext* aCx, uint32_t aDelayMS) { @@ -1406,8 +1474,8 @@ public: nsRefPtr runnable = new KillScriptRunnable(mWorkerPrivate); - nsRefPtr target = - new WorkerRunnableEventTarget(runnable); + nsRefPtr target = + new TimerThreadEventTarget(mWorkerPrivate, runnable); if (NS_FAILED(timer->SetTarget(target))) { JS_ReportError(aCx, "Failed to set timer's target!"); @@ -1424,8 +1492,29 @@ public: return true; } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + ~KillCloseEventRunnable() + { + if (mTimer) { + mTimer->Cancel(); + } + } + + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + MOZ_ASSUME_UNREACHABLE("Don't call Dispatch() on KillCloseEventRunnable!"); + } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE + { + MOZ_ASSUME_UNREACHABLE("Don't call Dispatch() on KillCloseEventRunnable!"); + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { if (mTimer) { mTimer->Cancel(); @@ -1436,7 +1525,7 @@ public: } }; -class UpdateJSContextOptionsRunnable : public WorkerControlRunnable +class UpdateJSContextOptionsRunnable MOZ_FINAL : public WorkerControlRunnable { JS::ContextOptions mContentOptions; JS::ContextOptions mChromeOptions; @@ -1445,12 +1534,13 @@ public: UpdateJSContextOptionsRunnable(WorkerPrivate* aWorkerPrivate, const JS::ContextOptions& aContentOptions, const JS::ContextOptions& aChromeOptions) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mContentOptions(aContentOptions), mChromeOptions(aChromeOptions) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->UpdateJSContextOptionsInternal(aCx, mContentOptions, mChromeOptions); @@ -1458,7 +1548,7 @@ public: } }; -class UpdatePreferenceRunnable : public WorkerControlRunnable +class UpdatePreferenceRunnable MOZ_FINAL : public WorkerControlRunnable { WorkerPreference mPref; bool mValue; @@ -1467,21 +1557,21 @@ public: UpdatePreferenceRunnable(WorkerPrivate* aWorkerPrivate, WorkerPreference aPref, bool aValue) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mPref(aPref), mValue(aValue) - { - } + { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->UpdatePreferenceInternal(aCx, mPref, mValue); return true; } }; -class UpdateJSWorkerMemoryParameterRunnable : public WorkerControlRunnable +class UpdateJSWorkerMemoryParameterRunnable MOZ_FINAL : + public WorkerControlRunnable { uint32_t mValue; JSGCParamKey mKey; @@ -1490,12 +1580,13 @@ public: UpdateJSWorkerMemoryParameterRunnable(WorkerPrivate* aWorkerPrivate, JSGCParamKey aKey, uint32_t aValue) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mValue(aValue), mKey(aKey) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->UpdateJSWorkerMemoryParameterInternal(aCx, mKey, mValue); return true; @@ -1503,7 +1594,7 @@ public: }; #ifdef JS_GC_ZEAL -class UpdateGCZealRunnable : public WorkerControlRunnable +class UpdateGCZealRunnable MOZ_FINAL : public WorkerControlRunnable { uint8_t mGCZeal; uint32_t mFrequency; @@ -1512,12 +1603,13 @@ public: UpdateGCZealRunnable(WorkerPrivate* aWorkerPrivate, uint8_t aGCZeal, uint32_t aFrequency) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mGCZeal(aGCZeal), mFrequency(aFrequency) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->UpdateGCZealInternal(aCx, mGCZeal, mFrequency); return true; @@ -1525,55 +1617,56 @@ public: }; #endif -class UpdateJITHardeningRunnable : public WorkerControlRunnable +class UpdateJITHardeningRunnable MOZ_FINAL : public WorkerControlRunnable { bool mJITHardening; public: UpdateJITHardeningRunnable(WorkerPrivate* aWorkerPrivate, bool aJITHardening) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mJITHardening(aJITHardening) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->UpdateJITHardeningInternal(aCx, mJITHardening); return true; } }; -class GarbageCollectRunnable : public WorkerControlRunnable +class GarbageCollectRunnable MOZ_FINAL : public WorkerControlRunnable { -protected: bool mShrinking; bool mCollectChildren; public: GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking, bool aCollectChildren) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mShrinking(aShrinking), mCollectChildren(aCollectChildren) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { // Silence bad assertions, this can be dispatched from either the main // thread or the timer thread.. return true; } - void + virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) + bool aDispatchResult) MOZ_OVERRIDE { // Silence bad assertions, this can be dispatched from either the main // thread or the timer thread.. } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren); return true; @@ -1582,31 +1675,14 @@ public: class CycleCollectRunnable : public WorkerControlRunnable { -protected: bool mCollectChildren; public: CycleCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aCollectChildren) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mCollectChildren(aCollectChildren) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - // Silence bad assertions, this can be dispatched from either the main - // thread or the timer thread.. - return true; - } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - // Silence bad assertions, this can be dispatched from either the main - // thread or the timer thread.. - } - bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { @@ -1677,7 +1753,7 @@ public: } }; -class MessagePortRunnable : public WorkerRunnable +class MessagePortRunnable MOZ_FINAL : public WorkerRunnable { uint64_t mMessagePortSerial; bool mConnect; @@ -1686,14 +1762,18 @@ public: MessagePortRunnable(WorkerPrivate* aWorkerPrivate, uint64_t aMessagePortSerial, bool aConnect) - : WorkerRunnable(aWorkerPrivate, WorkerThread, - aConnect ? ModifyBusyCount : UnchangedBusyCount, - SkipWhenClearing), + : WorkerRunnable(aWorkerPrivate, aConnect ? + WorkerThreadModifyBusyCount : + WorkerThreadUnchangedBusyCount), mMessagePortSerial(aMessagePortSerial), mConnect(aConnect) { } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +private: + ~MessagePortRunnable() + { } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { if (mConnect) { return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial); @@ -1704,224 +1784,41 @@ public: } }; +#ifdef DEBUG + +PRThread* +PRThreadFromThread(nsIThread* aThread) +{ + MOZ_ASSERT(aThread); + + PRThread* result; + MOZ_ASSERT(NS_SUCCEEDED(aThread->GetPRThread(&result))); + MOZ_ASSERT(result); + + return result; +} + +#endif // DEBUG + } /* anonymous namespace */ -#ifdef DEBUG -void -mozilla::dom::workers::AssertIsOnMainThread() -{ - MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); -} +NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, nsRunnable) -WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget, - BusyBehavior aBusyBehavior, - ClearingBehavior aClearingBehavior) -: mWorkerPrivate(aWorkerPrivate), mTarget(aTarget), - mBusyBehavior(aBusyBehavior), mClearingBehavior(aClearingBehavior) -{ - NS_ASSERTION(aWorkerPrivate, "Null worker private!"); -} -#endif +NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, nsRunnable) -NS_IMPL_ISUPPORTS1(WorkerRunnable, nsIRunnable) - -bool -WorkerRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) -{ -#ifdef DEBUG - if (mBusyBehavior == ModifyBusyCount) { - NS_ASSERTION(mTarget == WorkerThread, - "Don't set this option unless targeting the worker thread!"); - } - if (mTarget == ParentThread) { - aWorkerPrivate->AssertIsOnWorkerThread(); - } - else { - aWorkerPrivate->AssertIsOnParentThread(); - } -#endif - - if (mBusyBehavior == ModifyBusyCount && aCx) { - return aWorkerPrivate->ModifyBusyCount(aCx, true); - } - - return true; -} - -bool -WorkerRunnable::Dispatch(JSContext* aCx) -{ - bool ok; - - if (!aCx) { - ok = PreDispatch(nullptr, mWorkerPrivate); - if (ok) { - ok = DispatchInternal(); - } - PostDispatch(nullptr, mWorkerPrivate, ok); - return ok; - } - - JSAutoRequest ar(aCx); - - JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); - - Maybe ac; - if (global) { - ac.construct(aCx, global); - } - - ok = PreDispatch(aCx, mWorkerPrivate); - - if (ok && !DispatchInternal()) { - ok = false; - } - - PostDispatch(aCx, mWorkerPrivate, ok); - - return ok; -} - -// static -bool -WorkerRunnable::DispatchToMainThread(nsIRunnable* aRunnable) -{ - nsCOMPtr mainThread = do_GetMainThread(); - NS_ASSERTION(mainThread, "This should never fail!"); - - return NS_SUCCEEDED(mainThread->Dispatch(aRunnable, NS_DISPATCH_NORMAL)); -} - -// These DispatchInternal functions look identical but carry important type -// informaton so they can't be consolidated... - -#define IMPL_DISPATCH_INTERNAL(_class) \ - bool \ - _class ::DispatchInternal() \ - { \ - if (mTarget == WorkerThread) { \ - return mWorkerPrivate->Dispatch(this); \ - } \ - \ - if (mWorkerPrivate->GetParent()) { \ - return mWorkerPrivate->GetParent()->Dispatch(this); \ - } \ - \ - return DispatchToMainThread(this); \ - } - -IMPL_DISPATCH_INTERNAL(WorkerRunnable) -IMPL_DISPATCH_INTERNAL(WorkerSyncRunnable) -IMPL_DISPATCH_INTERNAL(WorkerControlRunnable) - -#undef IMPL_DISPATCH_INTERNAL - -void -WorkerRunnable::PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) -{ -#ifdef DEBUG - if (mTarget == ParentThread) { - aWorkerPrivate->AssertIsOnWorkerThread(); - } - else { - aWorkerPrivate->AssertIsOnParentThread(); - } -#endif - - if (!aDispatchResult && aCx) { - if (mBusyBehavior == ModifyBusyCount) { - aWorkerPrivate->ModifyBusyCount(aCx, false); - } - JS_ReportPendingException(aCx); - } -} - -NS_IMETHODIMP -WorkerRunnable::Run() -{ - JSContext* cx; - nsRefPtr kungFuDeathGrip; - nsCxPusher pusher; - - if (mTarget == WorkerThread) { - mWorkerPrivate->AssertIsOnWorkerThread(); - cx = mWorkerPrivate->GetJSContext(); - } else { - kungFuDeathGrip = mWorkerPrivate; - mWorkerPrivate->AssertIsOnParentThread(); - cx = mWorkerPrivate->ParentJSContext(); - - if (!mWorkerPrivate->GetParent()) { - AssertIsOnMainThread(); - pusher.Push(cx); - } - } - - JS::Rooted targetCompartmentObject(cx); - - if (mTarget == WorkerThread) { - targetCompartmentObject = JS::CurrentGlobalOrNull(cx); - } else { - targetCompartmentObject = mWorkerPrivate->GetWrapper(); - } - - NS_ASSERTION(cx, "Must have a context!"); - - JSAutoRequest ar(cx); - - Maybe ac; - if (targetCompartmentObject) { - ac.construct(cx, targetCompartmentObject); - } - - bool result = WorkerRun(cx, mWorkerPrivate); - // In the case of CompileScriptRunnnable, WorkerRun above can cause us to - // lazily create a global, in which case we need to be in its compartment - // when calling PostRun() below. Maybe<> this time... - if (mTarget == WorkerThread && ac.empty() && - js::DefaultObjectForContextOrNull(cx)) { - ac.construct(cx, js::DefaultObjectForContextOrNull(cx)); - } - PostRun(cx, mWorkerPrivate, result); - return result ? NS_OK : NS_ERROR_FAILURE; -} - -void -WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aRunResult) -{ -#ifdef DEBUG - if (mTarget == ParentThread) { - mWorkerPrivate->AssertIsOnParentThread(); - } - else { - mWorkerPrivate->AssertIsOnWorkerThread(); - } -#endif - - if (mBusyBehavior == ModifyBusyCount) { - if (!aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false)) { - aRunResult = false; - } - } - - if (!aRunResult) { - JS_ReportPendingException(aCx); - } -} +NS_IMPL_ISUPPORTS1(TimerThreadEventTarget, nsIEventTarget) template -class WorkerPrivateParent::SynchronizeAndResumeRunnable +class WorkerPrivateParent::SynchronizeAndResumeRunnable MOZ_FINAL : public nsRunnable { - friend class WorkerPrivateParent; friend class nsRevocableEventPtr; WorkerPrivate* mWorkerPrivate; nsCOMPtr mWindow; nsCOMPtr mScriptContext; +public: SynchronizeAndResumeRunnable(WorkerPrivate* aWorkerPrivate, nsPIDOMWindow* aWindow, nsIScriptContext* aScriptContext) @@ -1934,8 +1831,12 @@ class WorkerPrivateParent::SynchronizeAndResumeRunnable MOZ_ASSERT(!aWorkerPrivate->GetParent()); } +private: + ~SynchronizeAndResumeRunnable() + { } + NS_IMETHOD - Run() + Run() MOZ_OVERRIDE { AssertIsOnMainThread(); @@ -1965,6 +1866,62 @@ class WorkerPrivateParent::SynchronizeAndResumeRunnable } }; +template +class WorkerPrivateParent::EventTarget MOZ_FINAL + : public nsIEventTarget +{ + // This mutex protects mWorkerPrivate and must be acquired *before* the + // WorkerPrivate's mutex whenever they must both be held. + mozilla::Mutex mMutex; + WorkerPrivate* mWorkerPrivate; + nsIEventTarget* mWeakNestedEventTarget; + nsCOMPtr mNestedEventTarget; + +public: + EventTarget(WorkerPrivate* aWorkerPrivate) + : mMutex("WorkerPrivateParent::EventTarget::mMutex"), + mWorkerPrivate(aWorkerPrivate), mWeakNestedEventTarget(nullptr) + { + MOZ_ASSERT(aWorkerPrivate); + } + + EventTarget(WorkerPrivate* aWorkerPrivate, nsIEventTarget* aNestedEventTarget) + : mMutex("WorkerPrivateParent::EventTarget::mMutex"), + mWorkerPrivate(aWorkerPrivate), mWeakNestedEventTarget(aNestedEventTarget), + mNestedEventTarget(aNestedEventTarget) + { + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aNestedEventTarget); + } + + void + Disable() + { + nsCOMPtr nestedEventTarget; + { + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate = nullptr; + mNestedEventTarget.swap(nestedEventTarget); + } + } + + nsIEventTarget* + GetWeakNestedEventTarget() const + { + MOZ_ASSERT(mWeakNestedEventTarget); + return mWeakNestedEventTarget; + } + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIEVENTTARGET + +private: + ~EventTarget() + { } +}; + struct WorkerPrivate::TimeoutInfo { TimeoutInfo() @@ -2118,6 +2075,21 @@ private: NS_IMPL_ISUPPORTS1(WorkerPrivate::MemoryReporter, nsIMemoryReporter) +WorkerPrivate::SyncLoopInfo::SyncLoopInfo(EventTarget* aEventTarget) +: mEventTarget(aEventTarget), mCompleted(false), mResult(false) +#ifdef DEBUG + , mHasRun(false) +#endif +{ +} + +// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the +// templates. +template +typename WorkerPrivateParent::cycleCollection + WorkerPrivateParent::_cycleCollectorGlobal = + WorkerPrivateParent::cycleCollection(); + template WorkerPrivateParent::WorkerPrivateParent( JSContext* aCx, @@ -2171,38 +2143,6 @@ WorkerPrivateParent::~WorkerPrivateParent() DropJSObjects(this); } -template -NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent, nsDOMEventTargetHelper) - -template -NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent, nsDOMEventTargetHelper) - -template -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WorkerPrivateParent) - // No new interfaces, just cycle collection. -NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) - -template -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent, - nsDOMEventTargetHelper) - // Nothing else to traverse - // The various strong references in LoadInfo are managed manually and cannot - // be cycle collected. - tmp->AssertIsOnParentThread(); -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -template -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent, - nsDOMEventTargetHelper) - tmp->AssertIsOnParentThread(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -template -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent, - nsDOMEventTargetHelper) - tmp->AssertIsOnParentThread(); -NS_IMPL_CYCLE_COLLECTION_TRACE_END - template JSObject* WorkerPrivateParent::WrapObject(JSContext* aCx, @@ -2213,8 +2153,7 @@ WorkerPrivateParent::WrapObject(JSContext* aCx, AssertIsOnParentThread(); - JS::Rooted obj(aCx, WorkerBinding::Wrap(aCx, aScope, - ParentAsWorkerPrivate())); + JSObject* obj = WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate()); if (mRooted) { PreserveWrapper(this); @@ -2223,6 +2162,148 @@ WorkerPrivateParent::WrapObject(JSContext* aCx, return obj; } +template +nsresult +WorkerPrivateParent::DispatchPrivate(WorkerRunnable* aRunnable, + nsIEventTarget* aSyncLoopTarget) +{ + // May be called on any thread! + + WorkerPrivate* self = ParentAsWorkerPrivate(); + + { + MutexAutoLock lock(mMutex); + + MOZ_ASSERT_IF(aSyncLoopTarget, self->mThread); + + if (!self->mThread) { + if (ParentStatus() == Pending || self->mStatus == Pending) { + mPreStartRunnables.AppendElement(aRunnable); + return NS_OK; + } + + NS_WARNING("Using a worker event target after the thread has already" + "been released!"); + return NS_ERROR_UNEXPECTED; + } + + if (self->mStatus == Dead || + (!aSyncLoopTarget && ParentStatus() > Running)) { + NS_WARNING("A runnable was posted to a worker that is already shutting " + "down!"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr target; + if (aSyncLoopTarget) { + target = aSyncLoopTarget; + } + else { + target = self->mThread; + } + + nsresult rv = target->Dispatch(aRunnable, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mCondVar.Notify(); + } + + return NS_OK; +} + +template +nsresult +WorkerPrivateParent::DispatchControlRunnable( + WorkerControlRunnable* aWorkerControlRunnable) +{ + // May be called on any thread! + + MOZ_ASSERT(aWorkerControlRunnable); + + nsRefPtr runnable = aWorkerControlRunnable; + + WorkerPrivate* self = ParentAsWorkerPrivate(); + + { + MutexAutoLock lock(mMutex); + + if (self->mStatus == Dead) { + NS_WARNING("A control runnable was posted to a worker that is already " + "shutting down!"); + return NS_ERROR_UNEXPECTED; + } + + // Transfer ownership to the control queue. + self->mControlQueue.Push(runnable.forget().get()); + + if (JSContext* cx = self->mJSContext) { + MOZ_ASSERT(self->mThread); + + JSRuntime* rt = JS_GetRuntime(cx); + MOZ_ASSERT(rt); + + JS_TriggerOperationCallback(rt); + } + + mCondVar.Notify(); + } + + return NS_OK; +} + +template +already_AddRefed +WorkerPrivateParent::MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable) +{ + // May be called on any thread! + + MOZ_ASSERT(aRunnable); + + nsRefPtr workerRunnable = + WorkerRunnable::FromRunnable(aRunnable); + if (workerRunnable) { + return workerRunnable.forget(); + } + + nsCOMPtr cancelable = do_QueryInterface(aRunnable); + if (!cancelable) { + MOZ_CRASH("All runnables destined for a worker thread must be cancelable!"); + } + + workerRunnable = + new ExternalRunnableWrapper(ParentAsWorkerPrivate(), cancelable); + return workerRunnable.forget(); +} + +template +already_AddRefed +WorkerPrivateParent::GetEventTarget() +{ + WorkerPrivate* self = ParentAsWorkerPrivate(); + + nsCOMPtr target; + + { + MutexAutoLock lock(mMutex); + + if (!mEventTarget && + ParentStatus() <= Running && + self->mStatus <= Running) { + mEventTarget = new EventTarget(self); + } + + target = mEventTarget; + } + + NS_WARN_IF_FALSE(target, + "Requested event target for a worker that is already " + "shutting down!"); + + return target.forget(); +} + template bool WorkerPrivateParent::Start() @@ -2270,17 +2351,22 @@ WorkerPrivateParent::NotifyPrivate(JSContext* aCx, Status aStatus) if (pending) { WorkerPrivate* self = ParentAsWorkerPrivate(); + #ifdef DEBUG { - // Silence useless assertions in debug builds. + // Fake a thread here just so that our assertions don't go off for no + // reason. nsIThread* currentThread = NS_GetCurrentThread(); - NS_ASSERTION(currentThread, "This should never be null!"); + MOZ_ASSERT(currentThread); - self->SetThread(currentThread); + MOZ_ASSERT(!self->mPRThread); + self->mPRThread = PRThreadFromThread(currentThread); + MOZ_ASSERT(self->mPRThread); } #endif + // Worker never got a chance to run, go ahead and delete it. - self->ScheduleDeletion(true); + self->ScheduleDeletion(); return true; } @@ -2469,12 +2555,11 @@ WorkerPrivateParent::Resume(JSContext* aCx, nsPIDOMWindow* aWindow) AssertIsOnMainThread(); MOZ_ASSERT(IsDedicatedWorker()); - nsTArray > runnables; + nsTArray> runnables; mQueuedRunnables.SwapElements(runnables); for (uint32_t index = 0; index < runnables.Length(); index++) { - nsRefPtr& runnable = runnables[index]; - runnable->Run(); + runnables[index]->Run(); } } @@ -2698,8 +2783,9 @@ WorkerPrivateParent::PostMessageInternal( nsRefPtr runnable = new MessageEventRunnable(ParentAsWorkerPrivate(), - WorkerRunnable::WorkerThread, buffer, - clonedObjects, aToMessagePort, aMessagePortSerial); + WorkerRunnable::WorkerThreadModifyBusyCount, + buffer, clonedObjects, aToMessagePort, + aMessagePortSerial); if (!runnable->Dispatch(aCx)) { aRv.Throw(NS_ERROR_FAILURE); } @@ -3344,7 +3430,7 @@ WorkerPrivateParent::ParentJSContext() const if (mParent) { return mParent->GetJSContext(); - } + } AssertIsOnMainThread(); @@ -3353,6 +3439,93 @@ WorkerPrivateParent::ParentJSContext() const nsContentUtils::GetSafeJSContext(); } +template +void +WorkerPrivateParent::RegisterHostObjectURI(const nsACString& aURI) +{ + AssertIsOnMainThread(); + mHostObjectURIs.AppendElement(aURI); +} + +template +void +WorkerPrivateParent::UnregisterHostObjectURI(const nsACString& aURI) +{ + AssertIsOnMainThread(); + mHostObjectURIs.RemoveElement(aURI); +} + +template +void +WorkerPrivateParent::StealHostObjectURIs(nsTArray& aArray) +{ + aArray.SwapElements(mHostObjectURIs); +} + +template +NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent, nsDOMEventTargetHelper) + +template +NS_IMPL_RELEASE_INHERITED(WorkerPrivateParent, nsDOMEventTargetHelper) + +template +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(WorkerPrivateParent) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) + +template +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerPrivateParent, + nsDOMEventTargetHelper) + // Nothing else to traverse + // The various strong references in LoadInfo are managed manually and cannot + // be cycle collected. + tmp->AssertIsOnParentThread(); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +template +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerPrivateParent, + nsDOMEventTargetHelper) + tmp->AssertIsOnParentThread(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +template +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerPrivateParent, + nsDOMEventTargetHelper) + tmp->AssertIsOnParentThread(); +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +#ifdef DEBUG + +template +void +WorkerPrivateParent::AssertIsOnParentThread() const +{ + if (GetParent()) { + GetParent()->AssertIsOnWorkerThread(); + } + else { + AssertIsOnMainThread(); + } +} + +template +void +WorkerPrivateParent::AssertInnerWindowIsCorrect() const +{ + AssertIsOnParentThread(); + + // Only care about top level workers from windows. + if (mParent || !mLoadInfo.mWindow) { + return; + } + + AssertIsOnMainThread(); + + nsPIDOMWindow* outer = mLoadInfo.mWindow->GetOuterWindow(); + NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow, + "Inner window no longer correct!"); +} + +#endif WorkerPrivate::WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL, @@ -3366,7 +3539,11 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx, mStatus(Pending), mSuspended(false), mTimerRunning(false), mRunningExpiredTimeouts(false), mCloseHandlerStarted(false), mCloseHandlerFinished(false), mMemoryReporterRunning(false), - mBlockedForMemoryReporter(false) + mBlockedForMemoryReporter(false), mCancelAllPendingRunnables(false), + mPeriodicGCTimerRunning(false) +#ifdef DEBUG + , mPRThread(nullptr) +#endif { MOZ_ASSERT_IF(IsSharedWorker(), !aSharedWorkerName.IsVoid()); MOZ_ASSERT_IF(!IsSharedWorker(), aSharedWorkerName.IsEmpty()); @@ -3456,7 +3633,7 @@ WorkerPrivate::Constructor(const GlobalObject& aGlobal, MOZ_ASSERT_IF(aWorkerType != WorkerTypeShared, aSharedWorkerName.IsEmpty()); - mozilla::Maybe stackLoadInfo; + Maybe stackLoadInfo; if (!aLoadInfo) { stackLoadInfo.construct(); @@ -3494,13 +3671,13 @@ WorkerPrivate::Constructor(const GlobalObject& aGlobal, new WorkerPrivate(cx, parent, aScriptURL, aIsChromeWorker, aWorkerType, aSharedWorkerName, *aLoadInfo); - nsRefPtr compiler = new CompileScriptRunnable(worker); - if (!compiler->Dispatch(cx)) { + if (!runtimeService->RegisterWorker(cx, worker)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } - if (!runtimeService->RegisterWorker(cx, worker)) { + nsRefPtr compiler = new CompileScriptRunnable(worker); + if (!compiler->Dispatch(cx)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } @@ -3554,7 +3731,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, { MutexAutoLock lock(aParent->mMutex); parentStatus = aParent->mStatus; - } + } if (parentStatus > Running) { nsCOMPtr mainThread; @@ -3591,9 +3768,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, // See if we're being called from a window. nsCOMPtr globalWindow = aWindow; if (!globalWindow) { - nsCOMPtr scriptGlobal = - nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx)); - if (scriptGlobal) { + nsCOMPtr scriptGlobal = + nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx)); + if (scriptGlobal) { globalWindow = do_QueryInterface(scriptGlobal); MOZ_ASSERT(globalWindow); } @@ -3654,13 +3831,13 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, // No unsandboxed ancestor, use our GUID. rv = loadInfo.mPrincipal->GetBaseDomain(loadInfo.mDomain); NS_ENSURE_SUCCESS(rv, rv); - } + } } else { // Document creating the worker is not sandboxed. rv = loadInfo.mPrincipal->GetBaseDomain(loadInfo.mDomain); NS_ENSURE_SUCCESS(rv, rv); - } } + } nsCOMPtr permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); @@ -3744,7 +3921,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, rv = NS_GetFinalChannelURI(loadInfo.mChannel, getter_AddRefs(loadInfo.mResolvedScriptURI)); NS_ENSURE_SUCCESS(rv, rv); - } + } aLoadInfo->StealFrom(loadInfo); return NS_OK; @@ -3754,145 +3931,50 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) { AssertIsOnWorkerThread(); + MOZ_ASSERT(mThread); { MutexAutoLock lock(mMutex); mJSContext = aCx; - NS_ASSERTION(mStatus == Pending, "Huh?!"); + MOZ_ASSERT(mStatus == Pending); mStatus = Running; } - // We need a timer for GC. The basic plan is to run a normal (non-shrinking) - // GC periodically (NORMAL_GC_TIMER_DELAY_MS) while the worker is running. - // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_MS) timer to - // run a shrinking GC. If the worker receives more messages then the short - // timer is canceled and the periodic timer resumes. - nsCOMPtr gcTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - if (!gcTimer) { - JS_ReportError(aCx, "Failed to create GC timer!"); - return; - } - - bool normalGCTimerRunning = false; - - // We need to swap event targets below to get different types of GC behavior. - nsCOMPtr normalGCEventTarget; - nsCOMPtr idleGCEventTarget; - - // We also need to track the idle GC event so that we don't confuse it with a - // generic event that should re-trigger the idle GC timer. - nsCOMPtr idleGCEvent; - { - nsRefPtr runnable = - new GarbageCollectRunnable(this, false, false); - normalGCEventTarget = new WorkerRunnableEventTarget(runnable); - - runnable = new GarbageCollectRunnable(this, true, false); - idleGCEventTarget = new WorkerRunnableEventTarget(runnable); - - idleGCEvent = runnable; - } - EnableMemoryReporter(); - Maybe maybeAC; - for (;;) { - Status currentStatus; - bool scheduleIdleGC; + InitializeGCTimers(); + + Maybe workerCompartment; + + for (;;) { + // Workers lazily create a global object in CompileScriptRunnable. We need + // to enter the global's compartment as soon as it has been created. + if (workerCompartment.empty()) { + if (JSObject* global = js::DefaultObjectForContextOrNull(aCx)) { + workerCompartment.construct(aCx, global); + } + } + + Status currentStatus; + bool normalRunnablesPending = false; - WorkerRunnable* event; { MutexAutoLock lock(mMutex); - while (!mControlQueue.Pop(event) && !mQueue.Pop(event)) { + while (mControlQueue.IsEmpty() && + !(normalRunnablesPending = NS_HasPendingEvents(mThread))) { WaitForWorkerEvents(); } - bool eventIsNotIdleGCEvent; - currentStatus = mStatus; - - { - MutexAutoUnlock unlock(mMutex); - - // Workers lazily create a global object in CompileScriptRunnable. In - // the old world, creating the global would implicitly set it as the - // default compartment object on mJSContext, meaning that subsequent - // runnables would be able to operate in that compartment without - // explicitly entering it. That no longer works, so we mimic the - // "operate in the compartment of the worker global once it exists" - // behavior here. This could probably be improved with some refactoring. - if (maybeAC.empty() && js::DefaultObjectForContextOrNull(aCx)) { - maybeAC.construct(aCx, js::DefaultObjectForContextOrNull(aCx)); - } - - if (!normalGCTimerRunning && - event != idleGCEvent && - currentStatus <= Terminating) { - // Must always cancel before changing the timer's target. - if (NS_FAILED(gcTimer->Cancel())) { - NS_WARNING("Failed to cancel GC timer!"); - } - - if (NS_SUCCEEDED(gcTimer->SetTarget(normalGCEventTarget)) && - NS_SUCCEEDED(gcTimer->InitWithFuncCallback( - DummyCallback, nullptr, - NORMAL_GC_TIMER_DELAY_MS, - nsITimer::TYPE_REPEATING_SLACK))) { - normalGCTimerRunning = true; - } - else { - JS_ReportError(aCx, "Failed to start normal GC timer!"); - } - } - - // Keep track of whether or not this is the idle GC event. - eventIsNotIdleGCEvent = event != idleGCEvent; - - static_cast(event)->Run(); - NS_RELEASE(event); - } + ProcessAllControlRunnablesLocked(); currentStatus = mStatus; - scheduleIdleGC = mControlQueue.IsEmpty() && - mQueue.IsEmpty() && - eventIsNotIdleGCEvent && - JS::CurrentGlobalOrNull(aCx); - } - - // Take care of the GC timer. If we're starting the close sequence then we - // kill the timer once and for all. Otherwise we schedule the idle timeout - // if there are no more events. - if (currentStatus > Terminating || scheduleIdleGC) { - if (NS_SUCCEEDED(gcTimer->Cancel())) { - normalGCTimerRunning = false; - } - else { - NS_WARNING("Failed to cancel GC timer!"); - } - } - - if (scheduleIdleGC) { - NS_ASSERTION(JS::CurrentGlobalOrNull(aCx), "Should have global here!"); - - // Now *might* be a good time to GC. Let the JS engine make the decision. - JSAutoCompartment ac(aCx, JS::CurrentGlobalOrNull(aCx)); - JS_MaybeGC(aCx); - - if (NS_SUCCEEDED(gcTimer->SetTarget(idleGCEventTarget)) && - NS_SUCCEEDED(gcTimer->InitWithFuncCallback( - DummyCallback, nullptr, - IDLE_GC_TIMER_DELAY_MS, - nsITimer::TYPE_ONE_SHOT))) { - } - else { - JS_ReportError(aCx, "Failed to start idle GC timer!"); - } } + // If the close handler has finished and all features are done then we can + // kill this thread. if (currentStatus != Running && !HasActiveFeatures()) { - // If the close handler has finished and all features are done then we can - // kill this thread. if (mCloseHandlerFinished && currentStatus != Killing) { if (!NotifyInternal(aCx, Killing)) { JS_ReportPendingException(aCx); @@ -3902,7 +3984,7 @@ WorkerPrivate::DoRunLoop(JSContext* aCx) MutexAutoLock lock(mMutex); currentStatus = mStatus; } - NS_ASSERTION(currentStatus == Killing, "Should have changed status!"); + MOZ_ASSERT(currentStatus == Killing); #else currentStatus = Killing; #endif @@ -3910,14 +3992,26 @@ WorkerPrivate::DoRunLoop(JSContext* aCx) // If we're supposed to die then we should exit the loop. if (currentStatus == Killing) { - // Always make sure the timer is canceled. - if (NS_FAILED(gcTimer->Cancel())) { - NS_WARNING("Failed to cancel the GC timer!"); - } + ShutdownGCTimers(); DisableMemoryReporter(); - StopAcceptingEvents(); + { + MutexAutoLock lock(mMutex); + + mStatus = Dead; + mJSContext = nullptr; + } + + // After mStatus is set to Dead there can be no more + // WorkerControlRunnables so no need to lock here. + if (!mControlQueue.IsEmpty()) { + WorkerControlRunnable* runnable; + while (mControlQueue.Pop(runnable)) { + runnable->Cancel(); + runnable->Release(); + } + } // Clear away our MessagePorts. mWorkerPorts.Clear(); @@ -3928,9 +4022,155 @@ WorkerPrivate::DoRunLoop(JSContext* aCx) return; } } + + // Nothing to do here if we don't have any runnables in the main queue. + if (!normalRunnablesPending) { + SetGCTimerMode(IdleTimer); + continue; + } + + MOZ_ASSERT(NS_HasPendingEvents(mThread)); + + // Start the periodic GC timer if it is not already running. + SetGCTimerMode(PeriodicTimer); + + // Process a single runnable from the main queue. + MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(mThread, false)); + + if (NS_HasPendingEvents(mThread)) { + // Now *might* be a good time to GC. Let the JS engine make the decision. + if (!workerCompartment.empty()) { + JS_MaybeGC(aCx); + } + } + else { + // The normal event queue has been exhausted, cancel the periodic GC timer + // and schedule the idle GC timer. + SetGCTimerMode(IdleTimer); + } } - NS_NOTREACHED("Shouldn't get here!"); + MOZ_ASSUME_UNREACHABLE("Shouldn't get here!"); +} + +void +WorkerPrivate::OnProcessNextEvent(uint32_t aRecursionDepth) +{ + AssertIsOnWorkerThread(); + MOZ_ASSERT(aRecursionDepth); + + // Normally we process control runnables in DoRunLoop or RunCurrentSyncLoop. + // However, it's possible that non-worker C++ could spin its own nested event + // loop, and in that case we must ensure that we continue to process control + // runnables here. + if (aRecursionDepth > 1 && + mSyncLoopStack.Length() < aRecursionDepth - 1) { + ProcessAllControlRunnables(); + } +} + +void +WorkerPrivate::AfterProcessNextEvent(uint32_t aRecursionDepth) +{ + AssertIsOnWorkerThread(); + MOZ_ASSERT(aRecursionDepth); +} + +void +WorkerPrivate::InitializeGCTimers() +{ + AssertIsOnWorkerThread(); + + // We need a timer for GC. The basic plan is to run a non-shrinking GC + // periodically (PERIODIC_GC_TIMER_DELAY_SEC) while the worker is running. + // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_SEC) timer to + // run a shrinking GC. If the worker receives more messages then the short + // timer is canceled and the periodic timer resumes. + mGCTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + MOZ_ASSERT(mGCTimer); + + nsRefPtr runnable = + new GarbageCollectRunnable(this, false, false); + mPeriodicGCTimerTarget = new TimerThreadEventTarget(this, runnable); + + runnable = new GarbageCollectRunnable(this, true, false); + mIdleGCTimerTarget = new TimerThreadEventTarget(this, runnable); + + mPeriodicGCTimerRunning = false; +} + +void +WorkerPrivate::SetGCTimerMode(GCTimerMode aMode) +{ + AssertIsOnWorkerThread(); + MOZ_ASSERT(mGCTimer); + MOZ_ASSERT(mPeriodicGCTimerTarget); + MOZ_ASSERT(mIdleGCTimerTarget); + + if (aMode == PeriodicTimer && mPeriodicGCTimerRunning) { + return; + } + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->Cancel())); + + mPeriodicGCTimerRunning = false; + + LOG(("Worker %p canceled GC timer because %s\n", this, + aMode == PeriodicTimer ? + "periodic" : + aMode == IdleTimer ? "idle" : "none")); + + if (aMode == NoTimer) { + return; + } + + MOZ_ASSERT(aMode == PeriodicTimer || aMode == IdleTimer); + + nsIEventTarget* target; + uint32_t delay; + int16_t type; + + if (aMode == PeriodicTimer) { + target = mPeriodicGCTimerTarget; + delay = PERIODIC_GC_TIMER_DELAY_SEC * 1000; + type = nsITimer::TYPE_REPEATING_SLACK; + } + else { + target = mIdleGCTimerTarget; + delay = IDLE_GC_TIMER_DELAY_SEC * 1000; + type = nsITimer::TYPE_ONE_SHOT; + } + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->SetTarget(target))); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->InitWithFuncCallback(DummyCallback, + nullptr, delay, + type))); + + if (aMode == PeriodicTimer) { + LOG(("Worker %p scheduled periodic GC timer\n", this)); + mPeriodicGCTimerRunning = true; + } + else { + LOG(("Worker %p scheduled idle GC timer\n", this)); + } +} + +void +WorkerPrivate::ShutdownGCTimers() +{ + AssertIsOnWorkerThread(); + + MOZ_ASSERT(mGCTimer); + + // Always make sure the timer is canceled. + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mGCTimer->Cancel())); + + LOG(("Worker %p killed the GC timer\n", this)); + + mGCTimer = nullptr; + mPeriodicGCTimerTarget = nullptr; + mIdleGCTimerTarget = nullptr; + mPeriodicGCTimerRunning = false; } bool @@ -3939,6 +4179,7 @@ WorkerPrivate::OperationCallback(JSContext* aCx) AssertIsOnWorkerThread(); bool mayContinue = true; + bool scheduledIdleGC = false; for (;;) { // Run all control events now. @@ -3954,8 +4195,12 @@ WorkerPrivate::OperationCallback(JSContext* aCx) break; } - // Clean up before suspending. - JS_GC(JS_GetRuntime(aCx)); + // Cancel the periodic GC timer here before suspending. The idle GC timer + // will clean everything up once it runs. + if (!scheduledIdleGC) { + SetGCTimerMode(IdleTimer); + scheduledIdleGC = true; + } while ((mayContinue = MayContinueRunning())) { MutexAutoLock lock(mMutex); @@ -3974,39 +4219,58 @@ WorkerPrivate::OperationCallback(JSContext* aCx) return false; } + // Make sure the periodic timer gets turned back on here. + SetGCTimerMode(PeriodicTimer); + return true; } +nsresult +WorkerPrivate::IsOnCurrentThread(bool* aIsOnCurrentThread) +{ + // May be called on any thread! + + MOZ_ASSERT(aIsOnCurrentThread); + + nsCOMPtr thread; + { + MutexAutoLock lock(mMutex); + thread = mThread; + } + + if (!thread) { + NS_WARNING("Trying to test thread correctness after the worker has " + "released its thread!"); + return NS_ERROR_FAILURE; + } + + nsresult rv = thread->IsOnCurrentThread(aIsOnCurrentThread); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + void -WorkerPrivate::ScheduleDeletion(bool aWasPending) +WorkerPrivate::ScheduleDeletion() { AssertIsOnWorkerThread(); - NS_ASSERTION(mChildWorkers.IsEmpty(), "Live child workers!"); - NS_ASSERTION(mSyncQueues.IsEmpty(), "Should have no sync queues here!"); + MOZ_ASSERT(mChildWorkers.IsEmpty()); + MOZ_ASSERT(mSyncLoopStack.IsEmpty()); - StopAcceptingEvents(); + ClearMainEventQueue(); - nsIThread* currentThread; - if (aWasPending) { - // Don't want to close down this thread since we never got to run! - currentThread = nullptr; - } - else { - currentThread = NS_GetCurrentThread(); - NS_ASSERTION(currentThread, "This should never be null!"); - } - - WorkerPrivate* parent = GetParent(); - if (parent) { + if (WorkerPrivate* parent = GetParent()) { nsRefPtr runnable = - new WorkerFinishedRunnable(parent, this, currentThread); + new WorkerFinishedRunnable(parent, this); if (!runnable->Dispatch(nullptr)) { NS_WARNING("Failed to dispatch runnable!"); } } else { nsRefPtr runnable = - new TopLevelWorkerFinishedRunnable(this, currentThread); + new TopLevelWorkerFinishedRunnable(this); if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) { NS_WARNING("Failed to dispatch runnable!"); } @@ -4066,6 +4330,7 @@ void WorkerPrivate::EnableMemoryReporter() { AssertIsOnWorkerThread(); + MOZ_ASSERT(!mMemoryReporter); // No need to lock here since the main thread can't race until we've // successfully registered the reporter. @@ -4076,8 +4341,6 @@ WorkerPrivate::EnableMemoryReporter() // No need to lock here since a failed registration means our memory // reporter can't start running. Just clean up. mMemoryReporter = nullptr; - - return; } } @@ -4163,136 +4426,71 @@ WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval) } bool -WorkerPrivate::ProcessAllControlRunnables() +WorkerPrivate::ProcessAllControlRunnablesLocked() { AssertIsOnWorkerThread(); + mMutex.AssertCurrentThreadOwns(); bool result = true; for (;;) { - WorkerRunnable* event; - { - MutexAutoLock lock(mMutex); + // Block here if the memory reporter is trying to run. + if (mMemoryReporterRunning) { + MOZ_ASSERT(!mBlockedForMemoryReporter); - // Block here if the memory reporter is trying to run. - if (mMemoryReporterRunning) { - NS_ASSERTION(!mBlockedForMemoryReporter, - "Can't be blocked in more than one place at the same " - "time!"); + // Let the main thread know that we've received the block request and + // that memory reporting may proceed. + mBlockedForMemoryReporter = true; - // Let the main thread know that we've received the block request and - // that memory reporting may proceed. - mBlockedForMemoryReporter = true; + // The main thread is almost certainly waiting so we must notify here. + mMemoryReportCondVar.Notify(); - // The main thread is almost certainly waiting so we must notify here. - mMemoryReportCondVar.Notify(); - - // Wait for the memory report to finish. - while (mMemoryReporterRunning) { - mMemoryReportCondVar.Wait(); - } - - NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!"); - - // No need to notify here as the main thread isn't watching for this - // state. - mBlockedForMemoryReporter = false; + // Wait for the memory report to finish. + while (mMemoryReporterRunning) { + mMemoryReportCondVar.Wait(); } - if (!mControlQueue.Pop(event)) { - break; - } + MOZ_ASSERT(mBlockedForMemoryReporter); + + // No need to notify here as the main thread isn't watching for this + // state. + mBlockedForMemoryReporter = false; } + WorkerControlRunnable* event; + if (!mControlQueue.Pop(event)) { + break; + } + + MutexAutoUnlock unlock(mMutex); + + MOZ_ASSERT(event); if (NS_FAILED(static_cast(event)->Run())) { result = false; } - NS_RELEASE(event); + event->Release(); } return result; } -bool -WorkerPrivate::Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue) -{ - nsRefPtr event(aEvent); - - { - MutexAutoLock lock(mMutex); - - if (mStatus == Dead) { - // Nothing may be added after we've set Dead. - return false; - } - - if (aQueue == &mQueue) { - // Check parent status. - Status parentStatus = ParentStatus(); - if (parentStatus >= Terminating) { - // Throw. - return false; - } - - // Check inner status too. - if (parentStatus >= Closing || mStatus >= Closing) { - // Silently eat this one. - return true; - } - } - - if (!aQueue->Push(event)) { - return false; - } - - if (aQueue == &mControlQueue && mJSContext) { - JS_TriggerOperationCallback(JS_GetRuntime(mJSContext)); - } - - mCondVar.Notify(); - } - - event.forget(); - return true; -} - -bool -WorkerPrivate::DispatchToSyncQueue(WorkerSyncRunnable* aEvent) -{ - nsRefPtr event(aEvent); - - { - MutexAutoLock lock(mMutex); - - NS_ASSERTION(mSyncQueues.Length() > aEvent->mSyncQueueKey, "Bad event!"); - - if (!mSyncQueues[aEvent->mSyncQueueKey]->mQueue.Push(event)) { - return false; - } - - mCondVar.Notify(); - } - - event.forget(); - return true; -} - void -WorkerPrivate::ClearQueue(EventQueue* aQueue) +WorkerPrivate::ClearMainEventQueue() { AssertIsOnWorkerThread(); - mMutex.AssertCurrentThreadOwns(); - WorkerRunnable* event; - while (aQueue->Pop(event)) { - if (event->WantsToRunDuringClear()) { - MutexAutoUnlock unlock(mMutex); + nsIThread* currentThread = NS_GetCurrentThread(); + MOZ_ASSERT(currentThread); - static_cast(event)->Run(); - } - event->Release(); - } + MOZ_ASSERT(!mCancelAllPendingRunnables); + mCancelAllPendingRunnables = true; + + NS_ProcessPendingEvents(currentThread); + MOZ_ASSERT(!NS_HasPendingEvents(currentThread)); + + MOZ_ASSERT(mCancelAllPendingRunnables); + mCancelAllPendingRunnables = false; } uint32_t @@ -4377,8 +4575,8 @@ WorkerPrivate::AddChildWorker(JSContext* aCx, ParentType* aChildWorker) { Status currentStatus; { - MutexAutoLock lock(mMutex); - currentStatus = mStatus; + MutexAutoLock lock(mMutex); + currentStatus = mStatus; } MOZ_ASSERT(currentStatus == Running); @@ -4504,92 +4702,190 @@ WorkerPrivate::CancelAllTimeouts(JSContext* aCx) mTimer = nullptr; } -uint32_t +already_AddRefed WorkerPrivate::CreateNewSyncLoop() { AssertIsOnWorkerThread(); - NS_ASSERTION(mSyncQueues.Length() < UINT32_MAX, - "Should have bailed by now!"); + nsCOMPtr thread = do_QueryInterface(NS_GetCurrentThread()); + MOZ_ASSERT(thread); - mSyncQueues.AppendElement(new SyncQueue()); - return mSyncQueues.Length() - 1; + nsCOMPtr realEventTarget; + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->PushEventQueue( + getter_AddRefs(realEventTarget)))); + + nsRefPtr workerEventTarget = + new EventTarget(this, realEventTarget); + + { + // Modifications must be protected by mMutex in DEBUG builds, see comment + // about mSyncLoopStack in WorkerPrivate.h. +#ifdef DEBUG + MutexAutoLock lock(mMutex); +#endif + + mSyncLoopStack.AppendElement(new SyncLoopInfo(workerEventTarget)); + } + + return workerEventTarget.forget(); } bool -WorkerPrivate::RunSyncLoop(JSContext* aCx, uint32_t aSyncLoopKey) +WorkerPrivate::RunCurrentSyncLoop() { AssertIsOnWorkerThread(); - NS_ASSERTION(!mSyncQueues.IsEmpty() || - (aSyncLoopKey != mSyncQueues.Length() - 1), - "Forgot to call CreateNewSyncLoop!"); - if (aSyncLoopKey != mSyncQueues.Length() - 1) { - return false; - } + JSContext* cx = GetJSContext(); + MOZ_ASSERT(cx); - SyncQueue* syncQueue = mSyncQueues[aSyncLoopKey].get(); + // This should not change between now and the time we finish running this sync + // loop. + uint32_t currentLoopIndex = mSyncLoopStack.Length() - 1; - for (;;) { - WorkerRunnable* event; + SyncLoopInfo* loopInfo = mSyncLoopStack[currentLoopIndex]; + + MOZ_ASSERT(loopInfo); + MOZ_ASSERT(!loopInfo->mHasRun); + MOZ_ASSERT(!loopInfo->mCompleted); + +#ifdef DEBUG + loopInfo->mHasRun = true; +#endif + + nsCOMPtr thread = do_QueryInterface(mThread); + MOZ_ASSERT(thread); + + while (!loopInfo->mCompleted) { + bool normalRunnablesPending = false; + + // Don't block with the periodic GC timer running. + if (!NS_HasPendingEvents(thread)) { + SetGCTimerMode(IdleTimer); + } + + // Wait for something to do. { MutexAutoLock lock(mMutex); - while (!mControlQueue.Pop(event) && !syncQueue->mQueue.Pop(event)) { - WaitForWorkerEvents(); + for (;;) { + while (mControlQueue.IsEmpty() && + !normalRunnablesPending && + !(normalRunnablesPending = NS_HasPendingEvents(thread))) { + WaitForWorkerEvents(); + } + + ProcessAllControlRunnablesLocked(); + + if (normalRunnablesPending) { + break; + } } } - static_cast(event)->Run(); - NS_RELEASE(event); + // Make sure the periodic timer is running before we continue. + SetGCTimerMode(PeriodicTimer); - if (syncQueue->mComplete) { - NS_ASSERTION(mSyncQueues.Length() - 1 == aSyncLoopKey, - "Mismatched calls!"); - NS_ASSERTION(syncQueue->mQueue.IsEmpty(), "Unprocessed sync events!"); + MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(thread, false)); - bool result = syncQueue->mResult; - DestroySyncLoop(aSyncLoopKey); + // Now *might* be a good time to GC. Let the JS engine make the decision. + JS_MaybeGC(cx); + } + // Make sure that the stack didn't change underneath us. + MOZ_ASSERT(!mSyncLoopStack.IsEmpty()); + MOZ_ASSERT(mSyncLoopStack.Length() - 1 == currentLoopIndex); + MOZ_ASSERT(mSyncLoopStack[currentLoopIndex] == loopInfo); + + // We're about to delete |loop|, stash its event target and result. + nsIEventTarget* nestedEventTarget = + loopInfo->mEventTarget->GetWeakNestedEventTarget(); + MOZ_ASSERT(nestedEventTarget); + + bool result = loopInfo->mResult; + + { + // Modifications must be protected by mMutex in DEBUG builds, see comment + // about mSyncLoopStack in WorkerPrivate.h. #ifdef DEBUG - syncQueue = nullptr; + MutexAutoLock lock(mMutex); #endif - return result; + // This will delete |loop|! + mSyncLoopStack.RemoveElementAt(currentLoopIndex); + } + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->PopEventQueue(nestedEventTarget))); + + return result; +} + +void +WorkerPrivate::StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult) +{ + AssertIsOnWorkerThread(); + AssertValidSyncLoop(aSyncLoopTarget); + + MOZ_ASSERT(!mSyncLoopStack.IsEmpty()); + + for (uint32_t index = mSyncLoopStack.Length(); index > 0; index--) { + nsAutoPtr& loopInfo = mSyncLoopStack[index - 1]; + MOZ_ASSERT(loopInfo); + MOZ_ASSERT(loopInfo->mEventTarget); + + if (loopInfo->mEventTarget == aSyncLoopTarget) { + // Can't assert |loop->mHasRun| here because dispatch failures can cause + // us to bail out early. + MOZ_ASSERT(!loopInfo->mCompleted); + + loopInfo->mResult = aResult; + loopInfo->mCompleted = true; + + loopInfo->mEventTarget->Disable(); + + return; + } + + MOZ_ASSERT(!SameCOMIdentity(loopInfo->mEventTarget, aSyncLoopTarget)); + } + + MOZ_CRASH("Unknown sync loop!"); +} + +#ifdef DEBUG +void +WorkerPrivate::AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget) +{ + MOZ_ASSERT(aSyncLoopTarget); + + EventTarget* workerTarget; + nsresult rv = + aSyncLoopTarget->QueryInterface(kDEBUGWorkerEventTargetIID, + reinterpret_cast(&workerTarget)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + MOZ_ASSERT(workerTarget); + + bool valid = false; + + { + MutexAutoLock lock(mMutex); + + for (uint32_t index = 0; index < mSyncLoopStack.Length(); index++) { + nsAutoPtr& loopInfo = mSyncLoopStack[index]; + MOZ_ASSERT(loopInfo); + MOZ_ASSERT(loopInfo->mEventTarget); + + if (loopInfo->mEventTarget == aSyncLoopTarget) { + valid = true; + break; + } + + MOZ_ASSERT(!SameCOMIdentity(loopInfo->mEventTarget, aSyncLoopTarget)); } } - NS_NOTREACHED("Shouldn't get here!"); - return false; -} - -void -WorkerPrivate::StopSyncLoop(uint32_t aSyncLoopKey, bool aSyncResult) -{ - AssertIsOnWorkerThread(); - - NS_ASSERTION(mSyncQueues.IsEmpty() || - (aSyncLoopKey == mSyncQueues.Length() - 1), - "Forgot to call CreateNewSyncLoop!"); - if (aSyncLoopKey != mSyncQueues.Length() - 1) { - return; - } - - SyncQueue* syncQueue = mSyncQueues[aSyncLoopKey].get(); - - NS_ASSERTION(!syncQueue->mComplete, "Already called StopSyncLoop?!"); - - syncQueue->mResult = aSyncResult; - syncQueue->mComplete = true; -} - -void -WorkerPrivate::DestroySyncLoop(uint32_t aSyncLoopKey) -{ - AssertIsOnWorkerThread(); - - mSyncQueues.RemoveElementAt(aSyncLoopKey); + MOZ_ASSERT(valid); } +#endif void WorkerPrivate::PostMessageToParentInternal( @@ -4629,8 +4925,10 @@ WorkerPrivate::PostMessageToParentInternal( } nsRefPtr runnable = - new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer, - clonedObjects, aToMessagePort, aMessagePortSerial); + new MessageEventRunnable(this, + WorkerRunnable::ParentThreadUnchangedBusyCount, + buffer, clonedObjects, aToMessagePort, + aMessagePortSerial); if (!runnable->Dispatch(aCx)) { aRv = NS_ERROR_FAILURE; } @@ -4663,33 +4961,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) NS_ASSERTION(aStatus > Running && aStatus < Dead, "Bad status!"); + nsRefPtr eventTarget; + // Save the old status and set the new status. Status previousStatus; { MutexAutoLock lock(mMutex); if (mStatus >= aStatus) { + MOZ_ASSERT(!mEventTarget); return true; } previousStatus = mStatus; mStatus = aStatus; + + mEventTarget.swap(eventTarget); + } + + // Now that mStatus > Running, no-one can create a new WorkerEventTarget or + // WorkerCrossThreadDispatcher if we don't already have one. + if (eventTarget) { + // Since we'll no longer process events, make sure we no longer allow anyone + // to post them. We have to do this without mMutex held, since our mutex + // must be acquired *after* the WorkerEventTarget's mutex when they're both + // held. + eventTarget->Disable(); + eventTarget = nullptr; } - // Now that status > Running, no-one can create a new mCrossThreadDispatcher - // if we don't already have one. if (mCrossThreadDispatcher) { // Since we'll no longer process events, make sure we no longer allow - // anyone to post them. - // We have to do this without mMutex held, since our mutex must be - // acquired *after* mCrossThreadDispatcher's mutex when they're both held. + // anyone to post them. We have to do this without mMutex held, since our + // mutex must be acquired *after* mCrossThreadDispatcher's mutex when + // they're both held. mCrossThreadDispatcher->Forget(); + mCrossThreadDispatcher = nullptr; } - NS_ASSERTION(previousStatus != Pending, "How is this possible?!"); + MOZ_ASSERT(previousStatus != Pending); - NS_ASSERTION(previousStatus >= Canceling || mKillTime.IsNull(), - "Bad kill time set!"); + MOZ_ASSERT(previousStatus >= Canceling || mKillTime.IsNull()); // Let all our features know the new status. NotifyFeatures(aCx, aStatus); @@ -4697,8 +5009,7 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) // If this is the first time our status has changed then we need to clear the // main event queue. if (previousStatus == Running) { - MutexAutoLock lock(mMutex); - ClearQueue(&mQueue); + ClearMainEventQueue(); } // If we've run the close handler, we don't need to do anything else. @@ -4717,19 +5028,10 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) // If this is the first time our status has changed we also need to schedule // the close handler unless we're being shut down. if (previousStatus == Running && aStatus != Killing) { - NS_ASSERTION(!mCloseHandlerStarted && !mCloseHandlerFinished, - "This is impossible!"); + MOZ_ASSERT(!mCloseHandlerStarted && !mCloseHandlerFinished); nsRefPtr closeRunnable = new CloseEventRunnable(this); - - MutexAutoLock lock(mMutex); - - if (!mQueue.Push(closeRunnable)) { - NS_WARNING("Failed to push closeRunnable!"); - return false; - } - - closeRunnable.forget(); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(closeRunnable))); } if (aStatus == Closing) { @@ -4750,9 +5052,7 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) if (aStatus == Canceling) { // We need to enforce a timeout on the close handler. - NS_ASSERTION(previousStatus == Running || previousStatus == Closing || - previousStatus == Terminating, - "Bad previous status!"); + MOZ_ASSERT(previousStatus >= Running && previousStatus <= Terminating); uint32_t killSeconds = IsChromeWorker() ? RuntimeService::GetChromeCloseHandlerTimeoutSeconds() : @@ -4770,18 +5070,15 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) return mCloseHandlerStarted; } - if (aStatus == Killing) { - mKillTime = TimeStamp::Now(); + MOZ_ASSERT(aStatus == Killing); - if (!mCloseHandlerFinished && !ScheduleKillCloseEventRunnable(aCx)) { - return false; - } + mKillTime = TimeStamp::Now(); - // Always abort the script. - return false; + if (mCloseHandlerStarted && !mCloseHandlerFinished) { + ScheduleKillCloseEventRunnable(aCx); } - NS_NOTREACHED("Should never get here!"); + // Always abort the script. return false; } @@ -4789,7 +5086,7 @@ bool WorkerPrivate::ScheduleKillCloseEventRunnable(JSContext* aCx) { AssertIsOnWorkerThread(); - NS_ASSERTION(!mKillTime.IsNull(), "Must have a kill time!"); + MOZ_ASSERT(!mKillTime.IsNull()); nsRefPtr killCloseEventRunnable = new KillCloseEventRunnable(this); @@ -4797,14 +5094,9 @@ WorkerPrivate::ScheduleKillCloseEventRunnable(JSContext* aCx) return false; } - MutexAutoLock lock(mMutex); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread( + killCloseEventRunnable))); - if (!mQueue.Push(killCloseEventRunnable)) { - NS_WARNING("Failed to push killCloseEventRunnable!"); - return false; - } - - killCloseEventRunnable.forget(); return true; } @@ -4954,21 +5246,24 @@ WorkerPrivate::SetTimeout(JSContext* aCx, nsresult rv; if (!mTimer) { - mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); + nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } - nsRefPtr timerRunnable = new TimerRunnable(this); + nsRefPtr runnable = new TimerRunnable(this); - nsCOMPtr target = - new WorkerRunnableEventTarget(timerRunnable); - rv = mTimer->SetTarget(target); + nsRefPtr target = + new TimerThreadEventTarget(this, runnable); + + rv = timer->SetTarget(target); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } + + timer.swap(mTimer); } if (!mTimerRunning) { @@ -5244,19 +5539,30 @@ WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking, { AssertIsOnWorkerThread(); + if (!JS::CurrentGlobalOrNull(aCx)) { + // We haven't compiled anything yet. Just bail out. + return; + } + if (aShrinking || aCollectChildren) { JSRuntime* rt = JS_GetRuntime(aCx); JS::PrepareForFullGC(rt); if (aShrinking) { JS::ShrinkingGC(rt, JS::gcreason::DOM_WORKER); + + if (!aCollectChildren) { + LOG(("Worker %p collected idle garbage\n", this)); + } } else { JS::GCForReason(rt, JS::gcreason::DOM_WORKER); + LOG(("Worker %p collected garbage\n", this)); } } else { JS_MaybeGC(aCx); + LOG(("Worker %p collected periodic garbage\n", this)); } if (aCollectChildren) { @@ -5280,28 +5586,49 @@ WorkerPrivate::CycleCollectInternal(JSContext* aCx, bool aCollectChildren) } } - -template void -WorkerPrivateParent::RegisterHostObjectURI(const nsACString& aURI) +WorkerPrivate::SetThread(nsIThread* aThread) { - AssertIsOnMainThread(); - mHostObjectURIs.AppendElement(aURI); -} +#ifdef DEBUG + if (aThread) { + bool isOnCurrentThread; + MOZ_ASSERT(NS_SUCCEEDED(aThread->IsOnCurrentThread(&isOnCurrentThread))); + MOZ_ASSERT(isOnCurrentThread); -template -void -WorkerPrivateParent::UnregisterHostObjectURI(const nsACString& aURI) -{ - AssertIsOnMainThread(); - mHostObjectURIs.RemoveElement(aURI); -} + MOZ_ASSERT(!mPRThread); + mPRThread = PRThreadFromThread(aThread); + MOZ_ASSERT(mPRThread); + } + else { + MOZ_ASSERT(mPRThread); + } +#endif -template -void -WorkerPrivateParent::StealHostObjectURIs(nsTArray& aArray) -{ - aArray.SwapElements(mHostObjectURIs); + nsCOMPtr doomedThread; + + { // Scope so that |doomedThread| is released without holding the lock. + MutexAutoLock lock(mMutex); + + if (aThread) { + MOZ_ASSERT(!mThread); + MOZ_ASSERT(mStatus == Pending); + + mThread = aThread; + + if (!mPreStartRunnables.IsEmpty()) { + for (uint32_t index = 0; index < mPreStartRunnables.Length(); index++) { + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mThread->Dispatch( + mPreStartRunnables[index], + NS_DISPATCH_NORMAL))); + } + mPreStartRunnables.Clear(); + } + } + else { + MOZ_ASSERT(mThread); + mThread.swap(doomedThread); + } + } } WorkerCrossThreadDispatcher* @@ -5321,6 +5648,9 @@ WorkerPrivate::BeginCTypesCall() { AssertIsOnWorkerThread(); + // Don't try to GC while we're blocked in a ctypes call. + SetGCTimerMode(NoTimer); + MutexAutoLock lock(mMutex); NS_ASSERTION(!mBlockedForMemoryReporter, @@ -5342,18 +5672,23 @@ WorkerPrivate::EndCTypesCall() { AssertIsOnWorkerThread(); - MutexAutoLock lock(mMutex); + { + MutexAutoLock lock(mMutex); - NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!"); + NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!"); - // Don't continue until the memory reporter has finished. - while (mMemoryReporterRunning) { - mMemoryReportCondVar.Wait(); + // Don't continue until the memory reporter has finished. + while (mMemoryReporterRunning) { + mMemoryReportCondVar.Wait(); + } + + // No need to notify the main thread here as it shouldn't be waiting to see + // this state. + mBlockedForMemoryReporter = false; } - // No need to notify the main thread here as it shouldn't be waiting to see - // this state. - mBlockedForMemoryReporter = false; + // Make sure the periodic timer is running before we start running JS again. + SetGCTimerMode(PeriodicTimer); } bool @@ -5462,49 +5797,115 @@ WorkerPrivate::CreateGlobalScope(JSContext* aCx) } #ifdef DEBUG -template -void -WorkerPrivateParent::AssertIsOnParentThread() const -{ - if (GetParent()) { - GetParent()->AssertIsOnWorkerThread(); - } - else { - AssertIsOnMainThread(); - } -} - -template -void -WorkerPrivateParent::AssertInnerWindowIsCorrect() const -{ - AssertIsOnParentThread(); - - // Only care about top level workers from windows. - if (mParent || !mLoadInfo.mWindow) { - return; - } - - AssertIsOnMainThread(); - - nsPIDOMWindow* outer = mLoadInfo.mWindow->GetOuterWindow(); - NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow, - "Inner window no longer correct!"); -} void WorkerPrivate::AssertIsOnWorkerThread() const { - MOZ_ASSERT(mThread, - "Trying to assert thread identity after thread has been " - "shutdown!"); + // This is much more complicated than it needs to be but we can't use mThread + // because it must be protected by mMutex and sometimes this method is called + // when mMutex is already locked. This method should always work. + MOZ_ASSERT(mPRThread, + "AssertIsOnWorkerThread() called before a thread was assigned!"); + + MOZ_ASSERT(nsThreadManager::get()); + + nsCOMPtr thread; + nsresult rv = + nsThreadManager::get()->GetThreadFromPRThread(mPRThread, + getter_AddRefs(thread)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + MOZ_ASSERT(thread); bool current; - MOZ_ASSERT(NS_SUCCEEDED(mThread->IsOnCurrentThread(¤t))); + rv = thread->IsOnCurrentThread(¤t); + MOZ_ASSERT(NS_SUCCEEDED(rv)); MOZ_ASSERT(current, "Wrong thread!"); } + #endif // DEBUG +NS_IMPL_ISUPPORTS_INHERITED0(ExternalRunnableWrapper, WorkerRunnable) + +template +NS_IMPL_ADDREF(WorkerPrivateParent::EventTarget) + +template +NS_IMPL_RELEASE(WorkerPrivateParent::EventTarget) + +template +NS_INTERFACE_MAP_BEGIN(WorkerPrivateParent::EventTarget) + NS_INTERFACE_MAP_ENTRY(nsIEventTarget) + NS_INTERFACE_MAP_ENTRY(nsISupports) +#ifdef DEBUG + // kDEBUGWorkerEventTargetIID is special in that it does not AddRef its + // result. + if (aIID.Equals(kDEBUGWorkerEventTargetIID)) { + *aInstancePtr = this; + return NS_OK; + } + else +#endif +NS_INTERFACE_MAP_END + +template +NS_IMETHODIMP +WorkerPrivateParent:: +EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) +{ + // May be called on any thread! + + // Workers only support asynchronous dispatch for now. + if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) { + return NS_ERROR_UNEXPECTED; + } + + nsRefPtr workerRunnable; + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + NS_WARNING("A runnable was posted to a worker that is already shutting " + "down!"); + return NS_ERROR_UNEXPECTED; + } + + if (aRunnable) { + workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable); + } + + nsresult rv = + mWorkerPrivate->DispatchPrivate(workerRunnable, mNestedEventTarget); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +template +NS_IMETHODIMP +WorkerPrivateParent:: +EventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) +{ + // May be called on any thread! + + MOZ_ASSERT(aIsOnCurrentThread); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + NS_WARNING("A worker's event target was used after the worker has !"); + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = mWorkerPrivate->IsOnCurrentThread(aIsOnCurrentThread); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + BEGIN_WORKERS_NAMESPACE WorkerCrossThreadDispatcher* @@ -5520,14 +5921,6 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker) return w->GetCrossThreadDispatcher(); } -// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the -// templates. -template <> -WorkerPrivateParent::cycleCollection WorkerPrivateParent::_cycleCollectorGlobal = WorkerPrivateParent::cycleCollection(); - -// Force instantiation. -template class WorkerPrivateParent; - JSStructuredCloneCallbacks* WorkerStructuredCloneCallbacks(bool aMainRuntime) { @@ -5544,4 +5937,7 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime) &gChromeWorkerStructuredCloneCallbacks; } +// Force instantiation. +template class WorkerPrivateParent; + END_WORKERS_NAMESPACE diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index bac29ee7f9c4..b553d7e08b31 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -9,25 +9,19 @@ #include "Workers.h" #include "nsIContentSecurityPolicy.h" -#include "nsIRunnable.h" -#include "nsIThread.h" -#include "nsIThreadInternal.h" #include "nsPIDOMWindow.h" -#include "mozilla/Assertions.h" #include "mozilla/CondVar.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsCycleCollectionParticipant.h" #include "nsDataHashtable.h" #include "nsDOMEventTargetHelper.h" -#include "nsEventQueue.h" #include "nsHashKeys.h" #include "nsRefPtrHashtable.h" #include "nsString.h" #include "nsTArray.h" #include "nsThreadUtils.h" -#include "nsTPriorityQueue.h" #include "StructuredCloneTags.h" #include "Queue.h" @@ -36,8 +30,10 @@ class JSAutoStructuredCloneBuffer; class nsIChannel; class nsIDocument; +class nsIEventTarget; class nsIPrincipal; class nsIScriptContext; +class nsIThread; class nsITimer; class nsIURI; @@ -51,142 +47,19 @@ class Function; } } -BEGIN_WORKERS_NAMESPACE - -class MessagePort; -class SharedWorker; -class WorkerGlobalScope; -class WorkerPrivate; - -class WorkerRunnable : public nsIRunnable -{ -public: - enum Target { ParentThread, WorkerThread }; - enum BusyBehavior { ModifyBusyCount, UnchangedBusyCount }; - enum ClearingBehavior { SkipWhenClearing, RunWhenClearing }; - -protected: - WorkerPrivate* mWorkerPrivate; - Target mTarget; - BusyBehavior mBusyBehavior; - ClearingBehavior mClearingBehavior; - -public: - NS_DECL_THREADSAFE_ISUPPORTS - - bool - Dispatch(JSContext* aCx); - - static bool - DispatchToMainThread(nsIRunnable*); - - bool - WantsToRunDuringClear() - { - return mClearingBehavior == RunWhenClearing; - } - -protected: - WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget, - BusyBehavior aBusyBehavior, - ClearingBehavior aClearingBehavior) #ifdef DEBUG - ; -#else - : mWorkerPrivate(aWorkerPrivate), mTarget(aTarget), - mBusyBehavior(aBusyBehavior), mClearingBehavior(aClearingBehavior) - { } +struct PRThread; #endif - virtual ~WorkerRunnable() - { } +BEGIN_WORKERS_NAMESPACE - virtual bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate); - - virtual void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult); - - virtual bool - DispatchInternal(); - - virtual bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; - - virtual void - PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); - -public: - NS_DECL_NSIRUNNABLE -}; - -class WorkerSyncRunnable : public WorkerRunnable -{ -protected: - uint32_t mSyncQueueKey; - bool mBypassSyncQueue; - -protected: - friend class WorkerPrivate; - - WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, uint32_t aSyncQueueKey, - bool aBypassSyncQueue = false, - ClearingBehavior aClearingBehavior = SkipWhenClearing) - : WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount, - aClearingBehavior), - mSyncQueueKey(aSyncQueueKey), mBypassSyncQueue(aBypassSyncQueue) - { } - - virtual ~WorkerSyncRunnable() - { } - - virtual bool - DispatchInternal() MOZ_OVERRIDE; -}; - -class MainThreadSyncRunnable : public WorkerSyncRunnable -{ -public: - MainThreadSyncRunnable(WorkerPrivate* aWorkerPrivate, - ClearingBehavior aClearingBehavior, - uint32_t aSyncQueueKey, - bool aBypassSyncEventQueue) - : WorkerSyncRunnable(aWorkerPrivate, aSyncQueueKey, aBypassSyncEventQueue, - aClearingBehavior) - { - AssertIsOnMainThread(); - } - - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE - { - AssertIsOnMainThread(); - return true; - } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) MOZ_OVERRIDE - { - AssertIsOnMainThread(); - } -}; - -class WorkerControlRunnable : public WorkerRunnable -{ -protected: - WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget, - BusyBehavior aBusyBehavior) - : WorkerRunnable(aWorkerPrivate, aTarget, aBusyBehavior, SkipWhenClearing) - { } - - virtual ~WorkerControlRunnable() - { } - - virtual bool - DispatchInternal() MOZ_OVERRIDE; -}; +class AutoSyncLoopHolder; +class MessagePort; +class SharedWorker; +class WorkerControlRunnable; +class WorkerGlobalScope; +class WorkerPrivate; +class WorkerRunnable; // SharedMutex is a small wrapper around an (internal) reference-counted Mutex // object. It exists to avoid changing a lot of code to use Mutex* instead of @@ -195,7 +68,7 @@ class SharedMutex { typedef mozilla::Mutex Mutex; - class RefCountedMutex : public Mutex + class RefCountedMutex MOZ_FINAL : public Mutex { public: RefCountedMutex(const char* aName) @@ -222,20 +95,17 @@ public: operator Mutex&() { - MOZ_ASSERT(mMutex); return *mMutex; } operator const Mutex&() const { - MOZ_ASSERT(mMutex); return *mMutex; } void AssertCurrentThreadOwns() const { - MOZ_ASSERT(mMutex); mMutex->AssertCurrentThreadOwns(); } }; @@ -245,6 +115,10 @@ class WorkerPrivateParent : public nsDOMEventTargetHelper { class SynchronizeAndResumeRunnable; +protected: + class EventTarget; + friend class EventTarget; + public: struct LocationInfo { @@ -312,6 +186,10 @@ protected: mozilla::CondVar mCondVar; mozilla::CondVar mMemoryReportCondVar; + // Protected by mMutex. + nsRefPtr mEventTarget; + nsTArray> mPreStartRunnables; + private: WorkerPrivate* mParent; nsString mScriptURL; @@ -322,7 +200,7 @@ private: LoadInfo mLoadInfo; // Only used for top level workers. - nsTArray > mQueuedRunnables; + nsTArray> mQueuedRunnables; nsRevocableEventPtr mSynchronizeRunnable; // Only for ChromeWorkers without window and only touched on the main thread. @@ -376,6 +254,9 @@ private: bool aToMessagePort, uint64_t aMessagePortSerial, ErrorResult& aRv); + nsresult + DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget); + public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; @@ -384,6 +265,21 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent, nsDOMEventTargetHelper) + nsresult + Dispatch(WorkerRunnable* aRunnable) + { + return DispatchPrivate(aRunnable, nullptr); + } + + nsresult + DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable); + + already_AddRefed + MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable); + + already_AddRefed + GetEventTarget(); + // May be called on any thread... bool Start(); @@ -515,7 +411,7 @@ public: WorkerScriptLoaded(); void - QueueRunnable(WorkerRunnable* aRunnable) + QueueRunnable(nsIRunnable* aRunnable) { AssertIsOnMainThread(); mQueuedRunnables.AppendElement(aRunnable); @@ -538,13 +434,10 @@ public: IsAcceptingEvents() { AssertIsOnParentThread(); - bool acceptingEvents; - { - mozilla::MutexAutoLock lock(mMutex); - acceptingEvents = mParentStatus < Terminating; + + MutexAutoLock lock(mMutex); + return mParentStatus < Terminating; } - return acceptingEvents; - } Status ParentStatus() const @@ -775,53 +668,62 @@ class WorkerPrivate : public WorkerPrivateParent { friend class WorkerPrivateParent; typedef WorkerPrivateParent ParentType; + friend class AutoSyncLoopHolder; struct TimeoutInfo; - typedef Queue EventQueue; - EventQueue mQueue; - EventQueue mControlQueue; - - struct SyncQueue - { - Queue mQueue; - bool mComplete; - bool mResult; - - SyncQueue() - : mComplete(false), mResult(false) - { } - - ~SyncQueue() - { - WorkerRunnable* event; - while (mQueue.Pop(event)) { - event->Release(); - } - } - }; - class MemoryReporter; friend class MemoryReporter; - nsTArray > mSyncQueues; + enum GCTimerMode + { + PeriodicTimer = 0, + IdleTimer, + NoTimer + }; + + Queue mControlQueue; // Touched on multiple threads, protected with mMutex. JSContext* mJSContext; nsRefPtr mCrossThreadDispatcher; + nsTArray> mUndispatchedRunnablesForSyncLoop; + nsCOMPtr mThread; // Things touched on worker thread only. nsRefPtr mScope; nsTArray mChildWorkers; nsTArray mFeatures; - nsTArray > mTimeouts; + nsTArray> mTimeouts; + + struct SyncLoopInfo + { + SyncLoopInfo(EventTarget* aEventTarget); + + nsRefPtr mEventTarget; + bool mCompleted; + bool mResult; +#ifdef DEBUG + bool mHasRun; +#endif + }; + + // This is only modified on the worker thread, but in DEBUG builds + // AssertValidSyncLoop function iterates it on other threads. Therefore + // modifications are done with mMutex held *only* in DEBUG builds. + nsTArray> mSyncLoopStack; nsCOMPtr mTimer; + + nsCOMPtr mGCTimer; + nsCOMPtr mPeriodicGCTimerTarget; + nsCOMPtr mIdleGCTimerTarget; + nsRefPtr mMemoryReporter; nsRefPtrHashtable mWorkerPorts; - mozilla::TimeStamp mKillTime; + TimeStamp mKillTime; uint32_t mErrorHandlerRecursionCount; uint32_t mNextTimeoutId; Status mStatus; @@ -832,9 +734,11 @@ class WorkerPrivate : public WorkerPrivateParent bool mCloseHandlerFinished; bool mMemoryReporterRunning; bool mBlockedForMemoryReporter; + bool mCancelAllPendingRunnables; + bool mPeriodicGCTimerRunning; #ifdef DEBUG - nsCOMPtr mThread; + PRThread* mPRThread; #endif bool mPreferences[WORKERPREF_COUNT]; @@ -867,27 +771,8 @@ public: bool OperationCallback(JSContext* aCx); - bool - Dispatch(WorkerRunnable* aEvent) - { - return Dispatch(aEvent, &mQueue); - } - - bool - Dispatch(WorkerSyncRunnable* aEvent) - { - if (aEvent->mBypassSyncQueue) { - return Dispatch(aEvent, &mQueue); - } - - return DispatchToSyncQueue(aEvent); - } - - bool - Dispatch(WorkerControlRunnable* aEvent) - { - return Dispatch(aEvent, &mControlQueue); - } + nsresult + IsOnCurrentThread(bool* aIsOnCurrentThread); bool CloseInternal(JSContext* aCx) @@ -930,18 +815,6 @@ public: mFeatures.IsEmpty()); } - uint32_t - CreateNewSyncLoop(); - - bool - RunSyncLoop(JSContext* aCx, uint32_t aSyncLoopKey); - - void - StopSyncLoop(uint32_t aSyncLoopKey, bool aSyncResult); - - void - DestroySyncLoop(uint32_t aSyncLoopKey); - void PostMessageToParent(JSContext* aCx, JS::Handle aMessage, @@ -1008,7 +881,7 @@ public: UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue); void - ScheduleDeletion(bool aWasPending); + ScheduleDeletion(); bool BlockAndCollectRuntimeStats(JS::RuntimeStats* aRtStats); @@ -1042,18 +915,14 @@ public: return mScope; } -#ifdef DEBUG void - AssertIsOnWorkerThread() const; + SetThread(nsIThread* aThread); - void - SetThread(nsIThread* aThread) - { - mThread = aThread; - } -#else void AssertIsOnWorkerThread() const +#ifdef DEBUG + ; +#else { } #endif @@ -1113,20 +982,37 @@ public: return mPreferences[WORKERPREF_PROMISE]; } + void + StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult); + + bool + AllPendingRunnablesShouldBeCanceled() const + { + return mCancelAllPendingRunnables; + } + + void + OnProcessNextEvent(uint32_t aRecursionDepth); + + void + AfterProcessNextEvent(uint32_t aRecursionDepth); + + void + AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget) +#ifdef DEBUG + ; +#else + { } +#endif + private: WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerType aWorkerType, const nsAString& aSharedWorkerName, LoadInfo& aLoadInfo); - bool - Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue); - - bool - DispatchToSyncQueue(WorkerSyncRunnable* aEvent); - void - ClearQueue(EventQueue* aQueue); + ClearMainEventQueue(); bool MayContinueRunning() @@ -1135,7 +1021,7 @@ private: Status status; { - mozilla::MutexAutoLock lock(mMutex); + MutexAutoLock lock(mMutex); status = mStatus; } @@ -1157,22 +1043,15 @@ private: bool ScheduleKillCloseEventRunnable(JSContext* aCx); - void - StopAcceptingEvents() + bool + ProcessAllControlRunnables() { - AssertIsOnWorkerThread(); - - mozilla::MutexAutoLock lock(mMutex); - - mStatus = Dead; - mJSContext = nullptr; - - ClearQueue(&mControlQueue); - ClearQueue(&mQueue); + MutexAutoLock lock(mMutex); + return ProcessAllControlRunnablesLocked(); } bool - ProcessAllControlRunnables(); + ProcessAllControlRunnablesLocked(); void EnableMemoryReporter(); @@ -1197,6 +1076,21 @@ private: AssertIsOnWorkerThread(); memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool)); } + + already_AddRefed + CreateNewSyncLoop(); + + bool + RunCurrentSyncLoop(); + + void + InitializeGCTimers(); + + void + SetGCTimerMode(GCTimerMode aMode); + + void + ShutdownGCTimers(); }; // This class is only used to trick the DOM bindings. We never create @@ -1246,38 +1140,40 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime); class AutoSyncLoopHolder { + WorkerPrivate* mWorkerPrivate; + nsCOMPtr mTarget; + public: AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate) - : mWorkerPrivate(aWorkerPrivate), mSyncLoopKey(UINT32_MAX) + : mWorkerPrivate(aWorkerPrivate), mTarget(aWorkerPrivate->CreateNewSyncLoop()) { - mSyncLoopKey = mWorkerPrivate->CreateNewSyncLoop(); + aWorkerPrivate->AssertIsOnWorkerThread(); } ~AutoSyncLoopHolder() { if (mWorkerPrivate) { - mWorkerPrivate->StopSyncLoop(mSyncLoopKey, false); - mWorkerPrivate->DestroySyncLoop(mSyncLoopKey); + mWorkerPrivate->AssertIsOnWorkerThread(); + mWorkerPrivate->StopSyncLoop(mTarget, false); } } bool - RunAndForget(JSContext* aCx) + Run() { WorkerPrivate* workerPrivate = mWorkerPrivate; mWorkerPrivate = nullptr; - return workerPrivate->RunSyncLoop(aCx, mSyncLoopKey); + + workerPrivate->AssertIsOnWorkerThread(); + + return workerPrivate->RunCurrentSyncLoop(); } - uint32_t - SyncQueueKey() const + nsIEventTarget* + EventTarget() const { - return mSyncLoopKey; + return mTarget; } - -private: - WorkerPrivate* mWorkerPrivate; - uint32_t mSyncLoopKey; }; END_WORKERS_NAMESPACE diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp new file mode 100644 index 000000000000..e9bdb3e43b55 --- /dev/null +++ b/dom/workers/WorkerRunnable.cpp @@ -0,0 +1,480 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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 "WorkerRunnable.h" + +#include "nsIEventTarget.h" +#include "nsIRunnable.h" + +#include "js/RootingAPI.h" +#include "js/Value.h" +#include "nsThreadUtils.h" + +#include "WorkerPrivate.h" + +USING_WORKERS_NAMESPACE + +namespace { + +const nsIID kWorkerRunnableIID = { + 0x320cc0b5, 0xef12, 0x4084, { 0x88, 0x6e, 0xca, 0x6a, 0x81, 0xe4, 0x1d, 0x68 } +}; + +void +MaybeReportMainThreadException(JSContext* aCx, bool aResult) +{ + AssertIsOnMainThread(); + + if (aCx && !aResult) { + JS_ReportPendingException(aCx); + } +} + +} // anonymous namespace + +#ifdef DEBUG +WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate, + TargetAndBusyBehavior aBehavior) +: mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0), + mCallingCancelWithinRun(false) +{ + MOZ_ASSERT(aWorkerPrivate); +} +#endif + +bool +WorkerRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +{ +#ifdef DEBUG + MOZ_ASSERT(aWorkerPrivate); + + switch (mBehavior) { + case ParentThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnWorkerThread(); + break; + + case WorkerThreadModifyBusyCount: + aWorkerPrivate->AssertIsOnParentThread(); + MOZ_ASSERT(aCx); + break; + + case WorkerThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnParentThread(); + break; + + default: + MOZ_ASSUME_UNREACHABLE("Unknown behavior!"); + } +#endif + + if (mBehavior == WorkerThreadModifyBusyCount) { + return aWorkerPrivate->ModifyBusyCount(aCx, true); + } + + return true; +} + +bool +WorkerRunnable::Dispatch(JSContext* aCx) +{ + bool ok; + + if (!aCx) { + ok = PreDispatch(nullptr, mWorkerPrivate); + if (ok) { + ok = DispatchInternal(); + } + PostDispatch(nullptr, mWorkerPrivate, ok); + return ok; + } + + JSAutoRequest ar(aCx); + + JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); + + Maybe ac; + if (global) { + ac.construct(aCx, global); + } + + ok = PreDispatch(aCx, mWorkerPrivate); + + if (ok && !DispatchInternal()) { + ok = false; + } + + PostDispatch(aCx, mWorkerPrivate, ok); + + return ok; +} + +bool +WorkerRunnable::DispatchInternal() +{ + if (mBehavior == WorkerThreadModifyBusyCount || + mBehavior == WorkerThreadUnchangedBusyCount) { + return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this)); + } + + MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount); + + if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) { + return NS_SUCCEEDED(parent->Dispatch(this)); + } + + nsCOMPtr mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + + return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL)); +} + +void +WorkerRunnable::PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) +{ + MOZ_ASSERT(aWorkerPrivate); + +#ifdef DEBUG + switch (mBehavior) { + case ParentThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnWorkerThread(); + break; + + case WorkerThreadModifyBusyCount: + aWorkerPrivate->AssertIsOnParentThread(); + MOZ_ASSERT(aCx); + break; + + case WorkerThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnParentThread(); + break; + + default: + MOZ_ASSUME_UNREACHABLE("Unknown behavior!"); + } +#endif + + if (!aDispatchResult) { + if (mBehavior == WorkerThreadModifyBusyCount) { + aWorkerPrivate->ModifyBusyCount(aCx, false); + } + if (aCx) { + JS_ReportPendingException(aCx); + } + } +} + +void +WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aRunResult) +{ + MOZ_ASSERT(aCx); + MOZ_ASSERT(aWorkerPrivate); + +#ifdef DEBUG + switch (mBehavior) { + case ParentThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnParentThread(); + break; + + case WorkerThreadModifyBusyCount: + aWorkerPrivate->AssertIsOnWorkerThread(); + break; + + case WorkerThreadUnchangedBusyCount: + aWorkerPrivate->AssertIsOnWorkerThread(); + break; + + default: + MOZ_ASSUME_UNREACHABLE("Unknown behavior!"); + } +#endif + + if (mBehavior == WorkerThreadModifyBusyCount) { + if (!aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false)) { + aRunResult = false; + } + } + + if (!aRunResult) { + JS_ReportPendingException(aCx); + } +} + +// static +WorkerRunnable* +WorkerRunnable::FromRunnable(nsIRunnable* aRunnable) +{ + MOZ_ASSERT(aRunnable); + + WorkerRunnable* runnable; + nsresult rv = aRunnable->QueryInterface(kWorkerRunnableIID, + reinterpret_cast(&runnable)); + if (NS_FAILED(rv)) { + return nullptr; + } + + MOZ_ASSERT(runnable); + return runnable; +} + +NS_IMPL_ADDREF(WorkerRunnable) +NS_IMPL_RELEASE(WorkerRunnable) + +NS_INTERFACE_MAP_BEGIN(WorkerRunnable) + NS_INTERFACE_MAP_ENTRY(nsIRunnable) + NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable) + NS_INTERFACE_MAP_ENTRY(nsISupports) + // kWorkerRunnableIID is special in that it does not AddRef its result. + if (aIID.Equals(kWorkerRunnableIID)) { + *aInstancePtr = this; + return NS_OK; + } + else +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +WorkerRunnable::Run() +{ + bool targetIsWorkerThread = mBehavior == WorkerThreadModifyBusyCount || + mBehavior == WorkerThreadUnchangedBusyCount; + +#ifdef DEBUG + MOZ_ASSERT_IF(mCallingCancelWithinRun, targetIsWorkerThread); + if (targetIsWorkerThread) { + mWorkerPrivate->AssertIsOnWorkerThread(); + } + else { + MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount); + mWorkerPrivate->AssertIsOnParentThread(); + } +#endif + + if (IsCanceled() && !mCallingCancelWithinRun) { + return NS_OK; + } + + JSContext* cx; + nsRefPtr kungFuDeathGrip; + nsCxPusher pusher; + + if (targetIsWorkerThread) { + if (mWorkerPrivate->AllPendingRunnablesShouldBeCanceled() && + !IsCanceled() && + !mCallingCancelWithinRun) { + + // Prevent recursion. + mCallingCancelWithinRun = true; + + Cancel(); + + MOZ_ASSERT(mCallingCancelWithinRun); + mCallingCancelWithinRun = false; + + MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!"); + + return NS_OK; + } + + cx = mWorkerPrivate->GetJSContext(); + MOZ_ASSERT(cx); + } + else { + cx = mWorkerPrivate->ParentJSContext(); + MOZ_ASSERT(cx); + + kungFuDeathGrip = mWorkerPrivate; + + if (!mWorkerPrivate->GetParent()) { + AssertIsOnMainThread(); + pusher.Push(cx); + } + } + + JSAutoRequest ar(cx); + + JS::Rooted targetCompartmentObject(cx); + if (targetIsWorkerThread) { + targetCompartmentObject = JS::CurrentGlobalOrNull(cx); + } else { + targetCompartmentObject = mWorkerPrivate->GetWrapper(); + } + + Maybe ac; + if (targetCompartmentObject) { + ac.construct(cx, targetCompartmentObject); + } + + bool result = WorkerRun(cx, mWorkerPrivate); + + // In the case of CompileScriptRunnnable, WorkerRun above can cause us to + // lazily create a global, in which case we need to be in its compartment + // when calling PostRun() below. Maybe<> this time... + if (targetIsWorkerThread && + ac.empty() && + js::DefaultObjectForContextOrNull(cx)) { + ac.construct(cx, js::DefaultObjectForContextOrNull(cx)); + } + + PostRun(cx, mWorkerPrivate, result); + + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +WorkerRunnable::Cancel() +{ + uint32_t canceledCount = ++mCanceled; + + MOZ_ASSERT(canceledCount, "Cancel() overflow!"); + + // The docs say that Cancel() should not be called more than once and that we + // should throw NS_ERROR_UNEXPECTED if it is. + return (canceledCount == 1) ? NS_OK : NS_ERROR_UNEXPECTED; +} + +WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, + nsIEventTarget* aSyncLoopTarget) +: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), + mSyncLoopTarget(aSyncLoopTarget) +{ +#ifdef DEBUG + if (mSyncLoopTarget) { + mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget); + } +#endif +} + +WorkerSyncRunnable::WorkerSyncRunnable( + WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget) +: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), + mSyncLoopTarget(aSyncLoopTarget) +{ +#ifdef DEBUG + if (mSyncLoopTarget) { + mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget); + } +#endif +} + +WorkerSyncRunnable::~WorkerSyncRunnable() +{ +} + +bool +WorkerSyncRunnable::DispatchInternal() +{ + if (mSyncLoopTarget) { + return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL)); + } + + return WorkerRunnable::DispatchInternal(); +} + +void +MainThreadWorkerSyncRunnable::PostDispatch(JSContext* aCx, + WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) +{ + MaybeReportMainThreadException(aCx, aDispatchResult); +} + +StopSyncLoopRunnable::StopSyncLoopRunnable( + WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget, + bool aResult) +: WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget), mResult(aResult) +{ +#ifdef DEBUG + mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget); +#endif +} + +NS_IMETHODIMP +StopSyncLoopRunnable::Cancel() +{ + nsresult rv = Run(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +bool +StopSyncLoopRunnable::WorkerRun(JSContext* aCx, + WorkerPrivate* aWorkerPrivate) +{ + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mSyncLoopTarget); + + nsCOMPtr syncLoopTarget; + mSyncLoopTarget.swap(syncLoopTarget); + + if (!mResult) { + MaybeSetException(aCx); + } + + aWorkerPrivate->StopSyncLoop(syncLoopTarget, mResult); + return true; +} + +bool +StopSyncLoopRunnable::DispatchInternal() +{ + MOZ_ASSERT(mSyncLoopTarget); + + return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL)); +} + +void +MainThreadStopSyncLoopRunnable::PostDispatch(JSContext* aCx, + WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) +{ + MaybeReportMainThreadException(aCx, aDispatchResult); +} + +#ifdef DEBUG +WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, + TargetAndBusyBehavior aBehavior) +: WorkerRunnable(aWorkerPrivate, aBehavior) +{ + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aBehavior == ParentThreadUnchangedBusyCount || + aBehavior == WorkerThreadUnchangedBusyCount, + "WorkerControlRunnables should not modify the busy count"); +} +#endif + +bool +WorkerControlRunnable::DispatchInternal() +{ + if (mBehavior == WorkerThreadUnchangedBusyCount) { + return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(this)); + } + + if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) { + return NS_SUCCEEDED(parent->DispatchControlRunnable(this)); + } + + nsCOMPtr mainThread = do_GetMainThread(); + MOZ_ASSERT(mainThread); + + return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL)); +} + +void +MainThreadWorkerControlRunnable::PostDispatch(JSContext* aCx, + WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) +{ + AssertIsOnMainThread(); + + if (aCx && !aDispatchResult) { + JS_ReportPendingException(aCx); + } +} + +NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable) diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h new file mode 100644 index 000000000000..84acd46f443c --- /dev/null +++ b/dom/workers/WorkerRunnable.h @@ -0,0 +1,319 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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 mozilla_dom_workers_workerrunnable_h__ +#define mozilla_dom_workers_workerrunnable_h__ + +#include "Workers.h" + +#include "nsICancelableRunnable.h" + +#include "mozilla/Atomics.h" +#include "nsISupportsImpl.h" + +class JSContext; +class nsIEventTarget; + +BEGIN_WORKERS_NAMESPACE + +class WorkerPrivate; + +// Use this runnable to communicate from the worker to its parent or vice-versa. +// The busy count must be taken into consideration and declared at construction +// time. +class WorkerRunnable : public nsICancelableRunnable +{ +public: + enum TargetAndBusyBehavior { + // Target the main thread for top-level workers, otherwise target the + // WorkerThread of the worker's parent. No change to the busy count. + ParentThreadUnchangedBusyCount, + + // Target the thread where the worker event loop runs. The busy count will + // be incremented before dispatching and decremented (asynchronously) after + // running. + WorkerThreadModifyBusyCount, + + // Target the thread where the worker event loop runs. The busy count will + // not be modified in any way. Besides worker-internal runnables this is + // almost always the wrong choice. + WorkerThreadUnchangedBusyCount + }; + +protected: + // The WorkerPrivate that this runnable is associated with. + WorkerPrivate* mWorkerPrivate; + + // See above. + TargetAndBusyBehavior mBehavior; + + // It's unclear whether or not Cancel() is supposed to work when called on any + // thread. To be safe we're using an atomic but it's likely overkill. + Atomic mCanceled; + +private: + // Whether or not Cancel() is currently being called from inside the Run() + // method. Avoids infinite recursion when a subclass calls Run() from inside + // Cancel(). Only checked and modified on the target thread. + bool mCallingCancelWithinRun; + +public: + NS_DECL_THREADSAFE_ISUPPORTS + + // If you override Cancel() then you'll need to either call the base class + // Cancel() method or override IsCanceled() so that the Run() method bails out + // appropriately. + NS_DECL_NSICANCELABLERUNNABLE + + // Passing a JSContext here is required for the WorkerThreadModifyBusyCount + // behavior. It also guarantees that any failure (false return) will throw an + // exception on the given context. If a context is not passed then failures + // must be dealt with by the caller. + bool + Dispatch(JSContext* aCx); + + // See above note about Cancel(). + virtual bool + IsCanceled() const + { + return mCanceled != 0; + } + + static WorkerRunnable* + FromRunnable(nsIRunnable* aRunnable); + +protected: + WorkerRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior) +#ifdef DEBUG + ; +#else + : mWorkerPrivate(aWorkerPrivate), mBehavior(aBehavior), mCanceled(0), + mCallingCancelWithinRun(false) + { } +#endif + + // This class is reference counted. + virtual ~WorkerRunnable() + { } + + // By default asserts that Dispatch() is being called on the right thread + // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). + // Also increments the busy count of |mWorkerPrivate| if targeting the + // WorkerThread. + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate); + + // By default asserts that Dispatch() is being called on the right thread + // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). + // Also reports any Dispatch() failures as an exception on |aCx|, and + // busy count if targeting the WorkerThread and Dispatch() failed. + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult); + + // Must be implemented by subclasses. Called on the target thread. + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; + + // By default asserts that Run() (and WorkerRun()) were called on the correct + // thread. Any failures (false return from WorkerRun) are reported on |aCx|. + // Also sends an asynchronous message to the ParentThread if the busy + // count was previously modified in PreDispatch(). + virtual void + PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); + + virtual bool + DispatchInternal(); + + // Calling Run() directly is not supported. Just call Dispatch() and + // WorkerRun() will be called on the correct thread automatically. + NS_DECL_NSIRUNNABLE +}; + +// This runnable is used to send a message directly to a worker's sync loop. +class WorkerSyncRunnable : public WorkerRunnable +{ +protected: + nsCOMPtr mSyncLoopTarget; + + // Passing null for aSyncLoopTarget is allowed and will result in the behavior + // of a normal WorkerRunnable. + WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, + nsIEventTarget* aSyncLoopTarget); + + WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget); + + virtual ~WorkerSyncRunnable(); + +private: + virtual bool + DispatchInternal() MOZ_OVERRIDE; +}; + +// This runnable is identical to WorkerSyncRunnable except it is meant to be +// used on the main thread only. +class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable +{ +protected: + // Passing null for aSyncLoopTarget is allowed and will result in the behavior + // of a normal WorkerRunnable. + MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, + nsIEventTarget* aSyncLoopTarget) + : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) + { + AssertIsOnMainThread(); + } + + MainThreadWorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget) + : WorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget) + { + AssertIsOnMainThread(); + } + + virtual ~MainThreadWorkerSyncRunnable() + { } + +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + AssertIsOnMainThread(); + return true; + } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE; +}; + +// This runnable is used to stop a sync loop . As sync loops keep the busy count +// incremented as long as they run this runnable does not modify the busy count +// in any way. +class StopSyncLoopRunnable : public WorkerSyncRunnable +{ + bool mResult; + +public: + // Passing null for aSyncLoopTarget is not allowed. + StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget, + bool aResult); + + // By default StopSyncLoopRunnables cannot be canceled since they could leave + // a sync loop spinning forever. + NS_DECL_NSICANCELABLERUNNABLE + +protected: + virtual ~StopSyncLoopRunnable() + { } + + // Called on the worker thread to set an exception on the context if mResult + // is false. Override if you need an exception. + virtual void + MaybeSetException(JSContext* aCx) + { } + +private: + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; + + virtual bool + DispatchInternal() MOZ_OVERRIDE; +}; + +// This runnable is identical to StopSyncLoopRunnable except it is meant to be +// used on the main thread only. +class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable +{ +public: + // Passing null for aSyncLoopTarget is not allowed. + MainThreadStopSyncLoopRunnable( + WorkerPrivate* aWorkerPrivate, + already_AddRefed aSyncLoopTarget, + bool aResult) + : StopSyncLoopRunnable(aWorkerPrivate, aSyncLoopTarget, aResult) + { + AssertIsOnMainThread(); + } + +protected: + virtual ~MainThreadStopSyncLoopRunnable() + { } + +private: + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + AssertIsOnMainThread(); + return true; + } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE; +}; + +// This runnable is processed as soon as it is received by the worker, +// potentially running before previously queued runnables and perhaps even with +// other JS code executing on the stack. These runnables must not alter the +// state of the JS runtime and should only twiddle state values. The busy count +// is never modified. +class WorkerControlRunnable : public WorkerRunnable +{ + friend class WorkerPrivate; + +protected: + WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, + TargetAndBusyBehavior aBehavior) +#ifdef DEBUG + ; +#else + : WorkerRunnable(aWorkerPrivate, aBehavior) + { } +#endif + + virtual ~WorkerControlRunnable() + { } + +public: + NS_DECL_ISUPPORTS_INHERITED + +private: + virtual bool + DispatchInternal() MOZ_OVERRIDE; + + // Should only be called by WorkerPrivate::DoRunLoop. + using WorkerRunnable::Cancel; +}; + +// A convenience class for WorkerControlRunnables that originate on the main +// thread. +class MainThreadWorkerControlRunnable : public WorkerControlRunnable +{ +protected: + MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) + { } + + virtual ~MainThreadWorkerControlRunnable() + { } + + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + AssertIsOnMainThread(); + return true; + } + + virtual void + PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) MOZ_OVERRIDE; +}; + +END_WORKERS_NAMESPACE + +#endif // mozilla_dom_workers_workerrunnable_h__ diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 5b7c51ead740..2af5a6e3fb77 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -184,39 +184,50 @@ SuspendWorkersForWindow(nsPIDOMWindow* aWindow); void ResumeWorkersForWindow(nsPIDOMWindow* aWindow); -class WorkerTask { +class WorkerTask +{ +protected: + WorkerTask() + { } + + virtual ~WorkerTask() + { } + public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask) - virtual ~WorkerTask() { } - - virtual bool RunTask(JSContext* aCx) = 0; + virtual bool + RunTask(JSContext* aCx) = 0; }; -class WorkerCrossThreadDispatcher { +class WorkerCrossThreadDispatcher +{ + friend class WorkerPrivate; + + // Must be acquired *before* the WorkerPrivate's mutex, when they're both + // held. + Mutex mMutex; + WorkerPrivate* mWorkerPrivate; + +private: + // Only created by WorkerPrivate. + WorkerCrossThreadDispatcher(WorkerPrivate* aWorkerPrivate); + + // Only called by WorkerPrivate. + void + Forget() + { + MutexAutoLock lock(mMutex); + mWorkerPrivate = nullptr; + } + public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerCrossThreadDispatcher) - WorkerCrossThreadDispatcher(WorkerPrivate* aPrivate) : - mMutex("WorkerCrossThreadDispatcher"), mPrivate(aPrivate) {} - void Forget() - { - mozilla::MutexAutoLock lock(mMutex); - mPrivate = nullptr; - } - - /** - * Generically useful function for running a bit of C++ code on the worker - * thread. - */ - bool PostTask(WorkerTask* aTask); - -protected: - friend class WorkerPrivate; - - // Must be acquired *before* the WorkerPrivate's mutex, when they're both held. - mozilla::Mutex mMutex; - WorkerPrivate* mPrivate; + // Generically useful function for running a bit of C++ code on the worker + // thread. + bool + PostTask(WorkerTask* aTask); }; WorkerCrossThreadDispatcher* diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 2575efa55a63..701974945031 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -14,21 +14,21 @@ #include "nsIXPConnect.h" #include "jsfriendapi.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/dom/Exceptions.h" +#include "nsComponentManagerUtils.h" #include "nsContentUtils.h" #include "nsCxPusher.h" #include "nsEventDispatcher.h" #include "nsJSUtils.h" #include "nsThreadUtils.h" -#include "mozilla/dom/Exceptions.h" #include "File.h" #include "RuntimeService.h" #include "WorkerPrivate.h" +#include "WorkerRunnable.h" #include "XMLHttpRequestUpload.h" -#include "mozilla/Attributes.h" -#include "nsComponentManagerUtils.h" - using namespace mozilla; using namespace mozilla::dom; @@ -96,6 +96,8 @@ public: // Only touched on the main thread. nsRefPtr mXHR; nsCOMPtr mXHRUpload; + nsCOMPtr mSyncLoopTarget; + nsCOMPtr mSyncEventResponseTarget; uint32_t mInnerEventStreamId; uint32_t mInnerChannelId; uint32_t mOutstandingSendCount; @@ -114,16 +116,11 @@ public: bool mSeenUploadLoadStart; // Only touched on the main thread. - uint32_t mSyncQueueKey; - uint32_t mSyncEventResponseSyncQueueKey; bool mUploadEventListenersAttached; bool mMainThreadSeenLoadStart; bool mInOpen; public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - Proxy(XMLHttpRequest* aXHRPrivate, bool aMozAnon, bool aMozSystem) : mWorkerPrivate(nullptr), mXMLHttpRequestPrivate(aXHRPrivate), mMozAnon(aMozAnon), mMozSystem(aMozSystem), @@ -132,67 +129,15 @@ public: mLastUploadLoaded(0), mLastUploadTotal(0), mIsSyncXHR(false), mLastLengthComputable(false), mLastUploadLengthComputable(false), mSeenLoadStart(false), mSeenUploadLoadStart(false), - mSyncQueueKey(UINT32_MAX), - mSyncEventResponseSyncQueueKey(UINT32_MAX), mUploadEventListenersAttached(false), mMainThreadSeenLoadStart(false), mInOpen(false) { } - ~Proxy() - { - NS_ASSERTION(!mXHR, "Still have an XHR object attached!"); - NS_ASSERTION(!mXHRUpload, "Still have an XHR upload object attached!"); - NS_ASSERTION(!mOutstandingSendCount, "We're dying too early!"); - } + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER bool - Init() - { - AssertIsOnMainThread(); - NS_ASSERTION(mWorkerPrivate, "Must have a worker here!"); - - if (!mXHR) { - nsPIDOMWindow* ownerWindow = mWorkerPrivate->GetWindow(); - if (ownerWindow) { - ownerWindow = ownerWindow->GetOuterWindow(); - if (!ownerWindow) { - NS_ERROR("No outer window?!"); - return false; - } - - nsPIDOMWindow* innerWindow = ownerWindow->GetCurrentInnerWindow(); - if (mWorkerPrivate->GetWindow() != innerWindow) { - NS_WARNING("Window has navigated, cannot create XHR here."); - return false; - } - } - - mXHR = new nsXMLHttpRequest(); - - nsCOMPtr global = do_QueryInterface(ownerWindow); - if (NS_FAILED(mXHR->Init(mWorkerPrivate->GetPrincipal(), - mWorkerPrivate->GetScriptContext(), - global, mWorkerPrivate->GetBaseURI()))) { - mXHR = nullptr; - return false; - } - - mXHR->SetParameters(mMozAnon, mMozSystem); - - if (NS_FAILED(mXHR->GetUpload(getter_AddRefs(mXHRUpload)))) { - mXHR = nullptr; - return false; - } - - if (!AddRemoveEventListeners(false, true)) { - mXHRUpload = nullptr; - mXHR = nullptr; - return false; - } - } - - return true; - } + Init(); void Teardown(); @@ -210,28 +155,28 @@ public: } } - uint32_t - GetSyncQueueKey() + already_AddRefed + GetEventTarget() { AssertIsOnMainThread(); - return mSyncEventResponseSyncQueueKey == UINT32_MAX ? - mSyncQueueKey : - mSyncEventResponseSyncQueueKey; + + nsCOMPtr target = mSyncEventResponseTarget ? + mSyncEventResponseTarget : + mSyncLoopTarget; + return target.forget(); } - bool - EventsBypassSyncQueue() +private: + ~Proxy() { - AssertIsOnMainThread(); - - return mSyncQueueKey == UINT32_MAX && - mSyncEventResponseSyncQueueKey == UINT32_MAX; + MOZ_ASSERT(!mXHR); + MOZ_ASSERT(!mXHRUpload); + MOZ_ASSERT(!mOutstandingSendCount); } }; END_WORKERS_NAMESPACE - namespace { inline void @@ -259,7 +204,7 @@ ConvertStringToResponseType(const nsAString& aString) } } - MOZ_CRASH("Don't know anything about this response type!"); + MOZ_ASSUME_UNREACHABLE("Don't know anything about this response type!"); } enum @@ -279,8 +224,8 @@ enum STRING_LAST_EVENTTARGET = STRING_timeout }; -JS_STATIC_ASSERT(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET); -JS_STATIC_ASSERT(STRING_LAST_XHR == STRING_COUNT - 1); +static_assert(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET, "Bad string setup!"); +static_assert(STRING_LAST_XHR == STRING_COUNT - 1, "Bad string setup!"); const char* const sEventStrings[] = { // nsIXMLHttpRequestEventTarget event types, supported by both XHR and Upload. @@ -296,48 +241,42 @@ const char* const sEventStrings[] = { "loadend", }; -JS_STATIC_ASSERT(JS_ARRAY_LENGTH(sEventStrings) == STRING_COUNT); +static_assert(MOZ_ARRAY_LENGTH(sEventStrings) == STRING_COUNT, + "Bad string count!"); -class MainThreadProxyRunnable : public MainThreadSyncRunnable +class MainThreadProxyRunnable : public MainThreadWorkerSyncRunnable { protected: nsRefPtr mProxy; -public: - MainThreadProxyRunnable(WorkerPrivate* aWorkerPrivate, - ClearingBehavior aClearingBehavior, Proxy* aProxy) - : MainThreadSyncRunnable(aWorkerPrivate, aClearingBehavior, - aProxy->GetSyncQueueKey(), - aProxy->EventsBypassSyncQueue()), + MainThreadProxyRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) + : MainThreadWorkerSyncRunnable(aWorkerPrivate, aProxy->GetEventTarget()), mProxy(aProxy) + { + MOZ_ASSERT(aProxy); + } + + virtual ~MainThreadProxyRunnable() { } }; -class XHRUnpinRunnable : public WorkerControlRunnable +class XHRUnpinRunnable MOZ_FINAL : public MainThreadWorkerControlRunnable { XMLHttpRequest* mXMLHttpRequestPrivate; public: XHRUnpinRunnable(WorkerPrivate* aWorkerPrivate, XMLHttpRequest* aXHRPrivate) - : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount), + : MainThreadWorkerControlRunnable(aWorkerPrivate), mXMLHttpRequestPrivate(aXHRPrivate) + { + MOZ_ASSERT(aXHRPrivate); + } + +private: + ~XHRUnpinRunnable() { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - AssertIsOnMainThread(); - return true; - } - - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - AssertIsOnMainThread(); - } - bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { @@ -347,18 +286,25 @@ public: } }; -class AsyncTeardownRunnable : public nsRunnable +class AsyncTeardownRunnable MOZ_FINAL : public nsRunnable { nsRefPtr mProxy; public: AsyncTeardownRunnable(Proxy* aProxy) + : mProxy(aProxy) { - mProxy = aProxy; - NS_ASSERTION(mProxy, "Null proxy!"); + MOZ_ASSERT(aProxy); } - NS_IMETHOD Run() + NS_DECL_ISUPPORTS_INHERITED + +private: + ~AsyncTeardownRunnable() + { } + + NS_IMETHOD + Run() MOZ_OVERRIDE { AssertIsOnMainThread(); @@ -369,7 +315,7 @@ public: } }; -class LoadStartDetectionRunnable MOZ_FINAL : public nsIRunnable, +class LoadStartDetectionRunnable MOZ_FINAL : public nsRunnable, public nsIDOMEventListener { WorkerPrivate* mWorkerPrivate; @@ -377,10 +323,10 @@ class LoadStartDetectionRunnable MOZ_FINAL : public nsIRunnable, nsRefPtr mXHR; XMLHttpRequest* mXMLHttpRequestPrivate; nsString mEventType; - bool mReceivedLoadStart; uint32_t mChannelId; + bool mReceivedLoadStart; - class ProxyCompleteRunnable : public MainThreadProxyRunnable + class ProxyCompleteRunnable MOZ_FINAL : public MainThreadProxyRunnable { XMLHttpRequest* mXMLHttpRequestPrivate; uint32_t mChannelId; @@ -388,58 +334,54 @@ class LoadStartDetectionRunnable MOZ_FINAL : public nsIRunnable, public: ProxyCompleteRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, XMLHttpRequest* aXHRPrivate, uint32_t aChannelId) - : MainThreadProxyRunnable(aWorkerPrivate, RunWhenClearing, aProxy), + : MainThreadProxyRunnable(aWorkerPrivate, aProxy), mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(aChannelId) { } - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - AssertIsOnMainThread(); - return true; - } + private: + ~ProxyCompleteRunnable() + { } - void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) - { - AssertIsOnMainThread(); - } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE { if (mChannelId != mProxy->mOuterChannelId) { // Threads raced, this event is now obsolete. return true; } - if (mSyncQueueKey != UINT32_MAX) { - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true); + if (mSyncLoopTarget) { + aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, true); } mXMLHttpRequestPrivate->Unpin(); return true; } + + NS_IMETHOD + Cancel() MOZ_OVERRIDE + { + // This must run! + nsresult rv = MainThreadProxyRunnable::Cancel(); + nsresult rv2 = Run(); + return NS_FAILED(rv) ? rv : rv2; + } }; public: - NS_DECL_ISUPPORTS - LoadStartDetectionRunnable(Proxy* aProxy, XMLHttpRequest* aXHRPrivate) : mWorkerPrivate(aProxy->mWorkerPrivate), mProxy(aProxy), mXHR(aProxy->mXHR), - mXMLHttpRequestPrivate(aXHRPrivate), mReceivedLoadStart(false), - mChannelId(mProxy->mInnerChannelId) + mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(mProxy->mInnerChannelId), + mReceivedLoadStart(false) { AssertIsOnMainThread(); mEventType.AssignWithConversion(sEventStrings[STRING_loadstart]); } - ~LoadStartDetectionRunnable() - { - AssertIsOnMainThread(); - } + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIRUNNABLE + NS_DECL_NSIDOMEVENTLISTENER bool RegisterAndDispatch() @@ -454,63 +396,14 @@ public: return NS_SUCCEEDED(NS_DispatchToCurrentThread(this)); } - NS_IMETHOD - Run() +private: + ~LoadStartDetectionRunnable() { AssertIsOnMainThread(); - - if (NS_FAILED(mXHR->RemoveEventListener(mEventType, this, false))) { - NS_WARNING("Failed to remove event listener!"); } - - if (!mReceivedLoadStart) { - if (mProxy->mOutstandingSendCount > 1) { - mProxy->mOutstandingSendCount--; - } else if (mProxy->mOutstandingSendCount == 1) { - mProxy->Reset(); - - nsRefPtr runnable = - new ProxyCompleteRunnable(mWorkerPrivate, mProxy, - mXMLHttpRequestPrivate, - mChannelId); - if (runnable->Dispatch(nullptr)) { - mProxy->mWorkerPrivate = nullptr; - mProxy->mOutstandingSendCount--; - } - } - } - - mProxy = nullptr; - mXHR = nullptr; - mXMLHttpRequestPrivate = nullptr; - return NS_OK; - } - - NS_IMETHOD - HandleEvent(nsIDOMEvent* aEvent) - { - AssertIsOnMainThread(); - -#ifdef DEBUG - { - nsString type; - if (NS_SUCCEEDED(aEvent->GetType(type))) { - NS_ASSERTION(type == mEventType, "Unexpected event type!"); - } - else { - NS_WARNING("Failed to get event type!"); - } - } -#endif - - mReceivedLoadStart = true; - return NS_OK; - } }; -NS_IMPL_ISUPPORTS2(LoadStartDetectionRunnable, nsIRunnable, nsIDOMEventListener) - -class EventRunnable : public MainThreadProxyRunnable +class EventRunnable MOZ_FINAL : public MainThreadProxyRunnable { nsString mType; nsString mResponseType; @@ -532,79 +425,12 @@ class EventRunnable : public MainThreadProxyRunnable nsresult mResponseResult; public: - EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType, - bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal) - : MainThreadProxyRunnable(aProxy->mWorkerPrivate, SkipWhenClearing, aProxy), - mType(aType), mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal), - mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), - mUploadEvent(aUploadEvent), mProgressEvent(true), - mLengthComputable(aLengthComputable), mResponseTextResult(NS_OK), - mStatusResult(NS_OK), mResponseResult(NS_OK) - { } - - EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType) - : MainThreadProxyRunnable(aProxy->mWorkerPrivate, SkipWhenClearing, aProxy), - mType(aType), mResponse(JSVAL_VOID), mLoaded(0), mTotal(0), - mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), - mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0), - mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK) - { } - - bool - PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - nsRefPtr& xhr = mProxy->mXHR; - NS_ASSERTION(xhr, "Must have an XHR here!"); - - if (NS_FAILED(xhr->GetResponseType(mResponseType))) { - NS_ERROR("This should never fail!"); - } - - mResponseTextResult = xhr->GetResponseText(mResponseText); - if (NS_SUCCEEDED(mResponseTextResult)) { - mResponseResult = mResponseTextResult; - if (mResponseText.IsVoid()) { - mResponse = JSVAL_NULL; - } - } - else { - JS::Rooted response(aCx); - mResponseResult = xhr->GetResponse(aCx, response.address()); - if (NS_SUCCEEDED(mResponseResult)) { - if (JSVAL_IS_UNIVERSAL(response)) { - mResponse = response; - } - else { - // Anything subject to GC must be cloned. - JSStructuredCloneCallbacks* callbacks = - aWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(true) : - WorkerStructuredCloneCallbacks(true); - - nsTArray > clonedObjects; - - if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) { - mClonedObjects.SwapElements(clonedObjects); - } - else { - NS_WARNING("Failed to clone response!"); - mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR; - } - } - } - } - - mStatusResult = xhr->GetStatus(&mStatus); - - xhr->GetStatusText(mStatusText); - - mReadyState = xhr->ReadyState(); - - return true; - } - class StateDataAutoRooter : private JS::CustomAutoRooter { + XMLHttpRequest::StateData* mStateData; + js::SkipRoot mSkip; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + public: explicit StateDataAutoRooter(JSContext* aCx, XMLHttpRequest::StateData* aData MOZ_GUARD_OBJECT_NOTIFIER_PARAM) @@ -619,174 +445,35 @@ public: JS_CallHeapValueTracer(aTrc, &mStateData->mResponse, "XMLHttpRequest::StateData::mResponse"); } - - XMLHttpRequest::StateData* mStateData; - js::SkipRoot mSkip; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) - { - if (mEventStreamId != mProxy->mOuterEventStreamId) { - // Threads raced, this event is now obsolete. - return true; - } + EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType, + bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal) + : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType), + mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal), + mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), + mUploadEvent(aUploadEvent), mProgressEvent(true), + mLengthComputable(aLengthComputable), mResponseTextResult(NS_OK), + mStatusResult(NS_OK), mResponseResult(NS_OK) + { } - if (!mProxy->mXMLHttpRequestPrivate) { - // Object was finalized, bail. - return true; - } + EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType) + : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType), + mResponse(JSVAL_VOID), mLoaded(0), mTotal(0), + mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), + mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0), + mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK) + { } - if (mType.EqualsASCII(sEventStrings[STRING_loadstart])) { - if (mUploadEvent) { - mProxy->mSeenUploadLoadStart = true; - } - else { - mProxy->mSeenLoadStart = true; - } - } - else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) { - if (mUploadEvent) { - mProxy->mSeenUploadLoadStart = false; - } - else { - mProxy->mSeenLoadStart = false; - } - } - else if (mType.EqualsASCII(sEventStrings[STRING_abort])) { - if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) || - (!mUploadEvent && !mProxy->mSeenLoadStart)) { - // We've already dispatched premature abort events. - return true; - } - } - else if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) { - if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) { - // We've already dispatched premature abort events. - return true; - } - } +private: + ~EventRunnable() + { } - if (mProgressEvent) { - // Cache these for premature abort events. - if (mUploadEvent) { - mProxy->mLastUploadLengthComputable = mLengthComputable; - mProxy->mLastUploadLoaded = mLoaded; - mProxy->mLastUploadTotal = mTotal; - } - else { - mProxy->mLastLengthComputable = mLengthComputable; - mProxy->mLastLoaded = mLoaded; - mProxy->mLastTotal = mTotal; - } - } + virtual bool + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; - nsAutoPtr state(new XMLHttpRequest::StateData()); - StateDataAutoRooter rooter(aCx, state); - - state->mResponseTextResult = mResponseTextResult; - state->mResponseText = mResponseText; - - if (NS_SUCCEEDED(mResponseTextResult)) { - MOZ_ASSERT(JSVAL_IS_VOID(mResponse) || JSVAL_IS_NULL(mResponse)); - state->mResponseResult = mResponseTextResult; - state->mResponse = mResponse; - } - else { - state->mResponseResult = mResponseResult; - - if (NS_SUCCEEDED(mResponseResult)) { - if (mResponseBuffer.data()) { - MOZ_ASSERT(JSVAL_IS_VOID(mResponse)); - - JSAutoStructuredCloneBuffer responseBuffer; - mResponseBuffer.swap(responseBuffer); - - JSStructuredCloneCallbacks* callbacks = - aWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(false) : - WorkerStructuredCloneCallbacks(false); - - nsTArray > clonedObjects; - clonedObjects.SwapElements(mClonedObjects); - - JS::Rooted response(aCx); - if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) { - return false; - } - - state->mResponse = response; - } - else { - state->mResponse = mResponse; - } - } - } - - state->mStatusResult = mStatusResult; - state->mStatus = mStatus; - - state->mStatusText = mStatusText; - - state->mReadyState = mReadyState; - - XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate; - xhr->UpdateState(*state); - - if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) { - return true; - } - - JS::Rooted type(aCx, JS_NewUCStringCopyN(aCx, mType.get(), mType.Length())); - if (!type) { - return false; - } - - nsXHREventTarget* target; - if (mUploadEvent) { - target = xhr->GetUploadObjectNoCreate(); - } - else { - target = xhr; - } - - MOZ_ASSERT(target); - - nsCOMPtr event; - if (mProgressEvent) { - NS_NewDOMProgressEvent(getter_AddRefs(event), target, nullptr, nullptr); - nsCOMPtr progress = do_QueryInterface(event); - - if (progress) { - progress->InitProgressEvent(mType, false, false, mLengthComputable, - mLoaded, mTotal); - } - } - else { - NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr); - - if (event) { - event->InitEvent(mType, false, false); - } - } - - if (!event) { - return false; - } - - event->SetTrusted(true); - - target->DispatchDOMEvent(nullptr, event, nullptr, nullptr); - - // After firing the event set mResponse to JSVAL_NULL for chunked response - // types. - if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) { - xhr->NullResponseText(); - } - - return true; - } + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; }; class WorkerThreadProxySyncRunnable : public nsRunnable @@ -794,109 +481,96 @@ class WorkerThreadProxySyncRunnable : public nsRunnable protected: WorkerPrivate* mWorkerPrivate; nsRefPtr mProxy; - uint32_t mSyncQueueKey; + nsCOMPtr mSyncLoopTarget; private: - class ResponseRunnable : public MainThreadProxyRunnable + class ResponseRunnable MOZ_FINAL: public MainThreadStopSyncLoopRunnable { - uint32_t mSyncQueueKey; + nsRefPtr mProxy; nsresult mErrorCode; public: ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - uint32_t aSyncQueueKey, nsresult aErrorCode) - : MainThreadProxyRunnable(aWorkerPrivate, SkipWhenClearing, aProxy), - mSyncQueueKey(aSyncQueueKey), mErrorCode(aErrorCode) + nsresult aErrorCode) + : MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(), + NS_SUCCEEDED(aErrorCode)), + mProxy(aProxy), mErrorCode(aErrorCode) { - NS_ASSERTION(aProxy, "Don't hand me a null proxy!"); + MOZ_ASSERT(aProxy); } - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) + private: + ~ResponseRunnable() + { } + + virtual void + MaybeSetException(JSContext* aCx) MOZ_OVERRIDE { - if (NS_FAILED(mErrorCode)) { + MOZ_ASSERT(NS_FAILED(mErrorCode)); + Throw(aCx, mErrorCode); - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, false); } - else { - aWorkerPrivate->StopSyncLoop(mSyncQueueKey, true); - } - - return true; - } }; public: WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) - : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy), mSyncQueueKey(0) + : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy) { - mWorkerPrivate->AssertIsOnWorkerThread(); - NS_ASSERTION(aProxy, "Don't hand me a null proxy!"); + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aProxy); + aWorkerPrivate->AssertIsOnWorkerThread(); } + NS_DECL_ISUPPORTS_INHERITED + bool Dispatch(JSContext* aCx) { mWorkerPrivate->AssertIsOnWorkerThread(); AutoSyncLoopHolder syncLoop(mWorkerPrivate); - mSyncQueueKey = syncLoop.SyncQueueKey(); + mSyncLoopTarget = syncLoop.EventTarget(); if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { JS_ReportError(aCx, "Failed to dispatch to main thread!"); return false; } - return syncLoop.RunAndForget(aCx); + return syncLoop.Run(); } +protected: + virtual ~WorkerThreadProxySyncRunnable() + { } + virtual nsresult MainThreadRun() = 0; - NS_IMETHOD - Run() - { - AssertIsOnMainThread(); - - uint32_t oldSyncQueueKey = mProxy->mSyncEventResponseSyncQueueKey; - mProxy->mSyncEventResponseSyncQueueKey = mSyncQueueKey; - - nsresult rv = MainThreadRun(); - - nsRefPtr response = - new ResponseRunnable(mWorkerPrivate, mProxy, mSyncQueueKey, rv); - if (!response->Dispatch(nullptr)) { - NS_WARNING("Failed to dispatch response!"); - } - - mProxy->mSyncEventResponseSyncQueueKey = oldSyncQueueKey; - - return NS_OK; - } +private: + NS_DECL_NSIRUNNABLE }; -class SyncTeardownRunnable : public WorkerThreadProxySyncRunnable +class SyncTeardownRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { public: SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) - { - MOZ_ASSERT(aWorkerPrivate); - MOZ_ASSERT(aProxy); - } + { } + +private: + ~SyncTeardownRunnable() + { } virtual nsresult - MainThreadRun() + MainThreadRun() MOZ_OVERRIDE { - AssertIsOnMainThread(); - mProxy->Teardown(); - return NS_OK; } }; -class SetBackgroundRequestRunnable : public WorkerThreadProxySyncRunnable +class SetBackgroundRequestRunnable MOZ_FINAL : + public WorkerThreadProxySyncRunnable { bool mValue; @@ -906,14 +580,19 @@ public: : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) { } - nsresult - MainThreadRun() +private: + ~SetBackgroundRequestRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { return mProxy->mXHR->SetMozBackgroundRequest(mValue); } }; -class SetWithCredentialsRunnable : public WorkerThreadProxySyncRunnable +class SetWithCredentialsRunnable MOZ_FINAL : + public WorkerThreadProxySyncRunnable { bool mValue; @@ -923,14 +602,18 @@ public: : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) { } - nsresult - MainThreadRun() +private: + ~SetWithCredentialsRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { return mProxy->mXHR->SetWithCredentials(mValue); } }; -class SetResponseTypeRunnable : public WorkerThreadProxySyncRunnable +class SetResponseTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { nsString mResponseType; @@ -941,8 +624,18 @@ public: mResponseType(aResponseType) { } - nsresult - MainThreadRun() + void + GetResponseType(nsAString& aResponseType) + { + aResponseType.Assign(mResponseType); + } + +private: + ~SetResponseTypeRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { nsresult rv = mProxy->mXHR->SetResponseType(mResponseType); mResponseType.Truncate(); @@ -951,57 +644,46 @@ public: } return rv; } - - void - GetResponseType(nsAString& aResponseType) { - aResponseType.Assign(mResponseType); - } }; -class SetTimeoutRunnable : public WorkerThreadProxySyncRunnable +class SetTimeoutRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { uint32_t mTimeout; public: SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, uint32_t aTimeout) - : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), - mTimeout(aTimeout) + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mTimeout(aTimeout) { } - nsresult - MainThreadRun() +private: + ~SetTimeoutRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { return mProxy->mXHR->SetTimeout(mTimeout); } }; -class AbortRunnable : public WorkerThreadProxySyncRunnable +class AbortRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { public: AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) { } - nsresult - MainThreadRun() - { - mProxy->mInnerEventStreamId++; +private: + ~AbortRunnable() + { } - WorkerPrivate* oldWorker = mProxy->mWorkerPrivate; - mProxy->mWorkerPrivate = mWorkerPrivate; - - mProxy->mXHR->Abort(); - - mProxy->mWorkerPrivate = oldWorker; - - mProxy->Reset(); - - return NS_OK; - } + virtual nsresult + MainThreadRun() MOZ_OVERRIDE; }; -class GetAllResponseHeadersRunnable : public WorkerThreadProxySyncRunnable +class GetAllResponseHeadersRunnable MOZ_FINAL : + public WorkerThreadProxySyncRunnable { nsCString& mResponseHeaders; @@ -1012,15 +694,19 @@ public: mResponseHeaders(aResponseHeaders) { } - nsresult - MainThreadRun() +private: + ~GetAllResponseHeadersRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { mProxy->mXHR->GetAllResponseHeaders(mResponseHeaders); return NS_OK; } }; -class GetResponseHeaderRunnable : public WorkerThreadProxySyncRunnable +class GetResponseHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { const nsCString mHeader; nsCString& mValue; @@ -1032,14 +718,18 @@ public: mValue(aValue) { } - nsresult - MainThreadRun() +private: + ~GetResponseHeaderRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { return mProxy->mXHR->GetResponseHeader(mHeader, mValue); } }; -class OpenRunnable : public WorkerThreadProxySyncRunnable +class OpenRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { nsCString mMethod; nsString mURL; @@ -1059,9 +749,8 @@ public: bool aBackgroundRequest, bool aWithCredentials, uint32_t aTimeout) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod), - mURL(aURL), - mBackgroundRequest(aBackgroundRequest), mWithCredentials(aWithCredentials), - mTimeout(aTimeout) + mURL(aURL), mBackgroundRequest(aBackgroundRequest), + mWithCredentials(aWithCredentials), mTimeout(aTimeout) { if (aUser.WasPassed()) { mUserStr = aUser.Value(); @@ -1073,8 +762,12 @@ public: } } - nsresult - MainThreadRun() +private: + ~OpenRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { WorkerPrivate* oldWorker = mProxy->mWorkerPrivate; mProxy->mWorkerPrivate = mWorkerPrivate; @@ -1086,148 +779,39 @@ public: } nsresult - MainThreadRunInternal() - { - if (!mProxy->Init()) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - nsresult rv; - - if (mBackgroundRequest) { - rv = mProxy->mXHR->SetMozBackgroundRequest(mBackgroundRequest); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (mWithCredentials) { - rv = mProxy->mXHR->SetWithCredentials(mWithCredentials); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (mTimeout) { - rv = mProxy->mXHR->SetTimeout(mTimeout); - NS_ENSURE_SUCCESS(rv, rv); - } - - NS_ASSERTION(!mProxy->mInOpen, "Reentrancy is bad!"); - mProxy->mInOpen = true; - - ErrorResult rv2; - mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, rv2); - - NS_ASSERTION(mProxy->mInOpen, "Reentrancy is bad!"); - mProxy->mInOpen = false; - - if (rv2.Failed()) { - return rv2.ErrorCode(); - } - - rv = mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text")); - - return rv; - } + MainThreadRunInternal(); }; -class SendRunnable : public WorkerThreadProxySyncRunnable +class SendRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { nsString mStringBody; JSAutoStructuredCloneBuffer mBody; nsTArray > mClonedObjects; - uint32_t mSyncQueueKey; + nsCOMPtr mSyncLoopTarget; bool mHasUploadListeners; public: SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, const nsAString& aStringBody, JSAutoStructuredCloneBuffer& aBody, nsTArray >& aClonedObjects, - uint32_t aSyncQueueKey, bool aHasUploadListeners) + nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), - mStringBody(aStringBody), mSyncQueueKey(aSyncQueueKey), + mStringBody(aStringBody), mSyncLoopTarget(aSyncLoopTarget), mHasUploadListeners(aHasUploadListeners) { mBody.swap(aBody); mClonedObjects.SwapElements(aClonedObjects); } - nsresult - MainThreadRun() - { - nsCOMPtr variant; +private: + ~SendRunnable() + { } - if (mBody.data()) { - AutoSafeJSContext cx; - JSAutoRequest ar(cx); - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - NS_ASSERTION(xpc, "This should never be null!"); - - nsresult rv = NS_OK; - - JSStructuredCloneCallbacks* callbacks = - mWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(true) : - WorkerStructuredCloneCallbacks(true); - - JS::Rooted body(cx); - if (mBody.read(cx, &body, callbacks, &mClonedObjects)) { - if (NS_FAILED(xpc->JSValToVariant(cx, body.address(), - getter_AddRefs(variant)))) { - rv = NS_ERROR_DOM_INVALID_STATE_ERR; - } - } - else { - rv = NS_ERROR_DOM_DATA_CLONE_ERR; - } - - mBody.clear(); - mClonedObjects.Clear(); - - NS_ENSURE_SUCCESS(rv, rv); - } - else { - nsCOMPtr wvariant = - do_CreateInstance(NS_VARIANT_CONTRACTID); - NS_ENSURE_TRUE(wvariant, NS_ERROR_UNEXPECTED); - - if (NS_FAILED(wvariant->SetAsAString(mStringBody))) { - NS_ERROR("This should never fail!"); - } - - variant = wvariant; - } - - NS_ASSERTION(!mProxy->mWorkerPrivate, "Should be null!"); - mProxy->mWorkerPrivate = mWorkerPrivate; - - NS_ASSERTION(mProxy->mSyncQueueKey == UINT32_MAX, "Should be unset!"); - mProxy->mSyncQueueKey = mSyncQueueKey; - - if (mHasUploadListeners) { - NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); - if (!mProxy->AddRemoveEventListeners(true, true)) { - NS_ERROR("This should never fail!"); - } - } - - mProxy->mInnerChannelId++; - - nsresult rv = mProxy->mXHR->Send(variant); - - if (NS_SUCCEEDED(rv)) { - mProxy->mOutstandingSendCount++; - - if (!mHasUploadListeners) { - NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); - if (!mProxy->AddRemoveEventListeners(true, true)) { - NS_ERROR("This should never fail!"); - } - } - } - - return rv; - } + virtual nsresult + MainThreadRun() MOZ_OVERRIDE; }; -class SetRequestHeaderRunnable : public WorkerThreadProxySyncRunnable +class SetRequestHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { nsCString mHeader; nsCString mValue; @@ -1239,14 +823,18 @@ public: mValue(aValue) { } - nsresult - MainThreadRun() +private: + ~SetRequestHeaderRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { return mProxy->mXHR->SetRequestHeader(mHeader, mValue); } }; -class OverrideMimeTypeRunnable : public WorkerThreadProxySyncRunnable +class OverrideMimeTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable { nsString mMimeType; @@ -1256,8 +844,12 @@ public: : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMimeType(aMimeType) { } - nsresult - MainThreadRun() +private: + ~OverrideMimeTypeRunnable() + { } + + virtual nsresult + MainThreadRun() MOZ_OVERRIDE { mProxy->mXHR->OverrideMimeType(mMimeType); return NS_OK; @@ -1266,6 +858,8 @@ public: class AutoUnpinXHR { + XMLHttpRequest* mXMLHttpRequestPrivate; + public: AutoUnpinXHR(XMLHttpRequest* aXMLHttpRequestPrivate) : mXMLHttpRequestPrivate(aXMLHttpRequestPrivate) @@ -1284,13 +878,61 @@ public: { mXMLHttpRequestPrivate = nullptr; } - -private: - XMLHttpRequest* mXMLHttpRequestPrivate; }; } // anonymous namespace +bool +Proxy::Init() +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mWorkerPrivate); + + if (mXHR) { + return true; + } + + nsPIDOMWindow* ownerWindow = mWorkerPrivate->GetWindow(); + if (ownerWindow) { + ownerWindow = ownerWindow->GetOuterWindow(); + if (!ownerWindow) { + NS_ERROR("No outer window?!"); + return false; + } + + nsPIDOMWindow* innerWindow = ownerWindow->GetCurrentInnerWindow(); + if (mWorkerPrivate->GetWindow() != innerWindow) { + NS_WARNING("Window has navigated, cannot create XHR here."); + return false; + } + } + + mXHR = new nsXMLHttpRequest(); + + nsCOMPtr global = do_QueryInterface(ownerWindow); + if (NS_FAILED(mXHR->Init(mWorkerPrivate->GetPrincipal(), + mWorkerPrivate->GetScriptContext(), + global, mWorkerPrivate->GetBaseURI()))) { + mXHR = nullptr; + return false; + } + + mXHR->SetParameters(mMozAnon, mMozSystem); + + if (NS_FAILED(mXHR->GetUpload(getter_AddRefs(mXHRUpload)))) { + mXHR = nullptr; + return false; + } + + if (!AddRemoveEventListeners(false, true)) { + mXHRUpload = nullptr; + mXHR = nullptr; + return false; + } + + return true; +} + void Proxy::Teardown() { @@ -1437,6 +1079,443 @@ Proxy::HandleEvent(nsIDOMEvent* aEvent) return NS_OK; } +NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadProxySyncRunnable, nsRunnable) + +NS_IMPL_ISUPPORTS_INHERITED0(AsyncTeardownRunnable, nsRunnable) + +NS_IMPL_ISUPPORTS_INHERITED1(LoadStartDetectionRunnable, nsRunnable, + nsIDOMEventListener) + +NS_IMETHODIMP +LoadStartDetectionRunnable::Run() +{ + AssertIsOnMainThread(); + + if (NS_FAILED(mXHR->RemoveEventListener(mEventType, this, false))) { + NS_WARNING("Failed to remove event listener!"); + } + + if (!mReceivedLoadStart) { + if (mProxy->mOutstandingSendCount > 1) { + mProxy->mOutstandingSendCount--; + } else if (mProxy->mOutstandingSendCount == 1) { + mProxy->Reset(); + + nsRefPtr runnable = + new ProxyCompleteRunnable(mWorkerPrivate, mProxy, + mXMLHttpRequestPrivate, mChannelId); + if (runnable->Dispatch(nullptr)) { + mProxy->mWorkerPrivate = nullptr; + mProxy->mOutstandingSendCount--; + } + } + } + + mProxy = nullptr; + mXHR = nullptr; + mXMLHttpRequestPrivate = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +LoadStartDetectionRunnable::HandleEvent(nsIDOMEvent* aEvent) +{ + AssertIsOnMainThread(); + +#ifdef DEBUG + { + nsString type; + if (NS_SUCCEEDED(aEvent->GetType(type))) { + MOZ_ASSERT(type == mEventType); + } + else { + NS_WARNING("Failed to get event type!"); + } + } +#endif + + mReceivedLoadStart = true; + return NS_OK; +} + +bool +EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +{ + AssertIsOnMainThread(); + + nsRefPtr& xhr = mProxy->mXHR; + MOZ_ASSERT(xhr); + + if (NS_FAILED(xhr->GetResponseType(mResponseType))) { + MOZ_ASSERT(false, "This should never fail!"); + } + + mResponseTextResult = xhr->GetResponseText(mResponseText); + if (NS_SUCCEEDED(mResponseTextResult)) { + mResponseResult = mResponseTextResult; + if (mResponseText.IsVoid()) { + mResponse = JSVAL_NULL; + } + } + else { + JS::Rooted response(aCx); + mResponseResult = xhr->GetResponse(aCx, response.address()); + if (NS_SUCCEEDED(mResponseResult)) { + if (JSVAL_IS_UNIVERSAL(response)) { + mResponse = response; + } + else { + // Anything subject to GC must be cloned. + JSStructuredCloneCallbacks* callbacks = + aWorkerPrivate->IsChromeWorker() ? + ChromeWorkerStructuredCloneCallbacks(true) : + WorkerStructuredCloneCallbacks(true); + + nsTArray > clonedObjects; + + if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) { + mClonedObjects.SwapElements(clonedObjects); + } + else { + NS_WARNING("Failed to clone response!"); + mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR; + } + } + } + } + + mStatusResult = xhr->GetStatus(&mStatus); + + xhr->GetStatusText(mStatusText); + + mReadyState = xhr->ReadyState(); + + return true; +} + +bool +EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) +{ + if (mEventStreamId != mProxy->mOuterEventStreamId) { + // Threads raced, this event is now obsolete. + return true; + } + + if (!mProxy->mXMLHttpRequestPrivate) { + // Object was finalized, bail. + return true; + } + + if (mType.EqualsASCII(sEventStrings[STRING_loadstart])) { + if (mUploadEvent) { + mProxy->mSeenUploadLoadStart = true; + } + else { + mProxy->mSeenLoadStart = true; + } + } + else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) { + if (mUploadEvent) { + mProxy->mSeenUploadLoadStart = false; + } + else { + mProxy->mSeenLoadStart = false; + } + } + else if (mType.EqualsASCII(sEventStrings[STRING_abort])) { + if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) || + (!mUploadEvent && !mProxy->mSeenLoadStart)) { + // We've already dispatched premature abort events. + return true; + } + } + else if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) { + if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) { + // We've already dispatched premature abort events. + return true; + } + } + + if (mProgressEvent) { + // Cache these for premature abort events. + if (mUploadEvent) { + mProxy->mLastUploadLengthComputable = mLengthComputable; + mProxy->mLastUploadLoaded = mLoaded; + mProxy->mLastUploadTotal = mTotal; + } + else { + mProxy->mLastLengthComputable = mLengthComputable; + mProxy->mLastLoaded = mLoaded; + mProxy->mLastTotal = mTotal; + } + } + + nsAutoPtr state(new XMLHttpRequest::StateData()); + StateDataAutoRooter rooter(aCx, state); + + state->mResponseTextResult = mResponseTextResult; + state->mResponseText = mResponseText; + + if (NS_SUCCEEDED(mResponseTextResult)) { + MOZ_ASSERT(JSVAL_IS_VOID(mResponse) || JSVAL_IS_NULL(mResponse)); + state->mResponseResult = mResponseTextResult; + state->mResponse = mResponse; + } + else { + state->mResponseResult = mResponseResult; + + if (NS_SUCCEEDED(mResponseResult)) { + if (mResponseBuffer.data()) { + MOZ_ASSERT(JSVAL_IS_VOID(mResponse)); + + JSAutoStructuredCloneBuffer responseBuffer; + mResponseBuffer.swap(responseBuffer); + + JSStructuredCloneCallbacks* callbacks = + aWorkerPrivate->IsChromeWorker() ? + ChromeWorkerStructuredCloneCallbacks(false) : + WorkerStructuredCloneCallbacks(false); + + nsTArray > clonedObjects; + clonedObjects.SwapElements(mClonedObjects); + + JS::Rooted response(aCx); + if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) { + return false; + } + + state->mResponse = response; + } + else { + state->mResponse = mResponse; + } + } + } + + state->mStatusResult = mStatusResult; + state->mStatus = mStatus; + + state->mStatusText = mStatusText; + + state->mReadyState = mReadyState; + + XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate; + xhr->UpdateState(*state); + + if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) { + return true; + } + + JS::Rooted type(aCx, + JS_NewUCStringCopyN(aCx, mType.get(), mType.Length())); + if (!type) { + return false; + } + + nsXHREventTarget* target; + if (mUploadEvent) { + target = xhr->GetUploadObjectNoCreate(); + } + else { + target = xhr; + } + + MOZ_ASSERT(target); + + nsCOMPtr event; + if (mProgressEvent) { + NS_NewDOMProgressEvent(getter_AddRefs(event), target, nullptr, nullptr); + nsCOMPtr progress = do_QueryInterface(event); + + if (progress) { + progress->InitProgressEvent(mType, false, false, mLengthComputable, + mLoaded, mTotal); + } + } + else { + NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr); + + if (event) { + event->InitEvent(mType, false, false); + } + } + + if (!event) { + return false; + } + + event->SetTrusted(true); + + target->DispatchDOMEvent(nullptr, event, nullptr, nullptr); + + // After firing the event set mResponse to JSVAL_NULL for chunked response + // types. + if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) { + xhr->NullResponseText(); + } + + return true; +} + +NS_IMETHODIMP +WorkerThreadProxySyncRunnable::Run() +{ + AssertIsOnMainThread(); + + nsCOMPtr tempTarget; + mSyncLoopTarget.swap(tempTarget); + + mProxy->mSyncEventResponseTarget.swap(tempTarget); + + nsresult rv = MainThreadRun(); + + nsRefPtr response = + new ResponseRunnable(mWorkerPrivate, mProxy, rv); + if (!response->Dispatch(nullptr)) { + MOZ_ASSERT(false, "Failed to dispatch response!"); + } + + mProxy->mSyncEventResponseTarget.swap(tempTarget); + + return NS_OK; +} + +nsresult +AbortRunnable::MainThreadRun() +{ + mProxy->mInnerEventStreamId++; + + WorkerPrivate* oldWorker = mProxy->mWorkerPrivate; + mProxy->mWorkerPrivate = mWorkerPrivate; + + mProxy->mXHR->Abort(); + + mProxy->mWorkerPrivate = oldWorker; + + mProxy->Reset(); + + return NS_OK; +} + +nsresult +OpenRunnable::MainThreadRunInternal() +{ + if (!mProxy->Init()) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + nsresult rv; + + if (mBackgroundRequest) { + rv = mProxy->mXHR->SetMozBackgroundRequest(mBackgroundRequest); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (mWithCredentials) { + rv = mProxy->mXHR->SetWithCredentials(mWithCredentials); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (mTimeout) { + rv = mProxy->mXHR->SetTimeout(mTimeout); + NS_ENSURE_SUCCESS(rv, rv); + } + + MOZ_ASSERT(!mProxy->mInOpen); + mProxy->mInOpen = true; + + ErrorResult rv2; + mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, rv2); + + MOZ_ASSERT(mProxy->mInOpen); + mProxy->mInOpen = false; + + if (rv2.Failed()) { + return rv2.ErrorCode(); + } + + return mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text")); +} + + +nsresult +SendRunnable::MainThreadRun() +{ + nsCOMPtr variant; + + if (mBody.data()) { + AutoSafeJSContext cx; + JSAutoRequest ar(cx); + + nsIXPConnect* xpc = nsContentUtils::XPConnect(); + MOZ_ASSERT(xpc); + + nsresult rv = NS_OK; + + JSStructuredCloneCallbacks* callbacks = + mWorkerPrivate->IsChromeWorker() ? + ChromeWorkerStructuredCloneCallbacks(true) : + WorkerStructuredCloneCallbacks(true); + + JS::Rooted body(cx); + if (mBody.read(cx, &body, callbacks, &mClonedObjects)) { + if (NS_FAILED(xpc->JSValToVariant(cx, body.address(), + getter_AddRefs(variant)))) { + rv = NS_ERROR_DOM_INVALID_STATE_ERR; + } + } + else { + rv = NS_ERROR_DOM_DATA_CLONE_ERR; + } + + mBody.clear(); + mClonedObjects.Clear(); + + NS_ENSURE_SUCCESS(rv, rv); + } + else { + nsCOMPtr wvariant = + do_CreateInstance(NS_VARIANT_CONTRACTID); + NS_ENSURE_TRUE(wvariant, NS_ERROR_UNEXPECTED); + + if (NS_FAILED(wvariant->SetAsAString(mStringBody))) { + MOZ_ASSERT(false, "This should never fail!"); + } + + variant = wvariant; + } + + MOZ_ASSERT(!mProxy->mWorkerPrivate); + mProxy->mWorkerPrivate = mWorkerPrivate; + + MOZ_ASSERT(!mProxy->mSyncLoopTarget); + mProxy->mSyncLoopTarget.swap(mSyncLoopTarget); + + if (mHasUploadListeners) { + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); + if (!mProxy->AddRemoveEventListeners(true, true)) { + MOZ_ASSERT(false, "This should never fail!"); + } + } + + mProxy->mInnerChannelId++; + + nsresult rv = mProxy->mXHR->Send(variant); + + if (NS_SUCCEEDED(rv)) { + mProxy->mOutstandingSendCount++; + + if (!mHasUploadListeners) { + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); + if (!mProxy->AddRemoveEventListeners(true, true)) { + MOZ_ASSERT(false, "This should never fail!"); + } + } + } + + return rv; +} + XMLHttpRequest::XMLHttpRequest(WorkerPrivate* aWorkerPrivate) : mWorkerPrivate(aWorkerPrivate), mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0), @@ -1703,11 +1782,11 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody, AutoUnpinXHR autoUnpin(this); Maybe autoSyncLoop; - uint32_t syncQueueKey = UINT32_MAX; + nsCOMPtr syncLoopTarget; bool isSyncXHR = mProxy->mIsSyncXHR; if (isSyncXHR) { autoSyncLoop.construct(mWorkerPrivate); - syncQueueKey = autoSyncLoop.ref().SyncQueueKey(); + syncLoopTarget = autoSyncLoop.ref().EventTarget(); } mProxy->mOuterChannelId++; @@ -1716,7 +1795,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody, nsRefPtr runnable = new SendRunnable(mWorkerPrivate, mProxy, aStringBody, aBody, - aClonedObjects, syncQueueKey, hasUploadListeners); + aClonedObjects, syncLoopTarget, hasUploadListeners); if (!runnable->Dispatch(cx)) { aRv.Throw(NS_ERROR_FAILURE); return; @@ -1738,7 +1817,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody, autoUnpin.Clear(); - if (!autoSyncLoop.ref().RunAndForget(cx)) { + if (!autoSyncLoop.ref().Run()) { aRv.Throw(NS_ERROR_FAILURE); } } diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index c3aff3b8ae3a..8206c337178a 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -22,8 +22,8 @@ class Proxy; class XMLHttpRequestUpload; class WorkerPrivate; -class XMLHttpRequest : public nsXHREventTarget, - public WorkerFeature +class XMLHttpRequest MOZ_FINAL: public nsXHREventTarget, + public WorkerFeature { public: struct StateData @@ -61,10 +61,6 @@ private: bool mMozAnon; bool mMozSystem; -protected: - XMLHttpRequest(WorkerPrivate* aWorkerPrivate); - virtual ~XMLHttpRequest(); - public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; @@ -272,6 +268,9 @@ public: } private: + XMLHttpRequest(WorkerPrivate* aWorkerPrivate); + ~XMLHttpRequest(); + enum ReleaseType { Default, XHRIsGoingAway, WorkerIsGoingAway }; void diff --git a/dom/workers/moz.build b/dom/workers/moz.build index bc43618166e8..584291d8fadd 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -9,6 +9,7 @@ TEST_DIRS += ['test'] # Public stuff. EXPORTS.mozilla.dom += [ 'WorkerPrivate.h', + 'WorkerRunnable.h', 'WorkerScope.h', ] @@ -43,6 +44,7 @@ SOURCES += [ 'SharedWorker.cpp', 'URL.cpp', 'WorkerPrivate.cpp', + 'WorkerRunnable.cpp', 'WorkerScope.cpp', 'XMLHttpRequest.cpp', 'XMLHttpRequestUpload.cpp', @@ -58,6 +60,7 @@ LOCAL_INCLUDES += [ '/content/base/src', '/content/events/src', '/xpcom/build', + '/xpcom/threads', ] include('/ipc/chromium/chromium-config.mozbuild') From 709a4a7087f57b3fcac988124837a12e2aff12df Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Sat, 14 Dec 2013 15:36:17 -0800 Subject: [PATCH 33/34] Bug 923950 - Fix Android single locale repacks. r=glandium There are two parts to this. The first is to add AndroidManifest.xml as a dependency to the "no dependencies" ap_ built during packaging. The aapt call requires it. So "no dependencies" is more accurately "no *resource* dependencies". The second is to avoid including the Android res/ directory in the language repack step. What happens is that the l10n.py script sees the Android res/ files left in the dist/ directory after unpacking and expects to find them in the objdir. They're not there, so the script fails. To avoid this, we delete them after unpacking. See the comments in packager.mk describing this process. --HG-- extra : rebase_source : 35c3c125dddcd575c1a5e8ad58f9aa13ff2db4c3 --- mobile/android/base/Makefile.in | 6 +++--- python/mozbuild/mozbuild/jar.py | 4 ++-- toolkit/mozapps/installer/packager.mk | 19 +++++++++++++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 9ad4672606e3..a4d958c339c4 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -180,7 +180,7 @@ res/values/strings.xml: FORCE $(MAKE) -C locales all_resources = \ - AndroidManifest.xml \ + $(CURDIR)/AndroidManifest.xml \ $(android_res_files) \ $(ANDROID_GENERATED_RESFILES) \ $(NULL) @@ -228,8 +228,8 @@ endef # .aapt.deps: $(all_resources) $(eval $(call aapt_command,.aapt.deps,$(all_resources),gecko.ap_,$(gecko_package_dir)/,./)) -# .aapt.nodeps: FORCE -$(eval $(call aapt_command,.aapt.nodeps,FORCE,gecko-nodeps.ap_,gecko-nodeps/,gecko-nodeps/)) +# .aapt.nodeps: $(CURDIR)/AndroidManifest.xml FORCE +$(eval $(call aapt_command,.aapt.nodeps,$(CURDIR)/AndroidManifest.xml FORCE,gecko-nodeps.ap_,gecko-nodeps/,gecko-nodeps/)) fennec_ids.txt: $(gecko_package_dir)/R.java fennec-ids-generator.py $(PYTHON) $(topsrcdir)/mobile/android/base/fennec-ids-generator.py -i $< -o $@ diff --git a/python/mozbuild/mozbuild/jar.py b/python/mozbuild/mozbuild/jar.py index db9fa4811113..98c17cce76ed 100644 --- a/python/mozbuild/mozbuild/jar.py +++ b/python/mozbuild/mozbuild/jar.py @@ -507,8 +507,8 @@ def main(args=None): jm.relativesrcdir = options.relativesrcdir jm.l10nmerge = options.locale_mergedir if jm.l10nmerge and not os.path.isdir(jm.l10nmerge): - logging.warning("WARNING: --locale-mergedir passed, but '%s' does not exist. Ignore this message if the locale is complete." - ) + logging.warning("WARNING: --locale-mergedir passed, but '%s' does not exist. " + "Ignore this message if the locale is complete." % jm.l10nmerge) elif options.locale_mergedir: p.error('l10n-base required when using locale-mergedir') jm.localedirs = options.l10n_src diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 1dea725bd03e..1851a606cf4d 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -445,14 +445,28 @@ OMNIJAR_NAME := $(notdir $(OMNIJAR_NAME)) # thing if there are resource changes in between build time and # package time. We try to prevent mismatched resources by erroring # out if the compiled resource IDs are not the same as the resource -# IDs being packaged. +# IDs being packaged. If we're doing a single locale repack, however, +# we don't have a complete object directory, so we can't compare +# resource IDs. + +# A note on the res/ directory. We unzip the ap_ during packaging, +# which produces the res/ directory. This directory is then included +# in the final package. When we unpack (during locale repacks), we +# need to remove the res/ directory because these resources confuse +# the l10n packaging script that updates omni.ja: the script tries to +# localize the contents of the res/ directory, which fails. Instead, +# after the l10n packaging script completes, we build the ap_ +# described above (which includes freshly localized Android resources) +# and the res/ directory is taken from the ap_ as part of the regular +# packaging. PKG_SUFFIX = .apk INNER_MAKE_PACKAGE = \ $(if $(ALREADY_SZIPPED),,$(foreach lib,$(SZIP_LIBRARIES),host/bin/szip $(MOZ_SZIP_FLAGS) $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/$(lib) && )) \ make -C $(GECKO_APP_AP_PATH) gecko-nodeps.ap_ && \ cp $(GECKO_APP_AP_PATH)/gecko-nodeps.ap_ $(_ABS_DIST)/gecko.ap_ && \ - ( diff $(GECKO_APP_AP_PATH)/R.txt $(GECKO_APP_AP_PATH)/gecko-nodeps/R.txt >/dev/null || \ + ( (test ! -f $(GECKO_APP_AP_PATH)/R.txt && echo "*** Warning: The R.txt that is being packaged might not agree with the R.txt that was built. This is normal during l10n repacks.") || \ + diff $(GECKO_APP_AP_PATH)/R.txt $(GECKO_APP_AP_PATH)/gecko-nodeps/R.txt >/dev/null || \ (echo "*** Error: The R.txt that was built and the R.txt that is being packaged are not the same. Rebuild mobile/android/base and re-package." && exit 1)) && \ ( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \ mkdir -p lib/$(ABI_DIR) && \ @@ -487,6 +501,7 @@ INNER_UNMAKE_PACKAGE = \ mv lib/$(ABI_DIR)/libmozglue.so . && \ mv lib/$(ABI_DIR)/*plugin-container* $(MOZ_CHILD_PROCESS_NAME) && \ rm -rf lib/$(ABI_DIR) \ + rm -rf res \ $(if $(filter-out ./,$(OMNIJAR_DIR)), \ && mv $(OMNIJAR_DIR)$(OMNIJAR_NAME) $(OMNIJAR_NAME)) ) endif From 51be634cd2925f0e5fe630a4caffa6873e2f6565 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 16 Dec 2013 18:27:43 -0800 Subject: [PATCH 34/34] Backed out changeset ef0eeaec74a8 (bug 949183) on the theory that it somehow broke every single b2g test on a CLOSED TREE --- dom/base/nsDOMClassInfo.cpp | 34 +++++++-------- dom/bindings/BindingUtils.cpp | 12 +++--- dom/bindings/BindingUtils.h | 4 +- dom/bindings/Codegen.py | 8 ++-- dom/bindings/DOMJSProxyHandler.cpp | 2 +- dom/plugins/base/nsNPAPIPlugin.h | 2 +- dom/workers/RuntimeService.cpp | 4 +- js/public/Class.h | 2 +- js/public/Id.h | 43 +++++++------------ js/src/builtin/Object.cpp | 2 +- js/src/gc/Barrier.h | 6 +-- js/src/gdb/mozilla/jsid.py | 2 +- js/src/gdb/tests/test-jsid.cpp | 2 +- js/src/gdb/tests/test-jsid.py | 2 +- js/src/jit/BaselineIC.cpp | 2 +- js/src/jit/IonAnalysis.cpp | 2 +- js/src/jit/IonBuilder.cpp | 4 +- js/src/jit/MCallOptimize.cpp | 10 ++--- js/src/jit/MIR.cpp | 12 +++--- js/src/jsapi.cpp | 4 +- js/src/jsarray.cpp | 2 +- js/src/jscompartment.cpp | 2 +- js/src/jsinfer.cpp | 24 +++++------ js/src/jsinfer.h | 10 ++--- js/src/jsinferinlines.h | 6 +-- js/src/jsobjinlines.h | 6 +-- js/src/jsproxy.cpp | 32 +++++++------- js/src/jsproxy.h | 2 +- js/src/vm/Debugger.cpp | 2 +- js/src/vm/Id.cpp | 6 ++- js/src/vm/Shape.cpp | 2 +- js/src/vm/Shape.h | 2 +- js/src/vm/String.h | 2 +- js/src/vm/StructuredClone.cpp | 2 +- js/xpconnect/src/XPCCallContext.cpp | 2 +- js/xpconnect/src/XPCJSRuntime.cpp | 6 +-- js/xpconnect/src/XPCQuickStubs.cpp | 4 +- js/xpconnect/src/dictionary_helper_gen.py | 2 +- js/xpconnect/src/xpcprivate.h | 4 +- js/xpconnect/wrappers/AccessCheck.cpp | 8 ++-- js/xpconnect/wrappers/ChromeObjectWrapper.cpp | 2 +- js/xpconnect/wrappers/FilteringWrapper.cpp | 8 ++-- js/xpconnect/wrappers/XrayWrapper.cpp | 8 ++-- xpcom/base/CycleCollectedJSRuntime.cpp | 2 +- 44 files changed, 147 insertions(+), 158 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index c83c0b72505c..fdd4043450fa 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -573,15 +573,15 @@ nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nullptr; bool nsDOMClassInfo::sIsInitialized = false; -jsid nsDOMClassInfo::sLocation_id = jsid::voidId(); -jsid nsDOMClassInfo::sConstructor_id = jsid::voidId(); -jsid nsDOMClassInfo::sLength_id = jsid::voidId(); -jsid nsDOMClassInfo::sItem_id = jsid::voidId(); -jsid nsDOMClassInfo::sNamedItem_id = jsid::voidId(); -jsid nsDOMClassInfo::sEnumerate_id = jsid::voidId(); -jsid nsDOMClassInfo::sTop_id = jsid::voidId(); -jsid nsDOMClassInfo::sDocument_id = jsid::voidId(); -jsid nsDOMClassInfo::sWrappedJSObject_id = jsid::voidId(); +jsid nsDOMClassInfo::sLocation_id = JSID_VOID; +jsid nsDOMClassInfo::sConstructor_id = JSID_VOID; +jsid nsDOMClassInfo::sLength_id = JSID_VOID; +jsid nsDOMClassInfo::sItem_id = JSID_VOID; +jsid nsDOMClassInfo::sNamedItem_id = JSID_VOID; +jsid nsDOMClassInfo::sEnumerate_id = JSID_VOID; +jsid nsDOMClassInfo::sTop_id = JSID_VOID; +jsid nsDOMClassInfo::sDocument_id = JSID_VOID; +jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID; static const JSClass *sObjectClass = nullptr; @@ -1945,14 +1945,14 @@ nsDOMClassInfo::ShutDown() } } - sLocation_id = jsid::voidId(); - sConstructor_id = jsid::voidId(); - sLength_id = jsid::voidId(); - sItem_id = jsid::voidId(); - sEnumerate_id = jsid::voidId(); - sTop_id = jsid::voidId(); - sDocument_id = jsid::voidId(); - sWrappedJSObject_id = jsid::voidId(); + sLocation_id = JSID_VOID; + sConstructor_id = JSID_VOID; + sLength_id = JSID_VOID; + sItem_id = JSID_VOID; + sEnumerate_id = JSID_VOID; + sTop_id = JSID_VOID; + sDocument_id = JSID_VOID; + sWrappedJSObject_id = JSID_VOID; NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sSecMan); diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 9626aee1701d..6dce37c1ed1b 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -941,7 +941,7 @@ XrayResolveAttribute(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = attributes->specs - attributeSpecs; - for ( ; attributeIds[i] != jsid::voidId(); ++i) { + for ( ; attributeIds[i] != JSID_VOID; ++i) { if (id == attributeIds[i]) { const JSPropertySpec& attrSpec = attributeSpecs[i]; // Because of centralization, we need to make sure we fault in the @@ -1020,7 +1020,7 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = method->specs - methodsSpecs; - for ( ; methodIds[i] != jsid::voidId(); ++i) { + for ( ; methodIds[i] != JSID_VOID; ++i) { if (id == methodIds[i]) { const JSFunctionSpec& methodSpec = methodsSpecs[i]; JSFunction *fun; @@ -1084,7 +1084,7 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = constant->specs - nativeProperties->constantSpecs; - for ( ; nativeProperties->constantIds[i] != jsid::voidId(); ++i) { + for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { if (id == nativeProperties->constantIds[i]) { desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); desc.object().set(wrapper); @@ -1226,7 +1226,7 @@ XrayEnumerateAttributes(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = attributes->specs - attributeSpecs; - for ( ; attributeIds[i] != jsid::voidId(); ++i) { + for ( ; attributeIds[i] != JSID_VOID; ++i) { if (((flags & JSITER_HIDDEN) || (attributeSpecs[i].flags & JSPROP_ENUMERATE)) && !props.append(attributeIds[i])) { @@ -1264,7 +1264,7 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = method->specs - methodsSpecs; - for ( ; methodIds[i] != jsid::voidId(); ++i) { + for ( ; methodIds[i] != JSID_VOID; ++i) { if (((flags & JSITER_HIDDEN) || (methodsSpecs[i].flags & JSPROP_ENUMERATE)) && !props.append(methodIds[i])) { @@ -1310,7 +1310,7 @@ XrayEnumerateProperties(JSContext* cx, JS::Handle wrapper, // Set i to be the index into our full list of ids/specs that we're // looking at now. size_t i = constant->specs - nativeProperties->constantSpecs; - for ( ; nativeProperties->constantIds[i] != jsid::voidId(); ++i) { + for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { if (!props.append(nativeProperties->constantIds[i])) { return false; } diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 243f76a71e12..de98b3cdf3d4 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1408,9 +1408,9 @@ InitIds(JSContext* cx, const Prefable* prefableSpecs, jsid* ids) } } while (++ids, (++spec)->name); - // We ran out of ids for that pref. Put a jsid::voidId() in on the id + // We ran out of ids for that pref. Put a JSID_VOID in on the id // corresponding to the list terminator for the pref. - *ids = jsid::voidId(); + *ids = JSID_VOID; ++ids; } while ((++prefableSpecs)->specs); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 5b84e67fb2b0..47e964c98055 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1426,7 +1426,7 @@ class PropertyDefiner: ',\n'.join(prefableSpecs) + "\n" + "};\n\n") % (specType, name, specType, name)) if doIdArrays: - arrays += ("static jsid %s_ids[%i] = { jsid::voidId() };\n\n" % + arrays += ("static jsid %s_ids[%i] = { JSID_VOID };\n\n" % (name, len(specs))) return arrays @@ -1832,14 +1832,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): if len(idsToInit) > 1: initIds = CGWrapper(initIds, pre="(", post=")", reindent=True) initIds = CGList( - [CGGeneric("%s_ids[0] == jsid::voidId() &&" % idsToInit[0]), + [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), CGGeneric("NS_IsMainThread() &&"), initIds], "\n") initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True) initIds = CGList( [initIds, - CGGeneric((" %s_ids[0] = jsid::voidId();\n" + CGGeneric((" %s_ids[0] = JSID_VOID;\n" " return;") % idsToInit[0]), CGGeneric("}")], "\n") @@ -11297,7 +11297,7 @@ class GlobalGenRoots(): classMembers = [ClassMember(m.identifier.name + "_id", "jsid", visibility="public", - body="jsid::voidId()") for m in dictMembers] + body="JSID_VOID") for m in dictMembers] structName = dict.identifier.name + "Atoms" structs.append((structName, diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 57b1ea7e54e4..4bb115fbe1e3 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -21,7 +21,7 @@ using namespace JS; namespace mozilla { namespace dom { -jsid s_length_id = jsid::voidId(); +jsid s_length_id = JSID_VOID; bool DefineStaticJSVals(JSContext* cx) diff --git a/dom/plugins/base/nsNPAPIPlugin.h b/dom/plugins/base/nsNPAPIPlugin.h index 70429f74c04c..636e460f0aa1 100644 --- a/dom/plugins/base/nsNPAPIPlugin.h +++ b/dom/plugins/base/nsNPAPIPlugin.h @@ -141,7 +141,7 @@ NPStringIdentifierIsPermanent(NPP npp, NPIdentifier id) return JS_StringHasBeenInterned(cx, NPIdentifierToString(id)); } -#define NPIdentifier_VOID (JSIdToNPIdentifier(jsid::voidId())) +#define NPIdentifier_VOID (JSIdToNPIdentifier(JSID_VOID)) NPObject* NP_CALLBACK _getwindowobject(NPP npp); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 4a8f96b0c2c4..6cd7669b2412 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -173,7 +173,7 @@ enum { }; // These are jsids for the main runtime. Only touched on the main thread. -jsid gStringIDs[ID_COUNT] = { jsid::voidId() }; +jsid gStringIDs[ID_COUNT] = { JSID_VOID }; const char* gStringChars[] = { "Worker", @@ -1080,7 +1080,7 @@ ResolveWorkerClasses(JSContext* aCx, JS::Handle aObj, JS::Handle) JSID_VOIDHANDLE; extern JS_PUBLIC_DATA(const JS::Handle) JSID_EMPTYHANDLE; @@ -181,7 +168,7 @@ IsPoisonedId(jsid iden) template <> struct GCMethods { - static jsid initial() { return jsid::voidId(); } + static jsid initial() { return JSID_VOID; } static ThingRootKind kind() { return THING_ROOT_ID; } static bool poisoned(jsid id) { return IsPoisonedId(id); } static bool needsPostBarrier(jsid id) { return false; } diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 8ba187365d94..c77625685982 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -605,7 +605,7 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp) if (!ValueToId(cx, args[0], &id)) return false; } else { - id = jsid::voidId(); + id = JSID_VOID; } if (!JSObject::unwatch(cx, obj, id)) diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 4d2aa8bcf18d..0205a3e1ed5b 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -995,7 +995,7 @@ class EncapsulatedId : public BarrieredId { public: explicit EncapsulatedId(jsid id) : BarrieredId(id) {} - explicit EncapsulatedId() : BarrieredId(jsid::voidId()) {} + explicit EncapsulatedId() : BarrieredId(JSID_VOID) {} EncapsulatedId &operator=(const EncapsulatedId &v) { if (v.value != value) @@ -1009,7 +1009,7 @@ class EncapsulatedId : public BarrieredId class RelocatableId : public BarrieredId { public: - explicit RelocatableId() : BarrieredId(jsid::voidId()) {} + explicit RelocatableId() : BarrieredId(JSID_VOID) {} explicit inline RelocatableId(jsid id) : BarrieredId(id) {} ~RelocatableId() { pre(); } @@ -1046,7 +1046,7 @@ class RelocatableId : public BarrieredId class HeapId : public BarrieredId { public: - explicit HeapId() : BarrieredId(jsid::voidId()) {} + explicit HeapId() : BarrieredId(JSID_VOID) {} explicit HeapId(jsid id) : BarrieredId(id) diff --git a/js/src/gdb/mozilla/jsid.py b/js/src/gdb/mozilla/jsid.py index 60106c07c63d..aff1eab2c9e5 100644 --- a/js/src/gdb/mozilla/jsid.py +++ b/js/src/gdb/mozilla/jsid.py @@ -46,7 +46,7 @@ class jsid(object): elif tag & jsid.TYPE_INT: body = bits >> 1 elif tag == jsid.TYPE_VOID: - return "jsid::voidId()" + return "JSID_VOID" elif tag == jsid.TYPE_OBJECT: body = ((bits & ~jsid.TYPE_MASK) .cast(self.cache.JSObject_ptr_t)) diff --git a/js/src/gdb/tests/test-jsid.cpp b/js/src/gdb/tests/test-jsid.cpp index ababd5da9536..dcab84ef37da 100644 --- a/js/src/gdb/tests/test-jsid.cpp +++ b/js/src/gdb/tests/test-jsid.cpp @@ -6,7 +6,7 @@ FRAGMENT(jsid, simple) { JS::Rooted interned(cx, JS_InternJSString(cx, string)); JS::Rooted string_id(cx, INTERNED_STRING_TO_JSID(cx, interned)); jsid int_id = INT_TO_JSID(1729); - jsid void_id = jsid::voidId(); + jsid void_id = JSID_VOID; JS::Rooted object_id(cx, OBJECT_TO_JSID(JS::CurrentGlobalOrNull(cx))); breakpoint(); diff --git a/js/src/gdb/tests/test-jsid.py b/js/src/gdb/tests/test-jsid.py index 97cd8dc17d33..880abfc3cdb0 100644 --- a/js/src/gdb/tests/test-jsid.py +++ b/js/src/gdb/tests/test-jsid.py @@ -6,7 +6,7 @@ run_fragment('jsid.simple') assert_pretty('string_id', '$jsid("moon")') assert_pretty('int_id', '$jsid(1729)') -assert_pretty('void_id', 'jsid::voidId()') +assert_pretty('void_id', 'JSID_VOID') assert_pretty('object_id', '$jsid((JSObject *) [object global] delegate)') run_fragment('jsid.handles') diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 8731e71d039a..0caa47353c9b 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1469,7 +1469,7 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H case ICStub::SetElem_Dense: case ICStub::SetElem_DenseAdd: { JS_ASSERT(obj->isNative()); - id = jsid::voidId(); + id = JSID_VOID; types::AddTypePropertyId(cx, obj, id, value); break; } diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 98364231f589..d70f534998bf 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2013,7 +2013,7 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type, // Don't use GetAtomId here, we need to watch for SETPROP on // integer properties and bail out. We can't mark the aggregate - // jsid::voidId() type property as being in a definite slot. + // JSID_VOID type property as being in a definite slot. if (setprop->name() == cx->names().prototype || setprop->name() == cx->names().proto || setprop->name() == cx->names().constructor) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 7f9a2719a643..27d57b3609b2 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5522,7 +5522,7 @@ IonBuilder::jsop_initelem_array() if (!initializer->hasFlags(constraints(), types::OBJECT_FLAG_NON_PACKED)) needStub = true; } else if (!initializer->unknownProperties()) { - types::HeapTypeSetKey elemTypes = initializer->property(jsid::voidId()); + types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID); if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) { elemTypes.freeze(constraints()); needStub = true; @@ -7627,7 +7627,7 @@ IonBuilder::jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion convers } // Determine whether a write barrier is required. - if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), jsid::voidId())) + if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID)) store->setNeedsBarrier(); if (elementType != MIRType_None && packed) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 716abb92bd7e..2c649f5c758a 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -213,7 +213,7 @@ IonBuilder::inlineArray(CallInfo &callInfo) types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject); if (!type->unknownProperties()) { - types::HeapTypeSetKey elemTypes = type->property(jsid::voidId()); + types::HeapTypeSetKey elemTypes = type->property(JSID_VOID); for (uint32_t i = 0; i < initLength; i++) { MDefinition *value = callInfo.getArg(i); @@ -468,7 +468,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) // Constraints modeling this concat have not been generated by inference, // so check that type information already reflects possible side effects of // this call. - types::HeapTypeSetKey thisElemTypes = thisType->property(jsid::voidId()); + types::HeapTypeSetKey thisElemTypes = thisType->property(JSID_VOID); types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet(); if (!resTypes->hasType(types::Type::ObjectType(thisType))) @@ -482,7 +482,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (argType->unknownProperties()) return InliningStatus_NotInlined; - types::HeapTypeSetKey elemTypes = argType->property(jsid::voidId()); + types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID); if (!elemTypes.knownSubset(constraints(), thisElemTypes)) return InliningStatus_NotInlined; } @@ -958,7 +958,7 @@ IonBuilder::inlineStringSplit(CallInfo &callInfo) if (retType->unknownProperties()) return InliningStatus_NotInlined; - types::HeapTypeSetKey key = retType->property(jsid::voidId()); + types::HeapTypeSetKey key = retType->property(JSID_VOID); if (!key.maybeTypes()) return InliningStatus_NotInlined; @@ -1178,7 +1178,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base) // - arr is a dense array // - idx < initialized length // Furthermore, note that inlineUnsafePutElements ensures the type of the - // value is reflected in the jsid::voidId() property of the array. + // value is reflected in the JSID_VOID property of the array. MDefinition *obj = callInfo.getArg(base + 0); MDefinition *id = callInfo.getArg(base + 1); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 8b3a95cba007..92cff151ffb4 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2870,7 +2870,7 @@ jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinit if (object->unknownProperties()) return MIRType_None; - types::HeapTypeSetKey elementTypes = object->property(jsid::voidId()); + types::HeapTypeSetKey elementTypes = object->property(JSID_VOID); MIRType type = MIRTypeFromValueType(elementTypes.knownTypeTag(constraints)); if (type == MIRType_None) @@ -2899,7 +2899,7 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints, if (object->unknownProperties() || observed->empty()) return true; - jsid id = name ? NameToId(name) : jsid::voidId(); + jsid id = name ? NameToId(name) : JSID_VOID; types::HeapTypeSetKey property = object->property(id); if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) return true; @@ -3073,7 +3073,7 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name, if (object->unknownProperties()) return observed->addType(types::Type::AnyObjectType(), alloc); - jsid id = name ? NameToId(name) : jsid::voidId(); + jsid id = name ? NameToId(name) : JSID_VOID; types::HeapTypeSetKey property = object->property(id); types::HeapTypeSet *types = property.maybeTypes(); if (!types) @@ -3114,7 +3114,7 @@ TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *c if (object->unknownProperties()) return false; - jsid id = name ? NameToId(name) : jsid::voidId(); + jsid id = name ? NameToId(name) : JSID_VOID; types::HeapTypeSetKey property = object->property(id); if (!property.maybeTypes()) return false; @@ -3224,7 +3224,7 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstrai if (IsTypedArrayClass(object->clasp())) continue; - jsid id = name ? NameToId(name) : jsid::voidId(); + jsid id = name ? NameToId(name) : JSID_VOID; types::HeapTypeSetKey property = object->property(id); if (!TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) { // Either pobj or pvalue needs to be modified to filter out the @@ -3256,7 +3256,7 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstrai if (IsTypedArrayClass(object->clasp())) continue; - jsid id = name ? NameToId(name) : jsid::voidId(); + jsid id = name ? NameToId(name) : JSID_VOID; types::HeapTypeSetKey property = object->property(id); if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) continue; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 061859c3e2e4..722ec4ceb930 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3753,7 +3753,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) if (!shape->previous()) { JS_ASSERT(shape->isEmptyShape()); - *idp = jsid::voidId(); + *idp = JSID_VOID; } else { iterobj->setPrivateGCThing(const_cast(shape->previous().get())); *idp = shape->propid(); @@ -3764,7 +3764,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) JS_ASSERT(i <= ida->length); STATIC_ASSUME(i <= ida->length); if (i == 0) { - *idp = jsid::voidId(); + *idp = JSID_VOID; } else { *idp = ida->vector[--i]; iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i)); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index af8905f17cc5..85b3f2b0b194 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1200,7 +1200,7 @@ InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned co if (cx->typeInferenceEnabled() && !type->unknownProperties()) { AutoEnterAnalysis enter(cx); - HeapTypeSet *types = type->getProperty(cx, jsid::voidId()); + HeapTypeSet *types = type->getProperty(cx, JSID_VOID); if (!types) return false; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 257480d63526..326593b23ef6 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -373,7 +373,7 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin bool JSCompartment::wrapId(JSContext *cx, jsid *idp) { - MOZ_ASSERT(*idp != jsid::voidId(), "jsid::voidId() is an out-of-band sentinel value"); + MOZ_ASSERT(*idp != JSID_VOID, "JSID_VOID is an out-of-band sentinel value"); if (JSID_IS_INT(*idp)) return true; RootedValue value(cx, IdToValue(*idp)); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 04197729e663..5bfec3ee4129 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1253,7 +1253,7 @@ TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags fla return true; } - HeapTypeSetKey objectProperty = property(jsid::emptyId()); + HeapTypeSetKey objectProperty = property(JSID_EMPTY); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1297,7 +1297,7 @@ TypeObject::initialHeap(CompilerConstraintList *constraints) if (!canPreTenure()) return gc::DefaultHeap; - HeapTypeSetKey objectProperty = TypeObjectKey::get(this)->property(jsid::emptyId()); + HeapTypeSetKey objectProperty = TypeObjectKey::get(this)->property(JSID_EMPTY); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1404,7 +1404,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer void TypeObjectKey::watchStateChangeForInlinedCall(CompilerConstraintList *constraints) { - HeapTypeSetKey objectProperty = property(jsid::emptyId()); + HeapTypeSetKey objectProperty = property(JSID_EMPTY); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1415,7 +1415,7 @@ void TypeObjectKey::watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints) { JSObject *templateObject = asTypeObject()->newScript()->templateObject; - HeapTypeSetKey objectProperty = property(jsid::emptyId()); + HeapTypeSetKey objectProperty = property(JSID_EMPTY); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1427,7 +1427,7 @@ void TypeObjectKey::watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints) { void *viewData = asSingleObject()->as().viewData(); - HeapTypeSetKey objectProperty = property(jsid::emptyId()); + HeapTypeSetKey objectProperty = property(JSID_EMPTY); LifoAlloc *alloc = constraints->alloc(); typedef CompilerConstraintInstance T; @@ -1442,7 +1442,7 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno return; /* All constraints listening to state changes are on the empty id. */ - HeapTypeSet *types = object->maybeGetProperty(jsid::emptyId()); + HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY); /* Mark as unknown after getting the types, to avoid assertion. */ if (markingUnknown) { @@ -1554,7 +1554,7 @@ TemporaryTypeSet::convertDoubleElements(CompilerConstraintList *constraints) continue; } - HeapTypeSetKey property = type->property(jsid::voidId()); + HeapTypeSetKey property = type->property(JSID_VOID); property.freeze(constraints); // We can't convert to double elements for objects which do not have @@ -2033,7 +2033,7 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj) return true; if (type->unknownProperties()) return true; - HeapTypeSetKey index = type->property(jsid::voidId()); + HeapTypeSetKey index = type->property(JSID_VOID); if (index.configured(constraints) || index.isOwnProperty(constraints)) return true; if (!obj->hasTenuredProto()) @@ -2364,7 +2364,7 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx, obj->setType(objType); if (!objType->unknownProperties()) - objType->addPropertyType(cx, jsid::voidId(), elementType); + objType->addPropertyType(cx, JSID_VOID, elementType); key.proto = objProto; if (!p.add(*arrayTypeTable, key, objType)) { @@ -2714,7 +2714,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap /* * Don't add initial undefined types for properties of global objects - * that are not collated into the jsid::voidId() property (see propertySet + * that are not collated into the JSID_VOID property (see propertySet * comment). */ if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) { @@ -2870,7 +2870,7 @@ TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value) void TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type) { - jsid id = jsid::voidId(); + jsid id = JSID_VOID; if (name) { JSAtom *atom = Atomize(cx, name, strlen(name)); if (!atom) { @@ -2917,7 +2917,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg) return; AutoEnterAnalysis enter(cxArg); - HeapTypeSet *types = maybeGetProperty(jsid::emptyId()); + HeapTypeSet *types = maybeGetProperty(JSID_EMPTY); if (types) { if (JSContext *cx = cxArg->maybeJSContext()) { TypeConstraint *constraint = types->constraintList; diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 69cdaeb663c7..ff7c27970b00 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -330,7 +330,7 @@ public: virtual void newPropertyState(JSContext *cx, TypeSet *source) {} /* - * For constraints attached to the jsid::emptyId() type set on an object, + * For constraints attached to the JSID_EMPTY type set on an object, * indicate a change in one of the object's dynamic property flags or other * state. */ @@ -731,7 +731,7 @@ inline bool isInlinableCall(jsbytecode *pc); /* Type information about a property. */ struct Property { - /* Identifier for this property, jsid::voidId() for the aggregate integer index property. */ + /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ HeapId id; /* Possible types for this property, including types inherited from prototypes. */ @@ -1005,8 +1005,8 @@ struct TypeObject : gc::BarrieredCell private: /* - * Properties of this object. This may contain jsid::voidId(), representing the - * types of all integer indexes of the object, and/or jsid::emptyId(), holding + * Properties of this object. This may contain JSID_VOID, representing the + * types of all integer indexes of the object, and/or JSID_EMPTY, holding * constraints listening to changes to the object's state. * * The type sets in the properties of a type object describe the possible @@ -1381,7 +1381,7 @@ class HeapTypeSetKey public: HeapTypeSetKey() - : object_(nullptr), id_(jsid::emptyId()), maybeTypes_(nullptr) + : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr) {} TypeObjectKey *object() const { return object_; } diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index dc68d2c847ff..ab4186e83ef9 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -170,7 +170,7 @@ IdToTypeId(jsid id) * negative integers. */ if (JSID_IS_INT(id)) - return jsid::voidId(); + return JSID_VOID; /* * Check for numeric strings, as in js_StringIsIndex, but allow negative @@ -184,12 +184,12 @@ IdToTypeId(jsid id) if (!JS7_ISDEC(cp[i])) return id; } - return jsid::voidId(); + return JSID_VOID; } return id; } - return jsid::voidId(); + return JSID_VOID; } const char * TypeIdStringImpl(jsid id); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 365d7016ea2c..674d4ea03c17 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -153,7 +153,7 @@ JSObject::setShouldConvertDoubleElements() inline bool JSObject::setDenseElementIfHasType(uint32_t index, const js::Value &val) { - if (!js::types::HasTypePropertyId(this, jsid::voidId(), val)) + if (!js::types::HasTypePropertyId(this, JSID_VOID, val)) return false; setDenseElementMaybeConvertDouble(index, val); return true; @@ -167,7 +167,7 @@ JSObject::setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, // of the previous element. js::types::Type thisType = js::types::GetValueType(val); if (index == 0 || js::types::GetValueType(elements[index - 1]) != thisType) - js::types::AddTypePropertyId(cx, this, jsid::voidId(), thisType); + js::types::AddTypePropertyId(cx, this, JSID_VOID, thisType); setDenseElementMaybeConvertDouble(index, val); } @@ -176,7 +176,7 @@ JSObject::initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, const js::Value &val) { JS_ASSERT(!shouldConvertDoubleElements()); - js::types::AddTypePropertyId(cx, this, jsid::voidId(), val); + js::types::AddTypePropertyId(cx, this, JSID_VOID, val); initDenseElement(index, val); } diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 1b096bae0151..1b1582516c2b 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -226,7 +226,7 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver, bool BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); JS_ASSERT(props.length() == 0); if (!getOwnPropertyNames(cx, proxy, props)) @@ -255,7 +255,7 @@ BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) bool BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); AutoIdVector props(cx); if ((flags & JSITER_OWNONLY) @@ -318,7 +318,7 @@ BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl im bool BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedValue val(cx, ObjectValue(*proxy.get())); js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, JSDVG_SEARCH_STACK, val, NullPtr()); @@ -376,7 +376,7 @@ bool BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, HandleObject result) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedId id(cx); RootedValue value(cx); @@ -451,7 +451,7 @@ bool DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props); } @@ -468,7 +468,7 @@ bool DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, 0, &props); @@ -477,7 +477,7 @@ DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy, bool DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedValue target(cx, proxy->as().private_()); return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval()); } @@ -485,7 +485,7 @@ DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args bool DirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedValue target(cx, proxy->as().private_()); return InvokeConstructor(cx, target, args.length(), args.array(), args.rval().address()); } @@ -507,7 +507,7 @@ bool DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); bool b; RootedObject target(cx, proxy->as().target()); if (!JS_HasInstance(cx, target, v, &b)) @@ -541,7 +541,7 @@ DirectProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue, const char * DirectProxyHandler::className(JSContext *cx, HandleObject proxy) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject target(cx, proxy->as().target()); return JSObject::className(cx, target); } @@ -550,7 +550,7 @@ JSString * DirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject target(cx, proxy->as().target()); return fun_toStringHelper(cx, target, indent); } @@ -620,7 +620,7 @@ DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver bool DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject target(cx, proxy->as().target()); return GetPropertyNames(cx, target, JSITER_OWNONLY, &props); } @@ -629,7 +629,7 @@ bool DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype. RootedObject target(cx, proxy->as().target()); return GetIterator(cx, target, flags, vp); @@ -1046,7 +1046,7 @@ ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigne bool ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject ccHolder(cx, &proxy->as().extra(0).toObject()); JS_ASSERT(ccHolder->getClass() == &CallConstructHolder); RootedValue call(cx, ccHolder->getReservedSlot(0)); @@ -1057,7 +1057,7 @@ ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const Call bool ScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); RootedObject ccHolder(cx, &proxy->as().extra(0).toObject()); JS_ASSERT(ccHolder->getClass() == &CallConstructHolder); RootedValue construct(cx, ccHolder->getReservedSlot(1)); @@ -1076,7 +1076,7 @@ ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, N JSString * ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) { - assertEnteredPolicy(cx, proxy, jsid::voidId()); + assertEnteredPolicy(cx, proxy, JSID_VOID); if (!proxy->isCallable()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index d9ebaceb1d36..e463388fd8d7 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -130,7 +130,7 @@ class JS_FRIEND_API(BaseProxyHandler) * * enter() allows the policy to specify whether the caller may perform |act| * on the proxy's |id| property. In the case when |act| is CALL, |id| is - * generally jsid::voidId(). + * generally JSID_VOID. * * The |act| parameter to enter() specifies the action being performed. * If |bp| is false, the trap suggests that the caller throw (though it diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 4abf8b3f199c..ed23898292ba 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4996,7 +4996,7 @@ DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp) ac.construct(cx, obj); RootedId id(cx); for (size_t i = 0; i < n; i++) { - if (!rewrappedIds.append(jsid::voidId()) || !rewrappedDescs.append()) + if (!rewrappedIds.append(JSID_VOID) || !rewrappedDescs.append()) return false; id = ids[i]; if (!unwrappedDescs[i].wrapInto(cx, obj, id, &rewrappedIds[i], &rewrappedDescs[i])) diff --git a/js/src/vm/Id.cpp b/js/src/vm/Id.cpp index 56255cc2bb3e..96360d098030 100644 --- a/js/src/vm/Id.cpp +++ b/js/src/vm/Id.cpp @@ -7,9 +7,11 @@ #include "js/Id.h" #include "js/RootingAPI.h" -static MOZ_CONSTEXPR_VAR jsid voidIdValue = jsid::voidId(); -static MOZ_CONSTEXPR_VAR jsid emptyIdValue = jsid::emptyId(); +const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) }; +const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) }; +static const jsid voidIdValue = JSID_VOID; +static const jsid emptyIdValue = JSID_EMPTY; const JS::HandleId JSID_VOIDHANDLE = JS::HandleId::fromMarkedLocation(&voidIdValue); const JS::HandleId JSID_EMPTYHANDLE = JS::HandleId::fromMarkedLocation(&emptyIdValue); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 9453be68019c..f95670834921 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -688,7 +688,7 @@ js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent, js::AutoIdVector ids(cx); { for (unsigned i = 0; i <= shape->slot(); i++) { - if (!ids.append(jsid::voidId())) + if (!ids.append(JSID_VOID)) return nullptr; } Shape *nshape = shape; diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 56e3b21dc272..1599a18d7314 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1594,7 +1594,7 @@ Shape::Shape(const StackShape &other, uint32_t nfixed) inline Shape::Shape(UnownedBaseShape *base, uint32_t nfixed) : base_(base), - propid_(jsid::emptyId()), + propid_(JSID_EMPTY), slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)), attrs(JSPROP_SHARED), flags(0), diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 651c7635af90..ea4b7ca43638 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -957,7 +957,7 @@ class StaticStrings * - uint32_t indexes, * - PropertyName strings which don't encode uint32_t indexes, and * - jsspecial special properties (non-ES5 properties like object-valued - * jsids, EmptyId(), VoidId(), and maybe in the future Harmony-proposed + * jsids, JSID_EMPTY, JSID_VOID, and maybe in the future Harmony-proposed * private names). */ class PropertyName : public JSAtom diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 4d8cef1c8fc5..171cf9238b19 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1456,7 +1456,7 @@ JSStructuredCloneReader::readId(jsid *idp) return true; } if (tag == SCTAG_NULL) { - *idp = jsid::voidId(); + *idp = JSID_VOID; return true; } JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index 8a3f35b2c820..6e9e837708d4 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -20,7 +20,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, JSContext* cx /* = GetDefaultJSContext() */, HandleObject obj /* = nullptr */, HandleObject funobj /* = nullptr */, - HandleId name /* = jsid::voidId() */, + HandleId name /* = JSID_VOID */, unsigned argc /* = NO_ARGS */, jsval *argv /* = nullptr */, jsval *rval /* = nullptr */) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 14cb4d84cda4..8a8d8391a7f5 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2908,7 +2908,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) mJSContextStack(new XPCJSContextStack()), mCallContext(nullptr), mAutoRoots(nullptr), - mResolveName(jsid::voidId()), + mResolveName(JSID_VOID), mResolvingWrapper(nullptr), mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)), mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)), @@ -2933,7 +2933,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) DOM_InitInterfaces(); // these jsids filled in later when we have a JSContext to work with. - mStrIDs[0] = jsid::voidId(); + mStrIDs[0] = JSID_VOID; MOZ_ASSERT(Runtime()); JSRuntime* runtime = Runtime(); @@ -3134,7 +3134,7 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx) for (unsigned i = 0; i < IDX_TOTAL_COUNT; i++) { str = JS_InternString(cx, mStrings[i]); if (!str) { - mStrIDs[0] = jsid::voidId(); + mStrIDs[0] = JSID_VOID; return false; } mStrIDs[i] = INTERNED_STRING_TO_JSID(cx, str); diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 8f785b2115e6..67aa18a22b5f 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -209,7 +209,7 @@ GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp MOZ_ASSERT(JS_ObjectIsFunction(cx, funobj), "JSNative callee should be Function object"); RootedString str(cx, JS_GetFunctionId(JS_GetObjectFunction(funobj))); - RootedId methodId(cx, str ? INTERNED_STRING_TO_JSID(cx, str) : jsid::voidId()); + RootedId methodId(cx, str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID); GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep); *memberIdp = methodId; } @@ -353,7 +353,7 @@ void xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, unsigned paramnum, const char *ifaceName, const char *memberName) { - ThrowBadArg(cx, rv, ifaceName, jsid::voidId(), memberName, paramnum); + ThrowBadArg(cx, rv, ifaceName, JSID_VOID, memberName, paramnum); } void diff --git a/js/xpconnect/src/dictionary_helper_gen.py b/js/xpconnect/src/dictionary_helper_gen.py index 8d0aa180ec66..40fea45456f3 100644 --- a/js/xpconnect/src/dictionary_helper_gen.py +++ b/js/xpconnect/src/dictionary_helper_gen.py @@ -196,7 +196,7 @@ def print_cpp_file(fd, conf): fd.write("\nusing namespace mozilla::idl;\n\n") for a in attrnames: - fd.write("static jsid %s = jsid::voidId();\n"% get_jsid(a)) + fd.write("static jsid %s = JSID_VOID;\n"% get_jsid(a)) fd.write("\n" "static bool\n" diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 4f7fd0272e1b..fc8264b2fd33 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3448,7 +3448,7 @@ public: CreateObjectInOptions(JSContext *cx = xpc_GetSafeJSContext(), JSObject* options = nullptr) : OptionsBase(cx, options) - , defineAs(cx, jsid::voidId()) + , defineAs(cx, JSID_VOID) { } virtual bool Parse() { return ParseId("defineAs", &defineAs); }; @@ -3461,7 +3461,7 @@ public: ExportOptions(JSContext *cx = xpc_GetSafeJSContext(), JSObject* options = nullptr) : OptionsBase(cx, options) - , defineAs(cx, jsid::voidId()) + , defineAs(cx, JSID_VOID) { } virtual bool Parse() { return ParseId("defineAs", &defineAs); }; diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index b61d6bd5efaa..f84c9bb13fdc 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -217,12 +217,12 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, j RootedObject wrapper(cx, wrapperArg); RootedObject obj(cx, Wrapper::wrappedObject(wrapper)); - // Enumerate-like operations pass jsid::voidId() to |enter|, since there isn't + // Enumerate-like operations pass JSID_VOID to |enter|, since there isn't // another sane value to pass. For XOWs, we generally want to deny such // operations but fail silently (see CrossOriginAccessiblePropertiesOnly:: // deny). We could just fall through here and rely on the fact that none - // of the whitelisted properties below will match jsid::voidId(), but EIBTI. - if (id == jsid::voidId()) + // of the whitelisted properties below will match JSID_VOID, but EIBTI. + if (id == JSID_VOID) return false; const char *name; @@ -315,7 +315,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wr return false; } - if (id == jsid::voidId()) + if (id == JSID_VOID) return true; RootedValue exposedProps(cx); diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp index 4c8bdcf58158..e4b52e152fa2 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp @@ -178,7 +178,7 @@ ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper, // COWs fail silently for GETs, and that also happens to be the only case // where we might want to redirect the lookup to the home prototype chain. *bp = (act == Wrapper::GET); - if (!*bp || id == jsid::voidId()) + if (!*bp || id == JSID_VOID) return false; // Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index f27ad192f561..e7755b5f1c8f 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -87,7 +87,7 @@ bool FilteringWrapper::getOwnPropertyNames(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return Base::getOwnPropertyNames(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -97,7 +97,7 @@ bool FilteringWrapper::enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return Base::enumerate(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -107,7 +107,7 @@ bool FilteringWrapper::keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return Base::keys(cx, wrapper, props) && Filter(cx, wrapper, props); } @@ -117,7 +117,7 @@ bool FilteringWrapper::iterate(JSContext *cx, HandleObject wrapper, unsigned flags, MutableHandleValue vp) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); // We refuse to trigger the iterator hook across chrome wrappers because // we don't know how to censor custom iterator objects. Instead we trigger // the default proxy iterate trap, which will ask enumerate() for the list diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 9bbdd6b96fa5..2610670ab612 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1648,7 +1648,7 @@ bool XrayWrapper::getOwnPropertyNames(JSContext *cx, HandleObject wrapper, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props); } @@ -1675,7 +1675,7 @@ bool XrayWrapper::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags, AutoIdVector &props) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); if (!AccessCheck::wrapperSubsumes(wrapper)) { JS_ReportError(cx, "Not allowed to enumerate cross origin objects"); return false; @@ -1768,7 +1768,7 @@ template bool XrayWrapper::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return Traits::call(cx, wrapper, args, Base::singleton); } @@ -1776,7 +1776,7 @@ template bool XrayWrapper::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) { - assertEnteredPolicy(cx, wrapper, jsid::voidId()); + assertEnteredPolicy(cx, wrapper, JSID_VOID); return Traits::construct(cx, wrapper, args, Base::singleton); } diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index db2de8d60bec..90d0dfe2543b 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -785,7 +785,7 @@ struct ClearJSHolder : TraceCallbacks virtual void Trace(JS::Heap* aPtr, const char*, void*) const MOZ_OVERRIDE { - *aPtr = jsid::voidId(); + *aPtr = JSID_VOID; } virtual void Trace(JS::Heap* aPtr, const char*, void*) const MOZ_OVERRIDE