From 9daa5cbca0a51409eb01f18b4b6dbdb57ea76f15 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 9 Oct 2017 09:56:48 +0200 Subject: [PATCH 01/55] Bug 1405999 part 1 - Optimize CreatePromiseObjectInternal. r=till --- js/src/builtin/Promise.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index e6ae780eb545..1ded013f2a4f 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -1465,12 +1465,11 @@ ClearResolutionFunctionSlots(JSFunction* resolutionFun) } // ES2016, 25.4.3.1. steps 3-7. -static MOZ_MUST_USE PromiseObject* +static MOZ_MUST_USE MOZ_ALWAYS_INLINE PromiseObject* CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */, bool protoIsWrapped /* = false */, bool informDebugger /* = true */) { // Step 3. - Rooted promise(cx); // Enter the unwrapped proto's compartment, if that's different from // the current one. // All state stored in a Promise's fixed slots must be created in the @@ -1480,12 +1479,12 @@ CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */, if (protoIsWrapped) ac.emplace(cx, proto); - promise = NewObjectWithClassProto(cx, proto); + PromiseObject* promise = NewObjectWithClassProto(cx, proto); if (!promise) return nullptr; // Step 4. - promise->setFixedSlot(PromiseSlot_Flags, Int32Value(0)); + promise->initFixedSlot(PromiseSlot_Flags, Int32Value(0)); // Steps 5-6. // Omitted, we allocate our single list of reaction records lazily. @@ -1493,20 +1492,24 @@ CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */, // Step 7. // Implicit, the handled flag is unset by default. + if (MOZ_LIKELY(!ShouldCaptureDebugInfo(cx))) + return promise; + // Store an allocation stack so we can later figure out what the // control flow was for some unexpected results. Frightfully expensive, // but oh well. - if (ShouldCaptureDebugInfo(cx)) { - PromiseDebugInfo* debugInfo = PromiseDebugInfo::create(cx, promise); - if (!debugInfo) - return nullptr; - } + + Rooted promiseRoot(cx, promise); + + PromiseDebugInfo* debugInfo = PromiseDebugInfo::create(cx, promiseRoot); + if (!debugInfo) + return nullptr; // Let the Debugger know about this Promise. if (informDebugger) - Debugger::onNewPromise(cx, promise); + Debugger::onNewPromise(cx, promiseRoot); - return promise; + return promiseRoot; } // ES2016, 25.4.3.1. @@ -1588,7 +1591,7 @@ PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto)) return false; } - Rooted promise(cx, PromiseObject::create(cx, executor, proto, needsWrapping)); + PromiseObject* promise = PromiseObject::create(cx, executor, proto, needsWrapping); if (!promise) return false; From 0d4bbe070732d99f22720187840aeedf3cd01e36 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 9 Oct 2017 09:57:28 +0200 Subject: [PATCH 02/55] Bug 1405999 part 2 - Optimize CreateResolvingFunctions. r=till --- js/src/builtin/Promise.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 1ded013f2a4f..b1dbf047fb22 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -472,30 +472,30 @@ static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp); static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp); // ES2016, 25.4.1.3. -static MOZ_MUST_USE bool +static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(JSContext* cx, HandleObject promise, MutableHandleObject resolveFn, MutableHandleObject rejectFn) { - RootedAtom funName(cx, cx->names().empty); - RootedFunction resolve(cx, NewNativeFunction(cx, ResolvePromiseFunction, 1, funName, - gc::AllocKind::FUNCTION_EXTENDED, GenericObject)); - if (!resolve) + HandlePropertyName funName = cx->names().empty; + resolveFn.set(NewNativeFunction(cx, ResolvePromiseFunction, 1, funName, + gc::AllocKind::FUNCTION_EXTENDED, GenericObject)); + if (!resolveFn) return false; - RootedFunction reject(cx, NewNativeFunction(cx, RejectPromiseFunction, 1, funName, - gc::AllocKind::FUNCTION_EXTENDED, GenericObject)); - if (!reject) + rejectFn.set(NewNativeFunction(cx, RejectPromiseFunction, 1, funName, + gc::AllocKind::FUNCTION_EXTENDED, GenericObject)); + if (!rejectFn) return false; - resolve->setExtendedSlot(ResolveFunctionSlot_Promise, ObjectValue(*promise)); - resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*reject)); + JSFunction* resolveFun = &resolveFn->as(); + JSFunction* rejectFun = &rejectFn->as(); - reject->setExtendedSlot(RejectFunctionSlot_Promise, ObjectValue(*promise)); - reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, ObjectValue(*resolve)); + resolveFun->initExtendedSlot(ResolveFunctionSlot_Promise, ObjectValue(*promise)); + resolveFun->initExtendedSlot(ResolveFunctionSlot_RejectFunction, ObjectValue(*rejectFun)); - resolveFn.set(resolve); - rejectFn.set(reject); + rejectFun->initExtendedSlot(RejectFunctionSlot_Promise, ObjectValue(*promise)); + rejectFun->initExtendedSlot(RejectFunctionSlot_ResolveFunction, ObjectValue(*resolveFun)); return true; } @@ -1642,14 +1642,16 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto / return nullptr; // Need to wrap the resolution functions before storing them on the Promise. + MOZ_ASSERT(promise->getFixedSlot(PromiseSlot_RejectFunction).isUndefined(), + "Slot must be undefined so initFixedSlot can be used"); if (needsWrapping) { AutoCompartment ac(cx, promise); RootedObject wrappedRejectFn(cx, rejectFn); if (!cx->compartment()->wrap(cx, &wrappedRejectFn)) return nullptr; - promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*wrappedRejectFn)); + promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*wrappedRejectFn)); } else { - promise->setFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn)); + promise->initFixedSlot(PromiseSlot_RejectFunction, ObjectValue(*rejectFn)); } // Step 9. From d3f2375ac64766c41710ea65852f760851491d7a Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 9 Oct 2017 10:01:54 +0200 Subject: [PATCH 03/55] Bug 1405999 part 3 - Inline AutoGCRooter constructors and add MOZ_ALWAYS_INLINE to some functions. r=jonco --- js/src/gc/Barrier.h | 4 +- js/src/jsapi.cpp | 13 ---- js/src/jspubtd.h | 151 ++++++++++++++++++++++++-------------------- 3 files changed, 83 insertions(+), 85 deletions(-) diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 9c4f53975752..b0486f94949d 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -283,7 +283,7 @@ struct InternalBarrierMethods DispatchTyped(PreBarrierFunctor(), v); } - static void postBarrier(Value* vp, const Value& prev, const Value& next) { + static MOZ_ALWAYS_INLINE void postBarrier(Value* vp, const Value& prev, const Value& next) { MOZ_ASSERT(!CurrentThreadIsIonCompiling()); MOZ_ASSERT(vp); @@ -369,7 +369,7 @@ class WriteBarrieredBase : public BarrieredBase, protected: void pre() { InternalBarrierMethods::preBarrier(this->value); } - void post(const T& prev, const T& next) { + MOZ_ALWAYS_INLINE void post(const T& prev, const T& next) { InternalBarrierMethods::postBarrier(&this->value, prev, next); } }; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 87e94e2b3bce..213c8dbf7781 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -7525,19 +7525,6 @@ UnhideScriptedCaller(JSContext* cx) } /* namespace JS */ -AutoGCRooter::AutoGCRooter(JSContext* cx, ptrdiff_t tag) - : AutoGCRooter(JS::RootingContext::get(cx), tag) -{} - -AutoGCRooter::AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag) - : down(cx->autoGCRooters_), - tag_(tag), - stackTop(&cx->autoGCRooters_) -{ - MOZ_ASSERT(this != *stackTop); - *stackTop = this; -} - #ifdef JS_DEBUG JS_PUBLIC_API(void) JS::detail::AssertArgumentsAreSane(JSContext* cx, HandleValue value) diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index a20e1e41e4b7..245cd19d1f65 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -210,11 +210,90 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection) class RootingContext; +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + +using RootedListHeads = mozilla::EnumeratedArray*>; + +/* + * This list enumerates the different types of conceptual stacks we have in + * SpiderMonkey. In reality, they all share the C stack, but we allow different + * stack limits depending on the type of code running. + */ +enum StackKind +{ + StackForSystemCode, // C++, such as the GC, running on behalf of the VM. + StackForTrustedScript, // Script running with trusted principals. + StackForUntrustedScript, // Script running with untrusted principals. + StackKindCount +}; + +class JS_PUBLIC_API(AutoGCRooter); + +// Superclass of JSContext which can be used for rooting data in use by the +// current thread but that does not provide all the functions of a JSContext. +class RootingContext +{ + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; + template friend class JS::Rooted; + + // Stack GC roots for AutoFooRooter classes. + JS::AutoGCRooter* autoGCRooters_; + friend class JS::AutoGCRooter; + + public: + RootingContext(); + + void traceStackRoots(JSTracer* trc); + void checkNoGCRooters(); + + protected: + // The remaining members in this class should only be accessed through + // JSContext pointers. They are unrelated to rooting and are in place so + // that inlined API functions can directly access the data. + + /* The current compartment. */ + JSCompartment* compartment_; + + /* The current zone. */ + JS::Zone* zone_; + + public: + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[StackKindCount]; + + static const RootingContext* get(const JSContext* cx) { + return reinterpret_cast(cx); + } + + static RootingContext* get(JSContext* cx) { + return reinterpret_cast(cx); + } + + friend JSCompartment* js::GetContextCompartment(const JSContext* cx); + friend JS::Zone* js::GetContextZone(const JSContext* cx); +}; + class JS_PUBLIC_API(AutoGCRooter) { public: - AutoGCRooter(JSContext* cx, ptrdiff_t tag); - AutoGCRooter(RootingContext* cx, ptrdiff_t tag); + AutoGCRooter(JSContext* cx, ptrdiff_t tag) + : AutoGCRooter(JS::RootingContext::get(cx), tag) + {} + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag) + : down(cx->autoGCRooters_), + tag_(tag), + stackTop(&cx->autoGCRooters_) + { + MOZ_ASSERT(this != *stackTop); + *stackTop = this; + } ~AutoGCRooter() { MOZ_ASSERT(this == *stackTop); @@ -262,74 +341,6 @@ class JS_PUBLIC_API(AutoGCRooter) void operator=(AutoGCRooter& ida) = delete; }; -// Our instantiations of Rooted and PersistentRooted require an -// instantiation of MapTypeToRootKind. -template <> -struct MapTypeToRootKind { - static const RootKind kind = RootKind::Traceable; -}; - -using RootedListHeads = mozilla::EnumeratedArray*>; - -/* - * This list enumerates the different types of conceptual stacks we have in - * SpiderMonkey. In reality, they all share the C stack, but we allow different - * stack limits depending on the type of code running. - */ -enum StackKind -{ - StackForSystemCode, // C++, such as the GC, running on behalf of the VM. - StackForTrustedScript, // Script running with trusted principals. - StackForUntrustedScript, // Script running with untrusted principals. - StackKindCount -}; - -// Superclass of JSContext which can be used for rooting data in use by the -// current thread but that does not provide all the functions of a JSContext. -class RootingContext -{ - // Stack GC roots for Rooted GC heap pointers. - RootedListHeads stackRoots_; - template friend class JS::Rooted; - - // Stack GC roots for AutoFooRooter classes. - JS::AutoGCRooter* autoGCRooters_; - friend class JS::AutoGCRooter; - - public: - RootingContext(); - - void traceStackRoots(JSTracer* trc); - void checkNoGCRooters(); - - protected: - // The remaining members in this class should only be accessed through - // JSContext pointers. They are unrelated to rooting and are in place so - // that inlined API functions can directly access the data. - - /* The current compartment. */ - JSCompartment* compartment_; - - /* The current zone. */ - JS::Zone* zone_; - - public: - /* Limit pointer for checking native stack consumption. */ - uintptr_t nativeStackLimit[StackKindCount]; - - static const RootingContext* get(const JSContext* cx) { - return reinterpret_cast(cx); - } - - static RootingContext* get(JSContext* cx) { - return reinterpret_cast(cx); - } - - friend JSCompartment* js::GetContextCompartment(const JSContext* cx); - friend JS::Zone* js::GetContextZone(const JSContext* cx); -}; - } /* namespace JS */ namespace js { From e145c72b50219e02a8255f54e00bc5df34928ce1 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 9 Oct 2017 10:03:14 +0200 Subject: [PATCH 04/55] Bug 1405999 part 4 - Optimize and clean up NewNativeFunction and related functions. r=anba --- js/src/jsfun.cpp | 38 +++----------------------------------- js/src/jsfun.h | 48 +++++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 58 deletions(-) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index f5e69ef9fd23..d25cb798ba9d 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2036,28 +2036,6 @@ JSFunction::needsNamedLambdaEnvironment() const return scope->hasEnvironment(); } -JSFunction* -js::NewNativeFunction(JSContext* cx, Native native, unsigned nargs, HandleAtom atom, - gc::AllocKind allocKind /* = AllocKind::FUNCTION */, - NewObjectKind newKind /* = SingletonObject */) -{ - MOZ_ASSERT(native); - return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN, - nullptr, atom, nullptr, allocKind, newKind); -} - -JSFunction* -js::NewNativeConstructor(JSContext* cx, Native native, unsigned nargs, HandleAtom atom, - gc::AllocKind allocKind /* = AllocKind::FUNCTION */, - NewObjectKind newKind /* = SingletonObject */, - JSFunction::Flags flags /* = JSFunction::NATIVE_CTOR */) -{ - MOZ_ASSERT(native); - MOZ_ASSERT(flags & JSFunction::NATIVE_CTOR); - return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, - nullptr, allocKind, newKind); -} - JSFunction* js::NewScriptedFunction(JSContext* cx, unsigned nargs, JSFunction::Flags flags, HandleAtom atom, @@ -2092,26 +2070,16 @@ js::NewFunctionWithProto(JSContext* cx, Native native, unsigned nargs, JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom, HandleObject proto, gc::AllocKind allocKind /* = AllocKind::FUNCTION */, - NewObjectKind newKind /* = GenericObject */, - NewFunctionProtoHandling protoHandling /* = NewFunctionClassProto */) + NewObjectKind newKind /* = GenericObject */) { MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED); MOZ_ASSERT_IF(native, !enclosingEnv); MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv)); - RootedObject funobj(cx); - if (protoHandling == NewFunctionClassProto) { - funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind, - newKind); - } else { - funobj = NewObjectWithGivenTaggedProto(cx, &JSFunction::class_, AsTaggedProto(proto), - allocKind, newKind); - } - if (!funobj) + JSFunction* fun = NewObjectWithClassProto(cx, proto, allocKind, newKind); + if (!fun) return nullptr; - RootedFunction fun(cx, &funobj->as()); - if (allocKind == AllocKind::FUNCTION_EXTENDED) flags = JSFunction::Flags(flags | JSFunction::EXTENDED); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index d611c41c2941..646cf01f89da 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -687,20 +687,41 @@ AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp); extern bool AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp); +// If enclosingEnv is null, the function will have a null environment() +// (yes, null, not the global). In all cases, the global will be used as the +// parent. + +extern JSFunction* +NewFunctionWithProto(JSContext* cx, JSNative native, unsigned nargs, + JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom, + HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, + NewObjectKind newKind = GenericObject); + // Allocate a new function backed by a JSNative. Note that by default this // creates a singleton object. -extern JSFunction* +inline JSFunction* NewNativeFunction(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, - NewObjectKind newKind = SingletonObject); + NewObjectKind newKind = SingletonObject) +{ + MOZ_ASSERT(native); + return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN, + nullptr, atom, nullptr, allocKind, newKind); +} // Allocate a new constructor backed by a JSNative. Note that by default this // creates a singleton object. -extern JSFunction* +inline JSFunction* NewNativeConstructor(JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, NewObjectKind newKind = SingletonObject, - JSFunction::Flags flags = JSFunction::NATIVE_CTOR); + JSFunction::Flags flags = JSFunction::NATIVE_CTOR) +{ + MOZ_ASSERT(native); + MOZ_ASSERT(flags & JSFunction::NATIVE_CTOR); + return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, + nullptr, allocKind, newKind); +} // Allocate a new scripted function. If enclosingEnv is null, the // global will be used. In all cases the parent of the resulting object will be @@ -711,25 +732,6 @@ NewScriptedFunction(JSContext* cx, unsigned nargs, JSFunction::Flags flags, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, NewObjectKind newKind = GenericObject, HandleObject enclosingEnv = nullptr); - -// By default, if proto is nullptr, Function.prototype is used instead.i -// If protoHandling is NewFunctionExactProto, and proto is nullptr, the created -// function will use nullptr as its [[Prototype]] instead. If -// enclosingEnv is null, the function will have a null environment() -// (yes, null, not the global). In all cases, the global will be used as the -// parent. - -enum NewFunctionProtoHandling { - NewFunctionClassProto, - NewFunctionGivenProto -}; -extern JSFunction* -NewFunctionWithProto(JSContext* cx, JSNative native, unsigned nargs, - JSFunction::Flags flags, HandleObject enclosingEnv, HandleAtom atom, - HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, - NewObjectKind newKind = GenericObject, - NewFunctionProtoHandling protoHandling = NewFunctionClassProto); - extern JSAtom* IdToFunctionName(JSContext* cx, HandleId id, FunctionPrefixKind prefixKind = FunctionPrefixKind::None); From e763e6c4a2460dc805df909e130f3dd9c64998e9 Mon Sep 17 00:00:00 2001 From: Shawn Huang Date: Mon, 9 Oct 2017 16:57:55 +0800 Subject: [PATCH 05/55] Bug 1389561 - Part 2: Add MOZ_DIAGNOSTIC_ASSERT for mTemporaryStorageInitialized, r=janv --- dom/quota/ActorsParent.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 38beaa13030e..94820e2e2b1a 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -3830,6 +3830,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); +#if defined(NIGHTLY_BUILD) + { + MutexAutoLock autoLock(mQuotaMutex); + MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized); + } +#endif + if (aFileSizeOut) { *aFileSizeOut = 0; } @@ -3923,6 +3930,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); +#if defined(NIGHTLY_BUILD) + { + MutexAutoLock autoLock(mQuotaMutex); + MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized); + } +#endif + if (aFileSizeOut) { *aFileSizeOut = 0; } @@ -5242,7 +5256,14 @@ QuotaManager::EnsureOriginIsInitializedInternal( NS_ENSURE_SUCCESS(rv, rv); } +#if defined(NIGHTLY_BUILD) + { + MutexAutoLock autoLock(mQuotaMutex); mTemporaryStorageInitialized = true; + } +#else + mTemporaryStorageInitialized = true; +#endif CheckTemporaryStorageLimits(); } @@ -5328,7 +5349,16 @@ QuotaManager::ResetOrClearCompleted() AssertIsOnIOThread(); mInitializedOrigins.Clear(); - mTemporaryStorageInitialized = false; + +#if defined(NIGHTLY_BUILD) + { + MutexAutoLock autoLock(mQuotaMutex); + mTemporaryStorageInitialized = false; + } +#else + mTemporaryStorageInitialized = false; +#endif + mStorageInitialized = false; ReleaseIOThreadObjects(); From b6270c9da74a232276061e92ac4707530d1fc054 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 9 Oct 2017 10:03:20 +0100 Subject: [PATCH 06/55] Bug 1400003 - Mark Heap and barrier classes as MOZ_NON_MEMMOVABLE r=sfink r=froydnj --- js/public/RootingAPI.h | 10 +++++++++- js/src/gc/Barrier.h | 5 ++++- xpcom/ds/nsTArray.h | 27 +++++++++++++-------------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 528a15ae1f18..81a9f3020b6f 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -237,7 +237,7 @@ AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {} * Type T must be a public GC pointer type. */ template -class Heap : public js::HeapBase> +class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase> { // Please note: this can actually also be used by nsXBLMaybeCompiled, for legacy reasons. static_assert(js::IsHeapConstructibleType::value, @@ -1173,6 +1173,14 @@ class JS_PUBLIC_API(ObjectPtr) explicit ObjectPtr(JSObject* obj) : value(obj) {} + ObjectPtr(const ObjectPtr& other) : value(other.value) {} + + ObjectPtr(ObjectPtr&& other) + : value(other.value) + { + other.value = nullptr; + } + /* Always call finalize before the destructor. */ ~ObjectPtr() { MOZ_ASSERT(!value); } diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index b0486f94949d..dc6af50bb079 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -318,8 +318,11 @@ struct InternalBarrierMethods }; // Base class of all barrier types. +// +// This is marked non-memmovable since post barriers added by derived classes +// can add pointers to class instances to the store buffer. template -class BarrieredBase +class MOZ_NON_MEMMOVABLE BarrieredBase { protected: // BarrieredBase is not directly instantiable. diff --git a/xpcom/ds/nsTArray.h b/xpcom/ds/nsTArray.h index 424a50ba421e..4e9b57126bfb 100644 --- a/xpcom/ds/nsTArray.h +++ b/xpcom/ds/nsTArray.h @@ -37,6 +37,7 @@ namespace JS { template class Heap; +class ObjectPtr; } /* namespace JS */ class nsRegion; @@ -708,7 +709,7 @@ struct nsTArray_CopyWithConstructors template struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser { - typedef nsTArray_CopyWithMemutils Type; + using Type = nsTArray_CopyWithMemutils; }; // @@ -719,14 +720,18 @@ struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser template<> \ struct nsTArray_CopyChooser \ { \ - typedef nsTArray_CopyWithConstructors Type; \ + using Type = nsTArray_CopyWithConstructors; \ }; -template -struct nsTArray_CopyChooser> -{ - typedef nsTArray_CopyWithConstructors> Type; -}; +#define DECLARE_USE_COPY_CONSTRUCTORS_FOR_TEMPLATE(T) \ + template \ + struct nsTArray_CopyChooser> \ + { \ + using Type = nsTArray_CopyWithConstructors>; \ + }; + +DECLARE_USE_COPY_CONSTRUCTORS_FOR_TEMPLATE(JS::Heap) +DECLARE_USE_COPY_CONSTRUCTORS_FOR_TEMPLATE(std::function) DECLARE_USE_COPY_CONSTRUCTORS(nsRegion) DECLARE_USE_COPY_CONSTRUCTORS(nsIntRegion) @@ -740,13 +745,7 @@ DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::SerializedStructuredClone DECLARE_USE_COPY_CONSTRUCTORS(JSStructuredCloneData) DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::MessagePortMessage) DECLARE_USE_COPY_CONSTRUCTORS(mozilla::SourceBufferTask) - -template -struct nsTArray_CopyChooser> -{ - typedef nsTArray_CopyWithConstructors> Type; -}; - +DECLARE_USE_COPY_CONSTRUCTORS(JS::ObjectPtr) // // Base class for nsTArray_Impl that is templated on element type and derived From a05866a7278750648ce6cc1d3d8fece016f391f0 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 9 Oct 2017 10:22:44 +0100 Subject: [PATCH 07/55] Bug 1402473 - Relax RegExpShared assert to ignore shutdown leaks r=jandem --- js/src/gc/Zone.cpp | 7 +++++-- js/src/vm/RegExpShared.h | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 1fc8870028ee..e60eac7b10e2 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -82,9 +82,12 @@ Zone::~Zone() js_delete(jitZone_.ref()); #ifdef DEBUG - // Avoid assertion destroying the weak map list if the embedding leaked GC things. - if (!rt->gc.shutdownCollectedEverything()) + // Avoid assertions failures warning that not everything has been destroyed + // if the embedding leaked GC things. + if (!rt->gc.shutdownCollectedEverything()) { gcWeakMapList().clear(); + regExps.clear(); + } #endif } diff --git a/js/src/vm/RegExpShared.h b/js/src/vm/RegExpShared.h index 6fd54066b1d3..d111ff419f05 100644 --- a/js/src/vm/RegExpShared.h +++ b/js/src/vm/RegExpShared.h @@ -279,6 +279,10 @@ class RegExpZone /* Like 'get', but compile 'maybeOpt' (if non-null). */ RegExpShared* get(JSContext* cx, HandleAtom source, JSString* maybeOpt); +#ifdef DEBUG + void clear() { set_.clear(); } +#endif + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); }; From 3a810c3d6382ef288d73e5819e8079bfdc997be1 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 9 Oct 2017 10:22:44 +0100 Subject: [PATCH 08/55] Bug 1259222 - Add more assertions to hopefully catch bad pointers when collecting the nursery r=sfink --- js/public/Value.h | 25 ++++++++++++++++++------- js/src/gc/Marking.cpp | 3 +++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/js/public/Value.h b/js/public/Value.h index 8734365de880..3347f159f9d8 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1428,14 +1428,25 @@ auto DispatchTyped(F f, const JS::Value& val, Args&&... args) -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) { - if (val.isString()) - return f(val.toString(), mozilla::Forward(args)...); - if (val.isObject()) - return f(&val.toObject(), mozilla::Forward(args)...); - if (val.isSymbol()) - return f(val.toSymbol(), mozilla::Forward(args)...); - if (MOZ_UNLIKELY(val.isPrivateGCThing())) + if (val.isString()) { + JSString* str = val.toString(); + MOZ_ASSERT(gc::IsCellPointerValid(str)); + return f(str, mozilla::Forward(args)...); + } + if (val.isObject()) { + JSObject* obj = &val.toObject(); + MOZ_ASSERT(gc::IsCellPointerValid(obj)); + return f(obj, mozilla::Forward(args)...); + } + if (val.isSymbol()) { + JS::Symbol* sym = val.toSymbol(); + MOZ_ASSERT(gc::IsCellPointerValid(sym)); + return f(sym, mozilla::Forward(args)...); + } + if (MOZ_UNLIKELY(val.isPrivateGCThing())) { + MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing())); return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); + } MOZ_ASSERT(!val.isGCThing()); return F::defaultValue(val); } diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 4a0c68f4fd91..21b5a0568afc 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2716,6 +2716,7 @@ void js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const { NativeObject* obj = object(); + MOZ_ASSERT(IsCellPointerValid(obj)); // Beware JSObject::swap exchanging a native object for a non-native one. if (!obj->isNative()) @@ -2788,6 +2789,7 @@ js::gc::StoreBuffer::traceWholeCells(TenuringTracer& mover) { for (ArenaCellSet* cells = bufferWholeCell; cells; cells = cells->next) { Arena* arena = cells->arena; + MOZ_ASSERT(IsCellPointerValid(arena)); MOZ_ASSERT(arena->bufferedCells() == cells); arena->bufferedCells() = &ArenaCellSet::Empty; @@ -2817,6 +2819,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const if (!*edge) return; + MOZ_ASSERT(IsCellPointerValid(*edge)); MOZ_ASSERT((*edge)->getTraceKind() == JS::TraceKind::Object); mover.traverse(reinterpret_cast(edge)); } From b4627e9a7c7036c370cdd50d18abb707ecd7c102 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 5 Oct 2017 11:40:00 +0200 Subject: [PATCH 09/55] Bug 1347740: Use a rectifier frame when calling from wasm to jit; r=jandem, r=luke MozReview-Commit-ID: IvkmE7GX8CJ --HG-- extra : rebase_source : 7256257b71c4969c3349b95df38851b8f18c76d3 extra : amend_source : 910f55958c1aa958de598b17c77e0f7ac518e53d --- js/src/jit-test/tests/wasm/import-export.js | 65 ++++++++++++++++++--- js/src/jit-test/tests/wasm/profiling.js | 58 ++++++++++++++---- js/src/jit/BaselineBailouts.cpp | 10 ++-- js/src/jit/Ion.cpp | 9 +++ js/src/jit/JSJitFrameIter.cpp | 24 ++++++-- js/src/jit/JSJitFrameIter.h | 1 + js/src/jit/JitFrames.h | 4 +- js/src/jit/MacroAssembler.cpp | 16 +++++ js/src/jit/MacroAssembler.h | 2 + js/src/jit/arm/Trampoline-arm.cpp | 30 +++++----- js/src/jit/arm64/Trampoline-arm64.cpp | 24 ++++---- js/src/jit/mips32/Trampoline-mips32.cpp | 30 +++++----- js/src/jit/mips64/Trampoline-mips64.cpp | 30 +++++----- js/src/jit/x64/Trampoline-x64.cpp | 32 +++++----- js/src/jit/x86/Trampoline-x86.cpp | 30 +++++----- js/src/vm/Stack.cpp | 1 + js/src/wasm/WasmInstance.cpp | 29 +++++++-- js/src/wasm/WasmInstance.h | 3 + js/src/wasm/WasmStubs.cpp | 33 ++++++++--- 19 files changed, 292 insertions(+), 139 deletions(-) diff --git a/js/src/jit-test/tests/wasm/import-export.js b/js/src/jit-test/tests/wasm/import-export.js index 17743ee09edc..e773b8520e2d 100644 --- a/js/src/jit-test/tests/wasm/import-export.js +++ b/js/src/jit-test/tests/wasm/import-export.js @@ -619,26 +619,71 @@ assertEq(e.call(), 1090); let valueToConvert = 0; function ffi(n) { if (n == 1337) { return valueToConvert }; return 42; } - // Baseline compile ffi. - for (let i = baselineTrigger + 1; i --> 0;) - ffi(i); + function sum(a, b, c) { + if (a === 1337) + return valueToConvert; + return (a|0) + (b|0) + (c|0) | 0; + } - let imports = { a: { ffi }}; + // Baseline compile ffis. + for (let i = baselineTrigger + 1; i --> 0;) { + ffi(i); + sum((i%2)?i:undefined, + (i%3)?i:undefined, + (i%4)?i:undefined); + } + + let imports = { + a: { + ffi, + sum + } + }; i = wasmEvalText(`(module (import $ffi "a" "ffi" (param i32) (result i32)) - (func $foo (export "foo") (param i32) (result i32) + + (import $missingOneArg "a" "sum" (param i32) (param i32) (result i32)) + (import $missingTwoArgs "a" "sum" (param i32) (result i32)) + (import $missingThreeArgs "a" "sum" (result i32)) + + (func (export "foo") (param i32) (result i32) get_local 0 - call $ffi) + call $ffi + ) + + (func (export "missThree") (result i32) + call $missingThreeArgs + ) + + (func (export "missTwo") (param i32) (result i32) + get_local 0 + call $missingTwoArgs + ) + + (func (export "missOne") (param i32) (param i32) (result i32) + get_local 0 + get_local 1 + call $missingOneArg + ) )`, imports).exports; - // Enable the jit exit. + // Enable the jit exit for each JS callee. assertEq(i.foo(0), 42); - // Test the jit exit. + assertEq(i.missThree(), 0); + assertEq(i.missTwo(42), 42); + assertEq(i.missOne(13, 37), 50); + + // Test the jit exit under normal conditions. assertEq(i.foo(0), 42); assertEq(i.foo(1337), 0); + // Test the arguments rectifier. + assertEq(i.missThree(), 0); + assertEq(i.missTwo(-1), -1); + assertEq(i.missOne(23, 10), 33); + // Test OOL coercion. valueToConvert = 2**31; assertEq(i.foo(1337), -(2**31)); @@ -649,5 +694,7 @@ assertEq(e.call(), 1090); valueToConvert = { toString() { throw new Error('a FFI to believe in'); } } assertErrorMessage(() => i.foo(1337), Error, "a FFI to believe in"); -})(); + // Test the error path in the arguments rectifier. + assertErrorMessage(() => i.missTwo(1337), Error, "a FFI to believe in"); +})(); diff --git a/js/src/jit-test/tests/wasm/profiling.js b/js/src/jit-test/tests/wasm/profiling.js index 3c2b13c148b5..ad06a830a9c8 100644 --- a/js/src/jit-test/tests/wasm/profiling.js +++ b/js/src/jit-test/tests/wasm/profiling.js @@ -331,9 +331,17 @@ for (let type of ['f32', 'f64']) { var m = new Module(wasmTextToBinary(`(module (import $ffi "a" "ffi" (param i32) (result i32)) - (func $foo (export "foo") (param i32) (result i32) + + (import $missingOneArg "a" "sumTwo" (param i32) (result i32)) + + (func (export "foo") (param i32) (result i32) get_local 0 call $ffi) + + (func (export "id") (param i32) (result i32) + get_local 0 + call $missingOneArg + ) )`)); var valueToConvert = 0; @@ -343,45 +351,71 @@ for (let type of ['f32', 'f64']) { return 42; } - // Baseline compile ffi. - for (var i = 20; i --> 0;) - ffi(i); + function sumTwo(a, b) { + return (a|0)+(b|0)|0; + } - var imports = { a: { ffi }}; + // Baseline compile ffi. + for (var i = 20; i --> 0;) { + ffi(i); + sumTwo(i-1, i+1); + } + + var imports = { + a: { + ffi, + sumTwo + } + }; var i = new Instance(m, imports).exports; // Enable the jit exit. assertEq(i.foo(0), 42); + assertEq(i.id(13), 13); + // Test normal conditions. enableSingleStepProfiling(); assertEq(i.foo(0), 42); - assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "<,1,>", + assertEqStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>", // Losing stack information while the JIT func prologue sets profiler // virtual FP. "", // Callee time. - "<,1,>", + "<,2,>", // Losing stack information while we're exiting JIT func epilogue and // recovering wasm FP. "", // Back into the jit exit (frame info has been recovered). - "<,1,>", + "<,2,>", // Normal unwinding. - "1,>", ">", ""]); + "2,>", ">", ""]); + + // Test rectifier frame. + enableSingleStepProfiling(); + assertEq(i.id(100), 100); + assertEqStacks(disableSingleStepProfiling(), ["", ">", "3,>", "<,3,>", + // Rectifier frame time is spent here (lastProfilingFrame has not been + // set). + "", + "<,3,>", + // Rectifier frame unwinding time is spent here. + "", + "<,3,>", + "3,>", ">", ""]); // Test OOL coercion path. valueToConvert = 2**31; enableSingleStepProfiling(); assertEq(i.foo(1337), -(2**31)); - assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "<,1,>", "", "<,1,>", "", + assertEqStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>", "", "<,2,>", "", // Back into the jit exit (frame info has been recovered). // Inline conversion fails, we skip to the OOL path, call from there // and get back to the jit exit. - "<,1,>", + "<,2,>", // Normal unwinding. - "1,>", ">", ""]); + "2,>", ">", ""]); disableGeckoProfiling(); setJitCompilerOption("baseline.warmup.trigger", prevOptions["baseline.warmup.trigger"]); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index b4b9369a0207..a18ab915801f 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -394,11 +394,13 @@ struct BaselineStackBuilder BufferPointer priorFrame = pointerAtStackOffset(priorOffset); FrameType priorType = priorFrame->prevType(); - MOZ_ASSERT(priorType == JitFrame_IonJS || priorType == JitFrame_BaselineStub); + MOZ_ASSERT(priorType == JitFrame_WasmToJSJit || + priorType == JitFrame_IonJS || + priorType == JitFrame_BaselineStub); - // If the frame preceding the rectifier is an IonJS frame, then once again - // the frame pointer does not matter. - if (priorType == JitFrame_IonJS) + // If the frame preceding the rectifier is an IonJS or WasmToJSJit + // entry frame, then once again the frame pointer does not matter. + if (priorType == JitFrame_IonJS || priorType == JitFrame_WasmToJSJit) return nullptr; // Otherwise, the frame preceding the rectifier is a BaselineStub frame. diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index f4a2f0485923..d733dca2d371 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -280,6 +280,15 @@ JitRuntime::initialize(JSContext* cx, AutoLockForExclusiveAccess& lock) return false; } + // The arguments rectifier has to use the same frame layout as the function + // frames it rectifies. + static_assert(mozilla::IsBaseOf::value, + "a rectifier frame can be used with jit frame"); + static_assert(mozilla::IsBaseOf::value, + "wasm frames simply are jit frames"); + static_assert(sizeof(JitFrameLayout) == sizeof(WasmToJSJitFrameLayout), + "thus a rectifier frame can be used with a wasm frame"); + JitSpew(JitSpew_Codegen, "# Emitting sequential arguments rectifier"); argumentsRectifier_ = generateArgumentsRectifier(cx, &argumentsRectifierReturnAddr_.writeRef()); if (!argumentsRectifier_) diff --git a/js/src/jit/JSJitFrameIter.cpp b/js/src/jit/JSJitFrameIter.cpp index 91a80fc2c472..555bd684fdbd 100644 --- a/js/src/jit/JSJitFrameIter.cpp +++ b/js/src/jit/JSJitFrameIter.cpp @@ -643,6 +643,17 @@ JSJitProfilingFrameIterator::operator++() moveToNextFrame(frame); } +void +JSJitProfilingFrameIterator::moveToWasmFrame(CommonFrameLayout* frame) +{ + // No previous js jit frame, this is a transition frame, used to + // pass a wasm iterator the correct value of FP. + returnAddressToFp_ = nullptr; + fp_ = GetPreviousRawFrame(frame); + type_ = JitFrame_WasmToJSJit; + MOZ_ASSERT(!done()); +} + void JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame) { @@ -666,6 +677,8 @@ JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame) * | ^--- Ion * | | * | ^--- Baseline Stub <---- Baseline + * | | + * | ^--- WasmToJSJit <--- (other wasm frames) * | * ^--- Entry Frame (From C++) * Exit Frame (From previous JitActivation) @@ -726,6 +739,11 @@ JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame) return; } + if (rectPrevType == JitFrame_WasmToJSJit) { + moveToWasmFrame(rectFrame); + return; + } + MOZ_CRASH("Bad frame type prior to rectifier frame."); } @@ -742,11 +760,7 @@ JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame) } if (prevType == JitFrame_WasmToJSJit) { - // No previous js jit frame, this is a transition frame, used to pass - // a wasm iterator the correct value of FP. - returnAddressToFp_ = nullptr; - fp_ = GetPreviousRawFrame(frame); - type_ = JitFrame_WasmToJSJit; + moveToWasmFrame(frame); return; } diff --git a/js/src/jit/JSJitFrameIter.h b/js/src/jit/JSJitFrameIter.h index 37aa50ea8315..ffa232c93f54 100644 --- a/js/src/jit/JSJitFrameIter.h +++ b/js/src/jit/JSJitFrameIter.h @@ -297,6 +297,7 @@ class JSJitProfilingFrameIterator bool forLastCallSite); void fixBaselineReturnAddress(); + void moveToWasmFrame(CommonFrameLayout* frame); void moveToNextFrame(CommonFrameLayout* frame); public: diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h index e82850abeedd..8d9473d62879 100644 --- a/js/src/jit/JitFrames.h +++ b/js/src/jit/JitFrames.h @@ -445,11 +445,11 @@ class RectifierFrameLayout : public JitFrameLayout } }; -class WasmFrameLayout : public JitFrameLayout +class WasmToJSJitFrameLayout : public JitFrameLayout { public: static inline size_t Size() { - return sizeof(WasmFrameLayout); + return sizeof(WasmToJSJitFrameLayout); } }; diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index a7f9696e6b9e..98ce7047bd82 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1654,6 +1654,22 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo) } } +void +MacroAssembler::assertRectifierFrameParentType(Register frameType) +{ +#ifdef DEBUG + { + // Check the possible previous frame types here. + Label checkOk; + branch32(Assembler::Equal, frameType, Imm32(JitFrame_IonJS), &checkOk); + branch32(Assembler::Equal, frameType, Imm32(JitFrame_BaselineStub), &checkOk); + branch32(Assembler::Equal, frameType, Imm32(JitFrame_WasmToJSJit), &checkOk); + assumeUnreachable("Unrecognized frame type preceding RectifierFrame."); + bind(&checkOk); + } +#endif +} + void MacroAssembler::loadBaselineOrIonRaw(Register script, Register dest, Label* failure) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 8e9180b32327..be829fff42f8 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1837,6 +1837,8 @@ class MacroAssembler : public MacroAssemblerSpecific // Generates code used to complete a bailout. void generateBailoutTail(Register scratch, Register bailoutInfo); + void assertRectifierFrameParentType(Register frameType); + public: #ifndef JS_CODEGEN_ARM64 // StackPointer manipulation functions. diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp index 7e7e73c73cb5..b0a3f486a66e 100644 --- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -1287,10 +1287,10 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or + // a BaselineStub frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr @@ -1335,10 +1335,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type + masm.assertRectifierFrameParentType(scratch3); + // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1351,16 +1352,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif masm.ma_add(scratch2, scratch1, scratch3); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1424,7 +1422,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/jit/arm64/Trampoline-arm64.cpp b/js/src/jit/arm64/Trampoline-arm64.cpp index 8780d24cef56..4d1c6b1c5f60 100644 --- a/js/src/jit/arm64/Trampoline-arm64.cpp +++ b/js/src/jit/arm64/Trampoline-arm64.cpp @@ -1128,10 +1128,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type + masm.assertRectifierFrameParentType(scratch3); + // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1144,16 +1145,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif masm.addPtr(scratch2, scratch1, scratch3); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1218,7 +1216,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/jit/mips32/Trampoline-mips32.cpp b/js/src/jit/mips32/Trampoline-mips32.cpp index 96cf35f0ad8b..fce2fcdf3559 100644 --- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -1266,10 +1266,10 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or + // a BaselineStub frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr @@ -1314,10 +1314,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type + masm.assertRectifierFrameParentType(scratch3); + // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1330,16 +1331,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif masm.as_addu(scratch3, scratch2, scratch1); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1403,7 +1401,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp index 0ac1fc3b9768..1903b94a50f4 100644 --- a/js/src/jit/mips64/Trampoline-mips64.cpp +++ b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -1211,10 +1211,10 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or + // a BaselineStub frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr @@ -1259,10 +1259,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type + masm.assertRectifierFrameParentType(scratch3); + // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1275,16 +1276,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif masm.as_daddu(scratch3, scratch2, scratch1); Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1348,7 +1346,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 13b74407562f..9322455faef9 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -1180,10 +1180,10 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or + // a BaselineStub frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr @@ -1228,10 +1228,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type - // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + masm.assertRectifierFrameParentType(scratch3); + + // Check for either Ion or something else frame. + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1243,16 +1244,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1314,7 +1312,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 6b6aad610b4c..0aaf6361f129 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -1214,10 +1214,10 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // // JitFrame_Rectifier // - // The rectifier frame can be preceded by either an IonJS or a - // BaselineStub frame. + // The rectifier frame can be preceded by either an IonJS, a WasmToJSJit or + // a BaselineStub frame. // - // Stack layout if caller of rectifier was Ion: + // Stack layout if caller of rectifier was Ion or WasmToJSJit: // // Ion-Descriptor // Ion-ReturnAddr @@ -1262,10 +1262,11 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) // and |scratch2| points to Rectifier frame // and |scratch3| contains Rect-Descriptor.Type + masm.assertRectifierFrameParentType(scratch3); + // Check for either Ion or BaselineStub frame. - Label handle_Rectifier_BaselineStub; - masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), - &handle_Rectifier_BaselineStub); + Label notIonFrame; + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS), ¬IonFrame); // Handle Rectifier <- IonJS // scratch3 := RectFrame[ReturnAddr] @@ -1277,16 +1278,13 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) masm.storePtr(scratch3, lastProfilingFrame); masm.ret(); + masm.bind(¬IonFrame); + + // Check for either BaselineStub or WasmToJSJit: since WasmToJSJit is + // just an entry, jump there if we see it. + masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_BaselineStub), &handle_Entry); + // Handle Rectifier <- BaselineStub <- BaselineJS - masm.bind(&handle_Rectifier_BaselineStub); -#ifdef DEBUG - { - Label checkOk; - masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk); - masm.assumeUnreachable("Unrecognized frame preceding baselineStub."); - masm.bind(&checkOk); - } -#endif BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size() + BaselineStubFrameLayout::offsetOfReturnAddress()); @@ -1348,7 +1346,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx) } // - // JitFrame_CppToJSJit / JitFrame_WasmJSToJit + // JitFrame_CppToJSJit / JitFrame_WasmToJSJit // // If at an entry frame, store null into both fields. // A fast-path wasm->jit transition frame is an entry frame from the point diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 915b2517b8d4..3cf55cb1761c 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -538,6 +538,7 @@ JitFrameIter::skipNonScriptedJSFrames() jit::JSJitFrameIter& frames = asJSJit(); while (!frames.isScripted() && !frames.done()) ++frames; + settle(); } } diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp index 213c70119f1c..ca5eff96b02d 100644 --- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -215,10 +215,6 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con if (script->baselineScript()->hasPendingIonBuilder()) return true; - // Currently we can't rectify arguments. Therefore disable if argc is too low. - if (importFun->nargs() > fi.sig().args().length()) - return true; - // Ensure the argument types are included in the argument TypeSets stored in // the TypeScript. This is necessary for Ion, because the import will use // the skip-arg-checks entry point. @@ -229,9 +225,13 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con // patched back. if (!TypeScript::ThisTypes(script)->hasType(TypeSet::UndefinedType())) return true; - for (uint32_t i = 0; i < importFun->nargs(); i++) { + + const ValTypeVector& importArgs = fi.sig().args(); + + size_t numKnownArgs = Min(importArgs.length(), importFun->nargs()); + for (uint32_t i = 0; i < numKnownArgs; i++) { TypeSet::Type type = TypeSet::UnknownType(); - switch (fi.sig().args()[i]) { + switch (importArgs[i]) { case ValType::I32: type = TypeSet::Int32Type(); break; case ValType::I64: MOZ_CRASH("can't happen because of above guard"); case ValType::F32: type = TypeSet::DoubleType(); break; @@ -248,6 +248,14 @@ Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, con return true; } + // These arguments will be filled with undefined at runtime by the + // arguments rectifier: check that the imported function can handle + // undefined there. + for (uint32_t i = importArgs.length(); i < importFun->nargs(); i++) { + if (!TypeScript::ArgTypes(script, i)->hasType(TypeSet::UndefinedType())) + return true; + } + // Let's optimize it! if (!script->baselineScript()->addDependentWasmImport(cx, *this, funcImportIndex)) return false; @@ -451,6 +459,13 @@ Instance::init(JSContext* cx) } } + if (!metadata(code_->bestTier()).funcImports.empty()) { + JitRuntime* jitRuntime = cx->runtime()->getJitRuntime(cx); + if (!jitRuntime) + return false; + jsJitArgsRectifier_ = jitRuntime->getArgumentsRectifier(); + } + return true; } @@ -508,6 +523,8 @@ Instance::tracePrivate(JSTracer* trc) MOZ_ASSERT(!gc::IsAboutToBeFinalized(&object_)); TraceEdge(trc, &object_, "wasm instance object"); + TraceNullableEdge(trc, &jsJitArgsRectifier_, "wasm jit args rectifier"); + // OK to just do one tier here; though the tiers have different funcImports // tables, they share the tls object. for (const FuncImport& fi : metadata(code().stableTier()).funcImports) diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h index 754e4c5b419a..e1c5784be50f 100644 --- a/js/src/wasm/WasmInstance.h +++ b/js/src/wasm/WasmInstance.h @@ -71,6 +71,7 @@ class Instance { JSCompartment* const compartment_; ReadBarrieredWasmInstanceObject object_; + GCPtrJitCode jsJitArgsRectifier_; const SharedCode code_; const UniqueDebugState debug_; const UniqueGlobalSegment globals_; @@ -122,6 +123,8 @@ class Instance bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const; TlsData* tlsData() const { return globals_->tlsData(); } + static size_t offsetOfJSJitArgsRectifier() { return offsetof(Instance, jsJitArgsRectifier_); } + // This method returns a pointer to the GC object that owns this Instance. // Instances may be reached via weak edges (e.g., Compartment::instances_) // so this perform a read-barrier on the returned object unless the barrier diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp index 63cfec9909bf..83d0141a6747 100644 --- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -23,6 +23,7 @@ #include "wasm/WasmCode.h" #include "wasm/WasmGenerator.h" +#include "wasm/WasmInstance.h" #include "jit/MacroAssembler-inl.h" @@ -710,7 +711,7 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa // the return address. static_assert(WasmStackAlignment >= JitStackAlignment, "subsumes"); unsigned sizeOfRetAddr = sizeof(void*); - unsigned sizeOfPreFrame = WasmFrameLayout::Size() - sizeOfRetAddr; + unsigned sizeOfPreFrame = WasmToJSJitFrameLayout::Size() - sizeOfRetAddr; unsigned sizeOfThisAndArgs = (1 + fi.sig().args().length()) * sizeof(Value); unsigned totalJitFrameBytes = sizeOfRetAddr + sizeOfPreFrame + sizeOfThisAndArgs; unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) - @@ -722,7 +723,7 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa // 1. Descriptor size_t argOffset = 0; uint32_t descriptor = MakeFrameDescriptor(sizeOfThisAndArgsAndPadding, JitFrame_WasmToJSJit, - WasmFrameLayout::Size()); + WasmToJSJitFrameLayout::Size()); masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(masm.getStackPointer(), argOffset)); argOffset += sizeof(size_t); @@ -730,17 +731,13 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa Register callee = ABINonArgReturnReg0; // live until call Register scratch = ABINonArgReturnReg1; // repeatedly clobbered - // 2.1. Get callee + // 2.1. Get JSFunction callee masm.loadWasmGlobalPtr(fi.tlsDataOffset() + offsetof(FuncImportTls, obj), callee); // 2.2. Save callee masm.storePtr(callee, Address(masm.getStackPointer(), argOffset)); argOffset += sizeof(size_t); - // 2.3. Load callee executable entry point - masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee); - masm.loadBaselineOrIonNoArgCheck(callee, callee, nullptr); - // 3. Argc unsigned argc = fi.sig().args().length(); masm.storePtr(ImmWord(uintptr_t(argc)), Address(masm.getStackPointer(), argOffset)); @@ -757,6 +754,19 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa argOffset += fi.sig().args().length() * sizeof(Value); MOZ_ASSERT(argOffset == sizeOfThisAndArgs + sizeOfPreFrame); + // 6. Check if we need to rectify arguments + masm.load16ZeroExtend(Address(callee, JSFunction::offsetOfNargs()), scratch); + + Label rectify; + masm.branch32(Assembler::Above, scratch, Imm32(fi.sig().args().length()), &rectify); + + // 7. If we haven't rectified arguments, load callee executable entry point + masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee); + masm.loadBaselineOrIonNoArgCheck(callee, callee, nullptr); + + Label rejoinBeforeCall; + masm.bind(&rejoinBeforeCall); + AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr); masm.callJitNoProfiler(callee); @@ -818,6 +828,15 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa GenerateJitExitEpilogue(masm, masm.framePushed(), offsets); + { + // Call the arguments rectifier. + masm.bind(&rectify); + masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, instance)), callee); + masm.loadPtr(Address(callee, Instance::offsetOfJSJitArgsRectifier()), callee); + masm.loadPtr(Address(callee, JitCode::offsetOfCode()), callee); + masm.jump(&rejoinBeforeCall); + } + if (oolConvert.used()) { masm.bind(&oolConvert); masm.setFramePushed(nativeFramePushed); From 1adde8c8d3135c5d48ad571332ff1f2ac3699fda Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Mon, 9 Oct 2017 11:50:08 +0200 Subject: [PATCH 10/55] Backed out changeset 0b1a22a4c03c (bug 1389561) for often asserting mTemporaryStorageInitialized at dom/quota/ActorsParent.cpp:3936 and crashing on Android. r=backout on a CLOSED TREE --HG-- extra : amend_source : 32be53f42cf7c4c0fc95316eafd40b0d7a9db47b --- dom/quota/ActorsParent.cpp | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 94820e2e2b1a..38beaa13030e 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -3830,13 +3830,6 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); -#if defined(NIGHTLY_BUILD) - { - MutexAutoLock autoLock(mQuotaMutex); - MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized); - } -#endif - if (aFileSizeOut) { *aFileSizeOut = 0; } @@ -3930,13 +3923,6 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType, { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); -#if defined(NIGHTLY_BUILD) - { - MutexAutoLock autoLock(mQuotaMutex); - MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized); - } -#endif - if (aFileSizeOut) { *aFileSizeOut = 0; } @@ -5256,14 +5242,7 @@ QuotaManager::EnsureOriginIsInitializedInternal( NS_ENSURE_SUCCESS(rv, rv); } -#if defined(NIGHTLY_BUILD) - { - MutexAutoLock autoLock(mQuotaMutex); mTemporaryStorageInitialized = true; - } -#else - mTemporaryStorageInitialized = true; -#endif CheckTemporaryStorageLimits(); } @@ -5349,16 +5328,7 @@ QuotaManager::ResetOrClearCompleted() AssertIsOnIOThread(); mInitializedOrigins.Clear(); - -#if defined(NIGHTLY_BUILD) - { - MutexAutoLock autoLock(mQuotaMutex); - mTemporaryStorageInitialized = false; - } -#else - mTemporaryStorageInitialized = false; -#endif - + mTemporaryStorageInitialized = false; mStorageInitialized = false; ReleaseIOThreadObjects(); From 7417b9b0d4140286cbf485b6ac010f7db95b940f Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Mon, 18 Sep 2017 12:04:42 +0100 Subject: [PATCH 11/55] Bug 1395138 - Hold reference to layers in ContainerLayerComposite::mPrepared. r=mattwoodrow MozReview-Commit-ID: 6qUDRnRcFAw --- gfx/layers/composite/ContainerLayerComposite.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 4b81dc7b546b..b0c60fa6bca6 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -166,12 +166,12 @@ static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer) /* all of the per-layer prepared data we need to maintain */ struct PreparedLayer { - PreparedLayer(LayerComposite *aLayer, + PreparedLayer(Layer *aLayer, RenderTargetIntRect aClipRect, Maybe&& aGeometry) : mLayer(aLayer), mClipRect(aClipRect), mGeometry(Move(aGeometry)) {} - LayerComposite* mLayer; + RefPtr mLayer; RenderTargetIntRect mClipRect; Maybe mGeometry; }; @@ -235,7 +235,8 @@ ContainerPrepare(ContainerT* aContainer, CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer()); layerToRender->Prepare(clipRect); - aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender, clipRect, + aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender->GetLayer(), + clipRect, Move(layer.geometry))); } @@ -413,7 +414,7 @@ RenderLayers(ContainerT* aContainer, LayerManagerComposite* aManager, PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i]; const gfx::IntRect clipRect = preparedData.mClipRect.ToUnknownRect(); - LayerComposite* layerToRender = preparedData.mLayer; + LayerComposite* layerToRender = static_cast(preparedData.mLayer->ImplData()); const Maybe& childGeometry = preparedData.mGeometry; Layer* layer = layerToRender->GetLayer(); From 597f9d10214b67cc86efcee8f4889af31b827a59 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Mon, 9 Oct 2017 13:23:18 +0100 Subject: [PATCH 12/55] Bug 1404349 - Extend check from bug 1370497 to apply to marks with a specific Script property, as well as those with Script=Inherited. r=valentin --- netwerk/dns/nsIDNService.cpp | 5 ++++- netwerk/test/unit/test_idn_urls.js | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/netwerk/dns/nsIDNService.cpp b/netwerk/dns/nsIDNService.cpp index 9266a26f3eee..aad6d59f744a 100644 --- a/netwerk/dns/nsIDNService.cpp +++ b/netwerk/dns/nsIDNService.cpp @@ -780,7 +780,6 @@ bool nsIDNService::isLabelSafe(const nsAString &label) if (illegalScriptCombo(script, savedScript)) { return false; } - lastScript = script; } // Check for mixed numbering systems @@ -833,6 +832,10 @@ bool nsIDNService::isLabelSafe(const nsAString &label) } } + if (script != Script::COMMON && script != Script::INHERITED) { + lastScript = script; + } + // Simplified/Traditional Chinese check temporarily disabled -- bug 857481 #if 0 diff --git a/netwerk/test/unit/test_idn_urls.js b/netwerk/test/unit/test_idn_urls.js index f39a9650a13b..43f3a2f110a4 100644 --- a/netwerk/test/unit/test_idn_urls.js +++ b/netwerk/test/unit/test_idn_urls.js @@ -300,6 +300,9 @@ const testcases = [ ["goo\u0650gle", "xn--google-yri", false, false, false], // ...but Arabic diacritics are allowed on Arabic text ["العَرَبِي", "xn--mgbc0a5a6cxbzabt", false, true, true], + + // Hebrew diacritic also not allowed in Latin text (bug 1404349) + ["goo\u05b4gle", "xn--google-rvh", false, false, false], ]; const profiles = ["ASCII", "high", "moderate"]; From a966a4008f0fff072f2e57c57e415f074720b360 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Mon, 9 Oct 2017 08:42:51 -0400 Subject: [PATCH 13/55] Bug 1402426 - removing the requirement to sign addons from talos and run from source. reland as this was partially reverted in a mozreview rebase. r=me --- testing/talos/talos/ffsetup.py | 4 ---- testing/talos/talos/run_tests.py | 6 ------ 2 files changed, 10 deletions(-) diff --git a/testing/talos/talos/ffsetup.py b/testing/talos/talos/ffsetup.py index 51ad448557d7..fa3bf3d67592 100644 --- a/testing/talos/talos/ffsetup.py +++ b/testing/talos/talos/ffsetup.py @@ -93,10 +93,6 @@ class FFSetup(object): if self.test_config.get('extensions'): extensions.append(self.test_config['extensions']) - if self.browser_config['develop'] or \ - 'try' in str.lower(self.browser_config['branch_name']): - extensions = [os.path.dirname(i) for i in extensions] - # downloading a profile instead of using the empty one if self.test_config['profile'] is not None: path = heavy.download_profile(self.test_config['profile']) diff --git a/testing/talos/talos/run_tests.py b/testing/talos/talos/run_tests.py index d8dea605c2e7..38e3ffe62728 100755 --- a/testing/talos/talos/run_tests.py +++ b/testing/talos/talos/run_tests.py @@ -118,12 +118,6 @@ def run_tests(config, browser_config): if browser_config['develop']: browser_config['extra_args'] = '--no-remote' - # with addon signing for production talos, we want to develop without it - if browser_config['develop'] or 'try' in str.lower(browser_config['branch_name']): - browser_config['preferences']['xpinstall.signatures.required'] = False - - browser_config['preferences']['extensions.allow-non-mpc-extensions'] = True - # if using firstNonBlankPaint, must turn on pref for it if test.get('fnbpaint', False): LOG.info("Using firstNonBlankPaint, so turning on pref for it") From 2c8e8eae56240da76a425f5b36de320ca0d26fe8 Mon Sep 17 00:00:00 2001 From: Kevin Chen Date: Thu, 5 Oct 2017 14:59:10 +0800 Subject: [PATCH 14/55] Bug 1401898 - Add root StackingContext for WebRenderCommandBuilder which prevents Webrender from treating the first StackingContext as page root and setting the wrong isolation mode; r=kats MozReview-Commit-ID: 5EBBgPpOGbv --- gfx/layers/wr/WebRenderCommandBuilder.cpp | 9 +++++-- layout/reftests/css-blending/reftest.list | 32 +++++++++++------------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp index 943c35625829..f32415dca34c 100644 --- a/gfx/layers/wr/WebRenderCommandBuilder.cpp +++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp @@ -46,8 +46,13 @@ WebRenderCommandBuilder::BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder mLastCanvasDatas.Clear(); mLastAsr = nullptr; - CreateWebRenderCommandsFromDisplayList(aDisplayList, aDisplayListBuilder, sc, - aBuilder, aResourceUpdates); + { + StackingContextHelper pageRootSc(sc, aBuilder, aDisplayListBuilder, + nullptr, aDisplayList, nullptr, 0, + nullptr, nullptr); + CreateWebRenderCommandsFromDisplayList(aDisplayList, aDisplayListBuilder, + pageRootSc, aBuilder, aResourceUpdates); + } // Make a "root" layer data that has everything else as descendants mLayerScrollData.emplace_back(); diff --git a/layout/reftests/css-blending/reftest.list b/layout/reftests/css-blending/reftest.list index aea8059fbf12..4f6090b0d189 100644 --- a/layout/reftests/css-blending/reftest.list +++ b/layout/reftests/css-blending/reftest.list @@ -2,9 +2,9 @@ pref(layout.css.mix-blend-mode.enabled,true) == blend-canvas.html blend-canvas-r pref(layout.css.mix-blend-mode.enabled,true) == blend-constant-background-color.html blend-constant-background-color-ref.html pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender,1-1,7875-7875) == blend-gradient-background-color.html blend-gradient-background-color-ref.html pref(layout.css.mix-blend-mode.enabled,true) == blend-image.html blend-image-ref.html -pref(layout.css.mix-blend-mode.enabled,true) fails-if(webrender) == blend-difference-stacking.html blend-difference-stacking-ref.html +pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html -fuzzy-if(skiaContent,1,30000) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-alpha.html background-blending-alpha-ref.html +fuzzy-if(skiaContent,1,30000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-alpha.html background-blending-alpha-ref.html pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,1-1,7875-7875) == background-blending-gradient-color.html background-blending-gradient-color-ref.html fuzzy-if(azureSkiaGL,3,7597) fuzzy-if(cocoaWidget,3,7597) fuzzy-if(d2d,1,3800) fuzzy-if(d3d11,1,4200) fuzzy-if(skiaContent,2,9450) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html fuzzy-if(azureSkiaGL,2,7174) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-gradient-image.html background-blending-gradient-color-ref.html @@ -12,21 +12,21 @@ fuzzy-if(azureSkia||d2d||gtkWidget,1,10000) pref(layout.css.background-blend-mod pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-png.html background-blending-image-color-ref.html pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg.html background-blending-image-color-ref.html fuzzy-if(azureSkiaGL,2,7174) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-image-gradient.html background-blending-gradient-color-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-image-image.html background-blending-image-color-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-isolation.html background-blending-isolation-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-image.html background-blending-image-color-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation.html background-blending-isolation-ref.html pref(layout.css.background-blend-mode.enabled,true) == background-blending-list-repeat.html background-blending-list-repeat-ref.html pref(layout.css.background-blend-mode.enabled,true) == background-blending-multiple-images.html background-blending-multiple-images-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-color-burn.html background-blending-color-burn-ref.svg -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-color-dodge.html background-blending-color-dodge-ref.svg +pref(layout.css.background-blend-mode.enabled,true) == background-blending-color-burn.html background-blending-color-burn-ref.svg +pref(layout.css.background-blend-mode.enabled,true) == background-blending-color-dodge.html background-blending-color-dodge-ref.svg # need to investigate why these tests are fuzzy - first suspect is a possible color space conversion on some platforms; same for mix-blend-mode tests fuzzy-if(azureSkia||gtkWidget,2,9600) fuzzy-if(d2d,1,8000) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-color.html background-blending-color-ref.svg pref(layout.css.background-blend-mode.enabled,true) == background-blending-darken.html background-blending-darken-ref.svg -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-difference.html background-blending-difference-ref.svg -fuzzy-if(skiaContent,1,1600) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-exclusion.html background-blending-exclusion-ref.svg -fuzzy-if(cocoaWidget||d2d,1,1600) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-hard-light.html background-blending-hard-light-ref.svg +pref(layout.css.background-blend-mode.enabled,true) == background-blending-difference.html background-blending-difference-ref.svg +fuzzy-if(skiaContent,1,1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-exclusion.html background-blending-exclusion-ref.svg +fuzzy-if(cocoaWidget||d2d,1,1600) pref(layout.css.background-blend-mode.enabled,true) == background-blending-hard-light.html background-blending-hard-light-ref.svg fuzzy-if(d2d,1,9600) fuzzy-if(azureSkia||gtkWidget,2,9600) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-hue.html background-blending-hue-ref.svg -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-lighten.html background-blending-lighten-ref.svg +pref(layout.css.background-blend-mode.enabled,true) == background-blending-lighten.html background-blending-lighten-ref.svg fuzzy-if(d2d,1,8000) fuzzy-if(azureSkia||gtkWidget,2,9600) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-luminosity.html background-blending-luminosity-ref.svg pref(layout.css.background-blend-mode.enabled,true) == background-blending-multiply.html background-blending-multiply-ref.svg pref(layout.css.background-blend-mode.enabled,true) == background-blending-normal.html background-blending-normal-ref.svg @@ -60,7 +60,7 @@ pref(layout.css.background-blend-mode.enabled,true) == background-blending-image # Test plan 5.3.2 Background layers do not blend with content outside the background (or behind the element) - tests 2 and 3 pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation-parent-child-color.html background-blending-isolation-parent-child-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-isolation-parent-child-image.html background-blending-isolation-parent-child-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blending-isolation-parent-child-image.html background-blending-isolation-parent-child-ref.html # Test plan 5.3.6 background-blend-mode for an element with background-position pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-position-percentage.html background-blending-background-position-percentage-ref.html @@ -85,16 +85,16 @@ pref(layout.css.background-blend-mode.enabled,true) == background-blending-backg # Test plan 5.3.11 background-blend-mode for an element with background-attachement pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-attachement-fixed.html background-blending-background-attachement-fixed-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html -fuzzy-if(Android,4,768) fuzzy-if(gtkWidget,1,132) fuzzy-if(skiaContent,1,800) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-image.html background-blend-mode-body-image-ref.html +fuzzy-if(Android,4,768) fuzzy-if(gtkWidget,1,132) fuzzy-if(skiaContent,1,800) pref(layout.css.background-blend-mode.enabled,true) == background-blend-mode-body-transparent-image.html background-blend-mode-body-transparent-image-ref.html -pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == background-blending-moz-element.html background-blending-moz-element-ref.html +pref(layout.css.background-blend-mode.enabled,true) == background-blending-moz-element.html background-blending-moz-element-ref.html fuzzy(1,40000) pref(layout.css.background-blend-mode.enabled,true) fails-if(webrender) == mix-blend-mode-soft-light.html mix-blend-mode-soft-light-ref.html # Test plan 4.4.2 element with isolation:isolate creates an isolated group for blended children -pref(layout.css.isolation.enabled,true) fails-if(webrender) == blend-isolation.html blend-isolation-ref.html +pref(layout.css.isolation.enabled,true) == blend-isolation.html blend-isolation-ref.html pref(layout.css.background-blend-mode.enabled,true) == bug1281593.html bug1281593-ref.html From 57ae515fa5846312e2a925137ed3365d148fd900 Mon Sep 17 00:00:00 2001 From: Kevin Chen Date: Fri, 6 Oct 2017 15:06:08 +0800 Subject: [PATCH 15/55] Bug 1406305 - Remove unused arguments in StackingContextHelper's constructor; r=kats MozReview-Commit-ID: 47owLOUhMBM --- gfx/layers/wr/StackingContextHelper.cpp | 5 +-- gfx/layers/wr/StackingContextHelper.h | 13 +++--- gfx/layers/wr/WebRenderCommandBuilder.cpp | 4 +- layout/painting/nsDisplayList.cpp | 50 +++++------------------ 4 files changed, 18 insertions(+), 54 deletions(-) diff --git a/gfx/layers/wr/StackingContextHelper.cpp b/gfx/layers/wr/StackingContextHelper.cpp index 5a404c784902..8396b2f1d5b3 100644 --- a/gfx/layers/wr/StackingContextHelper.cpp +++ b/gfx/layers/wr/StackingContextHelper.cpp @@ -20,15 +20,12 @@ StackingContextHelper::StackingContextHelper() StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC, wr::DisplayListBuilder& aBuilder, - nsDisplayListBuilder* aDisplayListBuilder, - nsDisplayItem* aItem, - nsDisplayList* aDisplayList, + const nsTArray& aFilters, const gfx::Matrix4x4* aBoundTransform, uint64_t aAnimationsId, float* aOpacityPtr, gfx::Matrix4x4* aTransformPtr, gfx::Matrix4x4* aPerspectivePtr, - const nsTArray& aFilters, const gfx::CompositionOp& aMixBlendMode, bool aBackfaceVisible) : mBuilder(&aBuilder) diff --git a/gfx/layers/wr/StackingContextHelper.h b/gfx/layers/wr/StackingContextHelper.h index 8d84d812fdd4..45f7734e4863 100644 --- a/gfx/layers/wr/StackingContextHelper.h +++ b/gfx/layers/wr/StackingContextHelper.h @@ -30,15 +30,12 @@ class MOZ_RAII StackingContextHelper public: StackingContextHelper(const StackingContextHelper& aParentSC, wr::DisplayListBuilder& aBuilder, - nsDisplayListBuilder* aDisplayListBuilder, - nsDisplayItem* aItem, - nsDisplayList* aDisplayList, - const gfx::Matrix4x4* aBoundTransform, - uint64_t aAnimationsId, - float* aOpacityPtr, - gfx::Matrix4x4* aTransformPtr, - gfx::Matrix4x4* aPerspectivePtr = nullptr, const nsTArray& aFilters = nsTArray(), + const gfx::Matrix4x4* aBoundTransform = nullptr, + uint64_t aAnimationsId = 0, + float* aOpacityPtr = nullptr, + gfx::Matrix4x4* aTransformPtr = nullptr, + gfx::Matrix4x4* aPerspectivePtr = nullptr, const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER, bool aBackfaceVisible = true); // This version of the constructor should only be used at the root level diff --git a/gfx/layers/wr/WebRenderCommandBuilder.cpp b/gfx/layers/wr/WebRenderCommandBuilder.cpp index f32415dca34c..8cc23bac0b5f 100644 --- a/gfx/layers/wr/WebRenderCommandBuilder.cpp +++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp @@ -47,9 +47,7 @@ WebRenderCommandBuilder::BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder mLastAsr = nullptr; { - StackingContextHelper pageRootSc(sc, aBuilder, aDisplayListBuilder, - nullptr, aDisplayList, nullptr, 0, - nullptr, nullptr); + StackingContextHelper pageRootSc(sc, aBuilder); CreateWebRenderCommandsFromDisplayList(aDisplayList, aDisplayListBuilder, pageRootSc, aBuilder, aResourceUpdates); } diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index bad1fdce3061..0608a8d45b40 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -6279,17 +6279,8 @@ nsDisplayOpacity::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuil } nsTArray filters; - StackingContextHelper sc(aSc, - aBuilder, - aDisplayListBuilder, - this, - &mList, - nullptr, - animationsId, - opacityForSC, - nullptr, - nullptr, - filters); + StackingContextHelper sc(aSc, aBuilder, filters, nullptr, animationsId, + opacityForSC); aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(&mList, aDisplayListBuilder, @@ -6341,9 +6332,8 @@ nsDisplayBlendMode::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBu nsDisplayListBuilder* aDisplayListBuilder) { nsTArray filters; - StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this, - &mList, nullptr, 0, nullptr, nullptr, nullptr, - filters, nsCSSRendering::GetGFXBlendMode(mBlendMode)); + StackingContextHelper sc(aSc, aBuilder, filters, nullptr, 0, nullptr, nullptr, + nullptr, nsCSSRendering::GetGFXBlendMode(mBlendMode)); return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,aResources, sc, aManager, aDisplayListBuilder); @@ -6471,8 +6461,7 @@ nsDisplayBlendContainer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder mozilla::layers::WebRenderLayerManager* aManager, nsDisplayListBuilder* aDisplayListBuilder) { - StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this, - &mList, nullptr, 0, nullptr, nullptr); + StackingContextHelper sc(aSc, aBuilder); return nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder); @@ -6578,8 +6567,8 @@ nsDisplayOwnLayer::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBui animationInfo.EnsureAnimationsId(); mWrAnimationId = animationInfo.GetCompositorAnimationsId(); - StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this, - &mList, nullptr, mWrAnimationId, nullptr, nullptr); + StackingContextHelper sc(aSc, aBuilder, nsTArray(), nullptr, + mWrAnimationId); nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder); @@ -7131,8 +7120,7 @@ nsDisplayStickyPosition::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder // adjusted origin and use that for the nested items. This way all the // ToRelativeLayoutRect calls on this StackingContextHelper object will // include the necessary adjustment. - StackingContextHelper sc(aSc, aBuilder, aDisplayListBuilder, this, - &mList, nullptr, 0, nullptr, nullptr); + StackingContextHelper sc(aSc, aBuilder); sc.AdjustOrigin(scTranslation); // TODO: if, inside this nested command builder, we try to turn a gecko clip @@ -8056,15 +8044,12 @@ nsDisplayTransform::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBu nsTArray filters; StackingContextHelper sc(aSc, aBuilder, - aDisplayListBuilder, - this, - mStoredList.GetChildren(), + filters, &newTransformMatrix, animationsId, nullptr, transformForSC, nullptr, - filters, gfx::CompositionOp::OP_OVER, !BackfaceIsHidden()); @@ -8670,15 +8655,12 @@ nsDisplayPerspective::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& a nsTArray filters; StackingContextHelper sc(aSc, aBuilder, - aDisplayListBuilder, - this, - mList.GetChildren(), + filters, nullptr, 0, nullptr, &transformForSC, &perspectiveMatrix, - filters, gfx::CompositionOp::OP_OVER, !BackfaceIsHidden()); @@ -9409,17 +9391,7 @@ nsDisplayFilter::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild wrFilters.AppendElement(wr::ToWrFilterOp(ToCSSFilter(filter))); } - StackingContextHelper sc(aSc, - aBuilder, - aDisplayListBuilder, - this, - &mList, - nullptr, - 0, - nullptr, - nullptr, - nullptr, - wrFilters); + StackingContextHelper sc(aSc, aBuilder, wrFilters); nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, sc, aManager, aDisplayListBuilder); return true; From b2711ec3e9015229ba254cb1a8184794e97fb203 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Thu, 28 Sep 2017 18:14:46 +0200 Subject: [PATCH 16/55] Bug 1339853 - Make XPathExpression/XPathEvaluator arguments optional. r=bz. --HG-- extra : rebase_source : 96d441625eaf8866aabcf255613c848921a194ae extra : source : 00dd493a0b55f871d33fc08f514d7ea6ac5b875a --- dom/webidl/XPathEvaluator.webidl | 10 +++-- dom/webidl/XPathExpression.webidl | 7 +++- .../meta/domxpath/interfaces.html.ini | 38 ------------------- 3 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 testing/web-platform/meta/domxpath/interfaces.html.ini diff --git a/dom/webidl/XPathEvaluator.webidl b/dom/webidl/XPathEvaluator.webidl index a74909f2abee..9e5cc75745d1 100644 --- a/dom/webidl/XPathEvaluator.webidl +++ b/dom/webidl/XPathEvaluator.webidl @@ -9,11 +9,13 @@ interface XPathEvaluator { // Based on nsIDOMXPathEvaluator [NewObject, Throws] XPathExpression createExpression(DOMString expression, - XPathNSResolver? resolver); + optional XPathNSResolver? resolver = null); [Pure] Node createNSResolver(Node nodeResolver); [Throws] - XPathResult evaluate(DOMString expression, Node contextNode, - XPathNSResolver? resolver, unsigned short type, - object? result); + XPathResult evaluate(DOMString expression, + Node contextNode, + optional XPathNSResolver? resolver = null, + optional unsigned short type = 0 /* XPathResult.ANY_TYPE */, + optional object? result = null); }; diff --git a/dom/webidl/XPathExpression.webidl b/dom/webidl/XPathExpression.webidl index dd5835492efe..90bc603f82e1 100644 --- a/dom/webidl/XPathExpression.webidl +++ b/dom/webidl/XPathExpression.webidl @@ -9,7 +9,9 @@ interface XPathExpression { // returned by this method. If this is specified as null or it's not an // XPathResult object, a new result object will be constructed and returned. [Throws] - XPathResult evaluate(Node contextNode, unsigned short type, object? result); + XPathResult evaluate(Node contextNode, + optional unsigned short type = 0 /* XPathResult.ANY_TYPE */, + optional object? result = null); // The result specifies a specific result object which may be reused and // returned by this method. If this is specified as null or it's not an @@ -18,5 +20,6 @@ interface XPathExpression { XPathResult evaluateWithContext(Node contextNode, unsigned long contextPosition, unsigned long contextSize, - unsigned short type, object? result); + optional unsigned short type = 0 /* XPathResult.ANY_TYPE */, + optional object? result = null); }; diff --git a/testing/web-platform/meta/domxpath/interfaces.html.ini b/testing/web-platform/meta/domxpath/interfaces.html.ini deleted file mode 100644 index 6eb64d8ddc48..000000000000 --- a/testing/web-platform/meta/domxpath/interfaces.html.ini +++ /dev/null @@ -1,38 +0,0 @@ -[interfaces.html] - type: testharness - [XPathEvaluator interface: operation createExpression(DOMString,XPathNSResolver)] - expected: FAIL - - [XPathEvaluator interface: operation evaluate(DOMString,Node,XPathNSResolver,unsigned short,object)] - expected: FAIL - - [XPathExpression interface: operation evaluate(Node,unsigned short,object)] - expected: FAIL - - [Document interface: operation createExpression(DOMString,XPathNSResolver)] - expected: FAIL - - [Document interface: operation evaluate(DOMString,Node,XPathNSResolver,unsigned short,object)] - expected: FAIL - - [Document must be primary interface of document] - expected: FAIL - - [Stringification of document] - expected: FAIL - - [XPathEvaluator interface: operation createExpression(DOMString, XPathNSResolver)] - expected: FAIL - - [XPathEvaluator interface: operation evaluate(DOMString, Node, XPathNSResolver, unsigned short, object)] - expected: FAIL - - [XPathExpression interface: operation evaluate(Node, unsigned short, object)] - expected: FAIL - - [Document interface: operation createExpression(DOMString, XPathNSResolver)] - expected: FAIL - - [Document interface: operation evaluate(DOMString, Node, XPathNSResolver, unsigned short, object)] - expected: FAIL - From 3e4ac652e87fc335f64720e2324dc080edce7b57 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Oct 2017 10:39:38 -0400 Subject: [PATCH 17/55] Bug 1406440 - don't inline nsSMILNullType::Singleton(); r=dholbert Defining Singleton() in the declaration of nsSMILNullType implicitly sticks an "inline" on the function, which is not what we want: inlining it spreads around a lot of static initialization code. Providing an out-of-line definition is much better in terms of code size. --- dom/smil/nsSMILNullType.cpp | 7 +++++++ dom/smil/nsSMILNullType.h | 7 +------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dom/smil/nsSMILNullType.cpp b/dom/smil/nsSMILNullType.cpp index b51c135afe15..795a93df4b88 100644 --- a/dom/smil/nsSMILNullType.cpp +++ b/dom/smil/nsSMILNullType.cpp @@ -8,6 +8,13 @@ #include "nsSMILValue.h" #include "nsDebug.h" +/*static*/ nsSMILNullType* +nsSMILNullType::Singleton() +{ + static nsSMILNullType sSingleton; + return &sSingleton; +} + nsresult nsSMILNullType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const { diff --git a/dom/smil/nsSMILNullType.h b/dom/smil/nsSMILNullType.h index d21610ff410e..448312e4e07e 100644 --- a/dom/smil/nsSMILNullType.h +++ b/dom/smil/nsSMILNullType.h @@ -14,12 +14,7 @@ class nsSMILNullType : public nsISMILType { public: // Singleton for nsSMILValue objects to hold onto. - static nsSMILNullType* - Singleton() - { - static nsSMILNullType sSingleton; - return &sSingleton; - } + static nsSMILNullType* Singleton(); protected: // nsISMILType Methods From c322875b57ffddb55f3c728fa8397e921fa51fb7 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Oct 2017 10:39:38 -0400 Subject: [PATCH 18/55] Bug 1406441 - provide nsSMILCompositor with a move constructor, rather than a copy constructor; r=dholbert Using a copy constructor here means that reallocating hashtables containing nsSMILCompositor does a bunch of unnecessary work; we can use a move constructor to avoid a lot of that unnecessary work. --- dom/smil/nsSMILCompositor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/smil/nsSMILCompositor.h b/dom/smil/nsSMILCompositor.h index 0c780d54c73b..39d1ae7faec4 100644 --- a/dom/smil/nsSMILCompositor.h +++ b/dom/smil/nsSMILCompositor.h @@ -34,9 +34,9 @@ public: : mKey(*aKey), mForceCompositing(false) { } - nsSMILCompositor(const nsSMILCompositor& toCopy) - : mKey(toCopy.mKey), - mAnimationFunctions(toCopy.mAnimationFunctions), + nsSMILCompositor(nsSMILCompositor&& toMove) + : mKey(mozilla::Move(toMove.mKey)), + mAnimationFunctions(mozilla::Move(toMove.mAnimationFunctions)), mForceCompositing(false) { } ~nsSMILCompositor() { } From 26105ef609eeee32dd08851e55a08253b0618b5b Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Oct 2017 10:39:38 -0400 Subject: [PATCH 19/55] Bug 1406474 - provide gfxUserFontSet::Entry with a move constructor; r=heycam This change makes moving Entry around more efficient, and also copies the mAllowedFontSets member as a ride-along bonus fix. --- gfx/thebes/gfxUserFontSet.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 1c84ceb128d5..85ca0f3b392e 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -403,11 +403,12 @@ public: mPrivate(aKey->mPrivate) { } - Entry(const Entry& aOther) - : mURI(aOther.mURI), - mPrincipal(aOther.mPrincipal), - mFontEntry(aOther.mFontEntry), - mPrivate(aOther.mPrivate) + Entry(Entry&& aOther) + : mAllowedFontSets(mozilla::Move(mAllowedFontSets)), + mURI(mozilla::Move(aOther.mURI)), + mPrincipal(mozilla::Move(aOther.mPrincipal)), + mFontEntry(mozilla::Move(aOther.mFontEntry)), + mPrivate(mozilla::Move(aOther.mPrivate)) { } ~Entry() { } From 4438ffeabfcbebbbc104215423acbc62abeb6c48 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Oct 2017 10:39:38 -0400 Subject: [PATCH 20/55] Bug 1406486 - provide nsClientAuthRememberEntry/nsCertOverrideEntry with move constructors; r=keeler Move constructors are more appropriate for these classes, since the underlying hashtable code will be moving them around, not copying them. We can take this opportunity to fix a bug in nsClientAuthRememberEntry: it wasn't transferring the value of mEntryKey, which would have been disastrous if the underlying hash table was ever resized. --- security/manager/ssl/nsCertOverrideService.h | 7 ++++--- security/manager/ssl/nsClientAuthRemember.h | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h index 9f60aab37079..14a145e9a326 100644 --- a/security/manager/ssl/nsCertOverrideService.h +++ b/security/manager/ssl/nsCertOverrideService.h @@ -7,6 +7,7 @@ #ifndef nsCertOverrideService_h #define nsCertOverrideService_h +#include "mozilla/Move.h" #include "mozilla/Mutex.h" #include "mozilla/TypedEnumBits.h" #include "nsICertOverrideService.h" @@ -79,10 +80,10 @@ class nsCertOverrideEntry final : public PLDHashEntryHdr { } - nsCertOverrideEntry(const nsCertOverrideEntry& toCopy) + nsCertOverrideEntry(nsCertOverrideEntry&& toMove) + : mSettings(mozilla::Move(toMove.mSettings)) + , mHostWithPort(mozilla::Move(toMove.mHostWithPort)) { - mSettings = toCopy.mSettings; - mHostWithPort = toCopy.mHostWithPort; } ~nsCertOverrideEntry() diff --git a/security/manager/ssl/nsClientAuthRemember.h b/security/manager/ssl/nsClientAuthRemember.h index 08d7eac70747..f039a39eb5d0 100644 --- a/security/manager/ssl/nsClientAuthRemember.h +++ b/security/manager/ssl/nsClientAuthRemember.h @@ -7,6 +7,7 @@ #ifndef __NSCLIENTAUTHREMEMBER_H__ #define __NSCLIENTAUTHREMEMBER_H__ +#include "mozilla/Move.h" #include "mozilla/ReentrantMonitor.h" #include "nsTHashtable.h" #include "nsIObserver.h" @@ -62,9 +63,10 @@ class nsClientAuthRememberEntry final : public PLDHashEntryHdr { } - nsClientAuthRememberEntry(const nsClientAuthRememberEntry& aToCopy) + nsClientAuthRememberEntry(nsClientAuthRememberEntry&& aToMove) + : mSettings(mozilla::Move(aToMove.mSettings)) + , mEntryKey(mozilla::Move(aToMove.mEntryKey)) { - mSettings = aToCopy.mSettings; } ~nsClientAuthRememberEntry() From 92d68b33b698416ea5947a1ec772a5f897b227bd Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Oct 2017 10:39:38 -0400 Subject: [PATCH 21/55] Bug 1406485 - provide PermissionHashKey with a move constructor; r=ehsan --- extensions/cookie/nsPermissionManager.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/cookie/nsPermissionManager.h b/extensions/cookie/nsPermissionManager.h index 8d16d8ee21ef..6ea3b1c41df1 100644 --- a/extensions/cookie/nsPermissionManager.h +++ b/extensions/cookie/nsPermissionManager.h @@ -112,9 +112,9 @@ public: : nsRefPtrHashKey(aPermissionKey) {} - PermissionHashKey(const PermissionHashKey& toCopy) - : nsRefPtrHashKey(toCopy) - , mPermissions(toCopy.mPermissions) + PermissionHashKey(PermissionHashKey&& toCopy) + : nsRefPtrHashKey(mozilla::Move(toCopy)) + , mPermissions(mozilla::Move(toCopy.mPermissions)) {} bool KeyEquals(const PermissionKey* aKey) const From 07d42b1d97cac992bd576f59b8a478a6016829c4 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Mon, 9 Oct 2017 11:10:33 -0400 Subject: [PATCH 22/55] Bug 1243263 - Disable browser_notification_tab_switching.js for frequency failures. r=me, a=test-only --- browser/base/content/test/alerts/browser.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/base/content/test/alerts/browser.ini b/browser/base/content/test/alerts/browser.ini index ed9ee76161aa..fdd1b4d42454 100644 --- a/browser/base/content/test/alerts/browser.ini +++ b/browser/base/content/test/alerts/browser.ini @@ -11,3 +11,4 @@ skip-if = (os == 'win' && bits == 32) # Bug 1352791 [browser_notification_remove_permission.js] [browser_notification_replace.js] [browser_notification_tab_switching.js] +skip-if = os == "win" || os == "linux" # Bug 1243263 From 400ab2eb531a55075f0c6a79b28c303a2413209e Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Mon, 9 Oct 2017 11:10:33 -0400 Subject: [PATCH 23/55] Bug 1350189 - Disable browser/components/extensions/test/browser/test-oop-extensions/browser_ext_tabs_create.js for frequency failures. r=me, a=test-only --- browser/components/extensions/test/browser/browser-common.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini index 45a1fc604bf8..b9f10c3566e7 100644 --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -131,6 +131,7 @@ skip-if = !e10s || debug || asan [browser_ext_tabs_audio.js] [browser_ext_tabs_captureVisibleTab.js] [browser_ext_tabs_create.js] +skip-if = os == "linux" && debug && bits == 32 # Bug 1350189 [browser_ext_tabs_create_invalid_url.js] [browser_ext_tabs_detectLanguage.js] [browser_ext_tabs_discarded.js] From 8a10ffde65d1d7883efe01a391dc0c73f3011350 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Mon, 9 Oct 2017 11:10:34 -0400 Subject: [PATCH 24/55] Bug 1383577 - Disable font-face/reflow-sanity-delay-1-metrics.html on windows/debug for frequent failures. r=me, a=test-only --- layout/reftests/font-face/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list index 53086edfe328..d6c7e052435c 100644 --- a/layout/reftests/font-face/reftest.list +++ b/layout/reftests/font-face/reftest.list @@ -178,7 +178,7 @@ HTTP(..) == reflow-sanity-1.html reflow-sanity-1-data.html HTTP(..) == reflow-sanity-delay-1a.html reflow-sanity-1-ref.html HTTP(..) == reflow-sanity-delay-1b.html reflow-sanity-1-ref.html HTTP(..) == reflow-sanity-delay-1c.html reflow-sanity-1-ref.html -HTTP(..) == reflow-sanity-delay-1-metrics.html reflow-sanity-1-ref.html +skip-if(winWidget&&!isDebugBuild) HTTP(..) == reflow-sanity-delay-1-metrics.html reflow-sanity-1-ref.html # font-display skip-if(/^Linux\x20i686/.test(http.oscpu)) HTTP(..) == font-display-1.html font-display-1-ref.html # normal font load (~500ms) From fcf8cee97a00d5e66c750f6adb14302b3ee00294 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Mon, 9 Oct 2017 11:10:34 -0400 Subject: [PATCH 25/55] Bug 1395247 - copy speedometer into talos package. r=rwood --- python/mozbuild/mozbuild/action/test_archive.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/mozbuild/mozbuild/action/test_archive.py b/python/mozbuild/mozbuild/action/test_archive.py index 23041eadd860..ea3977e78614 100644 --- a/python/mozbuild/mozbuild/action/test_archive.py +++ b/python/mozbuild/mozbuild/action/test_archive.py @@ -370,6 +370,12 @@ ARCHIVE_FILES = { 'base': 'testing', 'pattern': 'talos/**', }, + { + 'source': buildconfig.topsrcdir, + 'base': 'third_party/speedometer', + 'pattern': '**', + 'dest': 'talos/talos/tests/speedometer/', + }, ], 'awsy': [ { From 79ec9daa80261956439c218dc626dbd6875f984a Mon Sep 17 00:00:00 2001 From: Dragan Mladjenovic Date: Mon, 9 Oct 2017 01:24:00 -0400 Subject: [PATCH 26/55] Bug 1406858 - [MIPS] Remove uses of ArgumentsRectifierReg. r=jandem --HG-- extra : amend_source : e5a069a5e90010a14611b7adc848402884e01f1e --- js/src/jit/mips32/Trampoline-mips32.cpp | 10 +++++----- js/src/jit/mips64/Trampoline-mips64.cpp | 8 ++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/js/src/jit/mips32/Trampoline-mips32.cpp b/js/src/jit/mips32/Trampoline-mips32.cpp index fce2fcdf3559..dbdb00a8b90a 100644 --- a/js/src/jit/mips32/Trampoline-mips32.cpp +++ b/js/src/jit/mips32/Trampoline-mips32.cpp @@ -427,21 +427,21 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut) MacroAssembler masm(cx); masm.pushReturnAddress(); - // ArgumentsRectifierReg contains the |nargs| pushed onto the current - // frame. Including |this|, there are (|nargs| + 1) arguments to copy. - MOZ_ASSERT(ArgumentsRectifierReg == s3); - Register numActArgsReg = t6; Register calleeTokenReg = t7; Register numArgsReg = t5; - // Copy number of actual arguments into numActArgsReg + // Load the number of actual arguments into numActArgsReg masm.loadPtr(Address(StackPointer, RectifierFrameLayout::offsetOfNumActualArgs()), numActArgsReg); // Load the number of |undefined|s to push into t1. masm.loadPtr(Address(StackPointer, RectifierFrameLayout::offsetOfCalleeToken()), calleeTokenReg); + + // Copy the number of actual arguments into s3. + masm.mov(numActArgsReg, s3); + masm.mov(calleeTokenReg, numArgsReg); masm.andPtr(Imm32(CalleeTokenMask), numArgsReg); masm.load16ZeroExtend(Address(numArgsReg, JSFunction::offsetOfNargs()), numArgsReg); diff --git a/js/src/jit/mips64/Trampoline-mips64.cpp b/js/src/jit/mips64/Trampoline-mips64.cpp index 1903b94a50f4..5a02c92eeda7 100644 --- a/js/src/jit/mips64/Trampoline-mips64.cpp +++ b/js/src/jit/mips64/Trampoline-mips64.cpp @@ -428,14 +428,10 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut) masm.pushReturnAddress(); // Caller: // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- sp - // '--- s3 ---' - - // ArgumentsRectifierReg contains the |nargs| pushed onto the current - // frame. Including |this|, there are (|nargs| + 1) arguments to copy. - MOZ_ASSERT(ArgumentsRectifierReg == s3); // Add |this|, in the counter of known arguments. - masm.addPtr(Imm32(1), ArgumentsRectifierReg); + masm.loadPtr(Address(StackPointer, RectifierFrameLayout::offsetOfNumActualArgs()), s3); + masm.addPtr(Imm32(1), s3); Register numActArgsReg = a6; Register calleeTokenReg = a7; From fb167c6fbf24bb2dff5a302d17e8708185e4c5f4 Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Mon, 9 Oct 2017 07:18:00 -0400 Subject: [PATCH 27/55] Bug 1406551 - Update the debugger frontend (10/6/2017). r=jdescottes --- devtools/client/debugger/new/README.mozilla | 11 + devtools/client/debugger/new/debugger.css | 55 +- devtools/client/debugger/new/debugger.js | 3686 +++++++++-------- devtools/client/debugger/new/parser-worker.js | 2431 +++++------ .../debugger/new/pretty-print-worker.js | 120 +- devtools/client/debugger/new/search-worker.js | 457 +- .../debugger/new/test/mochitest/browser.ini | 9 +- .../browser_dbg-expressions-error.js | 90 + .../new/test/mochitest/browser_dbg-reload.js | 29 + .../mochitest/browser_dbg-wasm-sourcemaps.js | 1 + .../examples/reload/code_reload_1.js | 3 + .../examples/reload/code_reload_2.js | 7 + .../mochitest/examples/reload/doc_reload.html | 15 + .../examples/reload/sjs_code_reload.sjs | 32 + .../debugger/new/test/mochitest/head.js | 2 +- .../client/locales/en-US/debugger.properties | 4 + devtools/client/preferences/debugger.js | 1 - 17 files changed, 3670 insertions(+), 3283 deletions(-) create mode 100644 devtools/client/debugger/new/README.mozilla create mode 100644 devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js create mode 100644 devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js create mode 100644 devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_1.js create mode 100644 devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_2.js create mode 100644 devtools/client/debugger/new/test/mochitest/examples/reload/doc_reload.html create mode 100644 devtools/client/debugger/new/test/mochitest/examples/reload/sjs_code_reload.sjs diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla new file mode 100644 index 000000000000..60157ebdf9b6 --- /dev/null +++ b/devtools/client/debugger/new/README.mozilla @@ -0,0 +1,11 @@ +This is the debugger.html project output. +See https://github.com/devtools-html/debugger.html + +Taken from upstream commit: 6a34276ba4e2e4f8dfb2123eb4e6795ae658486a + +Packages: +- babel-plugin-transform-es2015-modules-commonjs @6.26.0 +- babel-preset-react @6.24.1 +- react @15.6.2 +- react-dom @15.6.2 +- webpack @3.6.0 diff --git a/devtools/client/debugger/new/debugger.css b/devtools/client/debugger/new/debugger.css index 89e21eb636ab..8d30d289495c 100644 --- a/devtools/client/debugger/new/debugger.css +++ b/devtools/client/debugger/new/debugger.css @@ -412,7 +412,7 @@ body { .modal-wrapper { position: fixed; display: flex; - justify-content: center; + align-items: center; width: 100%; height: 100%; top: 0; @@ -423,7 +423,7 @@ body { .modal { top: 0; - height: 230px; + margin: auto; width: 500px; background-color: var(--theme-toolbar-background); transform: translateY(-250px); @@ -438,7 +438,7 @@ body { .modal.entered, .modal.exiting { - transform: translateY(30px); + transform: translateY(0px); } @media (max-width: 520px) { @@ -490,7 +490,6 @@ body { } .shortcuts-modal { - height: fit-content; width: 45%; } @@ -973,7 +972,7 @@ html .arrow.expanded svg { width: 15px; height: 15px; margin-right: 5px; - vertical-align: bottom; + vertical-align: sub; } .theme-dark .webpack { @@ -1428,6 +1427,7 @@ html[dir="rtl"] .managed-tree .tree .node > div { display: flex; overflow-x: hidden; overflow-y: auto; + padding-top: 11px; } .sources-list .managed-tree { @@ -1462,6 +1462,11 @@ html[dir="rtl"] .managed-tree .tree .node > div { display: inline-block; } +.sources-list .tree .node .no-arrow { + width: 10px; + display: inline-block; +} + .no-sources-message { font-size: 12px; color: var(--theme-comment-alt); @@ -1497,7 +1502,7 @@ html[dir="rtl"] .managed-tree .tree .node > div { position: relative; transition: all 0.25s ease; overflow: hidden; - padding: 6.5px; + padding: 8px 8px 7px 8px; margin-bottom: 0px; margin-top: -1px; cursor: default; @@ -2353,11 +2358,6 @@ html[dir="rtl"] .arrow svg, --theme-conditional-breakpoint-color: var(--theme-body-color); } -.paused .CodeMirror-line, -.paused .CodeMirror-linenumber { - opacity: 0.7; -} - /** * There's a known codemirror flex issue with chrome that this addresses. * BUG https://github.com/devtools-html/debugger.html/issues/63 @@ -2629,6 +2629,7 @@ html .breakpoints-list .breakpoint.paused { overflow-x: hidden; text-overflow: ellipsis; padding: 1px 0; + vertical-align: bottom; } .breakpoints-list .pause-indicator { @@ -3216,12 +3217,26 @@ html .command-bar > button:disabled { offset-inline-start: auto; } +.welcomebox .small-size-layout { + display: none; +} + +.welcomebox .normal-layout { + display: inline-block; +} + .shortcutKeys { text-align: right; float: left; font-family: Courier; } +.shortcutKey { + display: inline-block; + margin-right: 10px; + font-family: Courier; +} + .shortcutFunction { text-align: left; float: left; @@ -3231,6 +3246,24 @@ html .command-bar > button:disabled { html .welcomebox .toggle-button-end.collapsed { bottom: 1px; } + +@media (max-width: 430px) { + .welcomebox .small-size-layout { + display: inline-block; + } + + .welcomebox .normal-layout { + display: none; + } + + .shortcutFunction { + margin-left: 0; + } + + .shortcutKey { + display: block; + } +} .source-header { border-bottom: 1px solid var(--theme-splitter-color); width: 100%; diff --git a/devtools/client/debugger/new/debugger.js b/devtools/client/debugger/new/debugger.js index d620ebc6376c..6f56cce52cdd 100644 --- a/devtools/client/debugger/new/debugger.js +++ b/devtools/client/debugger/new/debugger.js @@ -1295,7 +1295,7 @@ exports.clearSearchResults = clearSearchResults; exports.searchSources = searchSources; exports.searchSource = searchSource; -var _search = __webpack_require__(1115); +var _search = __webpack_require__(1210); var _selectors = __webpack_require__(242); @@ -1541,14 +1541,18 @@ exports.addToTree = addToTree; var _utils = __webpack_require__(18); +var _treeOrder = __webpack_require__(1239); + var _getURL = __webpack_require__(24); -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function createNodeInTree(part, path, tree) { +function createNodeInTree(part, path, tree, index) { var node = (0, _utils.createNode)(part, path, []); + // we are modifying the tree - tree.contents = [].concat(_toConsumableArray(tree.contents), [node]); + var contents = tree.contents.slice(0); + contents.splice(index, 0, node); + tree.contents = contents; + return node; } @@ -1558,22 +1562,30 @@ function createNodeInTree(part, path, tree) { * 2. if it does not exist create it * 3. if it is a file, replace it with a directory */ -function findOrCreateNode(parts, subTree, path, part, index, url) { - var child = subTree.contents.find(c => c.name === part); + + +function findOrCreateNode(parts, subTree, path, part, index, url, debuggeeHost) { + var addedPartIsFile = (0, _utils.partIsFile)(index, parts, url); + + var _findNodeInContents = (0, _treeOrder.findNodeInContents)(subTree, (0, _treeOrder.createTreeNodeMatcher)(part, !addedPartIsFile, debuggeeHost)), + childFound = _findNodeInContents.found, + childIndex = _findNodeInContents.index; // we create and enter the new node - if (!child) { - return createNodeInTree(part, path, subTree); + + + if (!childFound) { + return createNodeInTree(part, path, subTree, childIndex); } // we found a path with the same name as the part. We need to determine // if this is the correct child, or if we have a naming conflict - var addedPartIsFile = (0, _utils.partIsFile)(index, parts, url); + var child = subTree.contents[childIndex]; var childIsFile = !(0, _utils.nodeHasChildren)(child); // if we have a naming conflict, we'll create a new node if (childIsFile && !addedPartIsFile || !childIsFile && addedPartIsFile) { - return createNodeInTree(part, path, subTree); + return createNodeInTree(part, path, subTree, childIndex); } // if there is no naming conflict, we can traverse into the child @@ -1584,7 +1596,7 @@ function findOrCreateNode(parts, subTree, path, part, index, url) { * walk the source tree to the final node for a given url, * adding new nodes along the way */ -function traverseTree(url, tree) { +function traverseTree(url, tree, debuggeeHost) { url.path = decodeURIComponent(url.path); var parts = url.path.split("/").filter(p => p !== ""); @@ -1593,7 +1605,8 @@ function traverseTree(url, tree) { var path = ""; return parts.reduce((subTree, part, index) => { path = `${path}/${part}`; - return findOrCreateNode(parts, subTree, path, part, index, url); + var debuggeeHostIfRoot = index === 0 ? debuggeeHost : null; + return findOrCreateNode(parts, subTree, path, part, index, url, debuggeeHostIfRoot); }, tree); } @@ -1610,18 +1623,26 @@ function addSourceToNode(node, url, source) { } var name = (0, _getURL.getFilenameFromPath)(url.path); - var existingNode = node.contents.find(childNode => childNode.name === name); + + var _findNodeInContents2 = (0, _treeOrder.findNodeInContents)(node, (0, _treeOrder.createTreeNodeMatcher)(name, false, null)), + childFound = _findNodeInContents2.found, + childIndex = _findNodeInContents2.index; // if we are readding an existing file in the node, overwrite the existing // file and return the node's contents - if (existingNode) { + + + if (childFound) { + var existingNode = node.contents[childIndex]; existingNode.contents = source; return node.contents; } // if this is a new file, add the new file; var newNode = (0, _utils.createNode)(name, source.get("url"), source); - return [].concat(_toConsumableArray(node.contents), [newNode]); + var contents = node.contents.slice(0); + contents.splice(childIndex, 0, newNode); + return contents; } /** @@ -1630,12 +1651,13 @@ function addSourceToNode(node, url, source) { */ function addToTree(tree, source, debuggeeUrl) { var url = (0, _getURL.getURL)(source.get("url"), debuggeeUrl); + var debuggeeHost = (0, _treeOrder.getDomain)(debuggeeUrl); if ((0, _utils.isInvalidUrl)(url, source)) { return; } - var finalNode = traverseTree(url, tree); + var finalNode = traverseTree(url, tree, debuggeeHost); finalNode.contents = addSourceToNode(finalNode, url, source); } @@ -5433,12 +5455,10 @@ module.exports = { /***/ (function(module, exports, __webpack_require__) { /** - * Copyright (c) 2014-2015, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2014-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ (function (global, factory) { @@ -11875,7 +11895,7 @@ module.exports = { var React = __webpack_require__(0); -__webpack_require__(851); +__webpack_require__(1221); var dom = React.DOM; var ImPropTypes = __webpack_require__(150); @@ -12302,7 +12322,7 @@ function combineReducers(reducers) { var React = __webpack_require__(0); -__webpack_require__(852); +__webpack_require__(1222); var dom = React.DOM; var classnames = __webpack_require__(175); @@ -12539,7 +12559,7 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! var React = __webpack_require__(0); var createElement = React.createElement; -__webpack_require__(853); +__webpack_require__(1223); var rocketSvg = __webpack_require__(1126); var InlineSVG = __webpack_require__(1205); @@ -13201,7 +13221,7 @@ module.exports = { * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ var classnames = __webpack_require__(175); -__webpack_require__(856); +__webpack_require__(1225); module.exports = function (className) { var root = document.createElement("div"); @@ -13448,9 +13468,7 @@ function log(_ref) { getState = _ref.getState; return next => action => { - var actionText = JSON.stringify(action, null, 2); - var truncatedActionText = `${actionText.slice(0, 1000)}...`; - console.log(`[DISPATCH ${action.type}]`, action, truncatedActionText); + console.log(`[DISPATCH ${action.type}]`, action); next(action); }; } @@ -13580,7 +13598,7 @@ exports.createPrettySource = createPrettySource; var _selectors = __webpack_require__(242); -var _prettyPrint = __webpack_require__(903); +var _prettyPrint = __webpack_require__(1213); var _pause = __webpack_require__(255); @@ -13874,7 +13892,6 @@ if (isDevelopment()) { pref("devtools.debugger.pause-on-exceptions", false); pref("devtools.debugger.ignore-caught-exceptions", false); pref("devtools.debugger.call-stack-visible", false); - pref("devtools.debugger.scopes-visible", false); pref("devtools.debugger.start-panel-collapsed", false); pref("devtools.debugger.end-panel-collapsed", false); pref("devtools.debugger.tabs", "[]"); @@ -13897,7 +13914,6 @@ const prefs = new PrefsHelper("devtools", { pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"], ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"], callStackVisible: ["Bool", "debugger.call-stack-visible"], - scopesVisible: ["Bool", "debugger.scopes-visible"], startPanelCollapsed: ["Bool", "debugger.start-panel-collapsed"], endPanelCollapsed: ["Bool", "debugger.end-panel-collapsed"], frameworkGroupingOn: ["Bool", "debugger.ui.framework-grouping-on"], @@ -14590,7 +14606,7 @@ exports.default = update; Object.defineProperty(exports, "__esModule", { value: true }); -exports.isLoaded = exports.getMode = exports.getSourceLineCount = exports.getSourcePath = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.shouldPrettyPrint = exports.isThirdParty = exports.isPretty = exports.isJavaScript = undefined; +exports.isLoaded = exports.getMode = exports.getSourceLineCount = exports.getSourcePath = exports.getFileURL = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.shouldPrettyPrint = exports.isThirdParty = exports.isPretty = exports.isJavaScript = undefined; var _devtoolsSourceMap = __webpack_require__(898); @@ -14689,12 +14705,23 @@ function getRawSourceURL(url) { return url.replace(/:formatted$/, ""); } -function getFilenameFromURL(url) { +function resolveFileURL(url) { + var transformUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : initialUrl => initialUrl; + url = getRawSourceURL(url || ""); - var name = (0, _path.basename)(url) || "(index)"; + var name = transformUrl(url); return (0, _utils.endTruncateStr)(name, 50); } +function getFilenameFromURL(url) { + return resolveFileURL(url, initialUrl => (0, _path.basename)(initialUrl) || "(index)"); +} + +function getFormattedSourceId(id) { + var sourceId = id.split("/")[1]; + return `SOURCE${sourceId}`; +} + /** * Show a source url's filename. * If the source does not have a url, use the source id. @@ -14707,13 +14734,30 @@ function getFilename(source) { id = source.id; if (!url) { - var sourceId = id.split("/")[1]; - return `SOURCE${sourceId}`; + return getFormattedSourceId(id); } return getFilenameFromURL(url); } +/** + * Show a source url. + * If the source does not have a url, use the source id. + * + * @memberof utils/source + * @static + */ +function getFileURL(source) { + var url = source.url, + id = source.id; + + if (!url) { + return getFormattedSourceId(id); + } + + return resolveFileURL(url); +} + var contentTypeModeMap = { "text/javascript": { name: "javascript" }, "text/typescript": { name: "javascript", typescript: true }, @@ -14825,6 +14869,7 @@ exports.getPrettySourceURL = getPrettySourceURL; exports.getRawSourceURL = getRawSourceURL; exports.getFilename = getFilename; exports.getFilenameFromURL = getFilenameFromURL; +exports.getFileURL = getFileURL; exports.getSourcePath = getSourcePath; exports.getSourceLineCount = getSourceLineCount; exports.getMode = getMode; @@ -15339,6 +15384,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument exports.isStepping = isStepping; exports.isPaused = isPaused; exports.isEvaluatingExpression = isEvaluatingExpression; +exports.pausedInEval = pausedInEval; exports.getLoadedObject = getLoadedObject; exports.getObjectProperties = getObjectProperties; exports.getIsWaitingOnBreak = getIsWaitingOnBreak; @@ -15521,6 +15567,19 @@ function isEvaluatingExpression(state) { return state.pause.command === "expression"; } +function pausedInEval(state) { + if (!state.pause.pause) { + return false; + } + + var exception = state.pause.pause.why.exception; + if (!exception) { + return false; + } + + return exception.preview.fileName === "debugger eval code"; +} + function getLoadedObject(state, objectId) { return getLoadedObjects(state)[objectId]; } @@ -15846,6 +15905,8 @@ exports.default = update; "use strict"; +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + var _expressions = __webpack_require__(228); var expressions = _interopRequireWildcard(_expressions); @@ -15922,7 +15983,7 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; * @param object - location */ -module.exports = Object.assign({}, expressions, sources, pause, debuggee, breakpoints, pendingBreakpoints, eventListeners, ui, ast, coverage, projectTextSearch, sourceSearch, sourceTree, { +module.exports = _extends({}, expressions, sources, pause, debuggee, breakpoints, pendingBreakpoints, eventListeners, ui, ast, coverage, projectTextSearch, sourceSearch, sourceTree, { getBreakpointAtLocation: _breakpointAtLocation2.default, getInScopeLines: _linesInScope2.default, getVisibleBreakpoints: _visibleBreakpoints2.default, @@ -15940,6 +16001,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -15962,13 +16027,13 @@ var _ui = __webpack_require__(1128); var _devtoolsModules = __webpack_require__(830); -__webpack_require__(857); +__webpack_require__(1228); -__webpack_require__(858); +__webpack_require__(1229); -__webpack_require__(859); +__webpack_require__(1230); -__webpack_require__(860); +__webpack_require__(1231); var _devtoolsSplitter = __webpack_require__(910); @@ -16030,6 +16095,7 @@ class App extends _react.Component { this.renderEditorPane = this.renderEditorPane.bind(this); this.renderVerticalLayout = this.renderVerticalLayout.bind(this); this.onEscape = this.onEscape.bind(this); + this.onCommandSlash = this.onCommandSlash.bind(this); } getChildContext() { @@ -16040,6 +16106,7 @@ class App extends _react.Component { verticalLayoutBreakpoint.addListener(this.onLayoutChange); shortcuts.on(L10N.getStr("symbolSearch.search.key2"), this.toggleSymbolModal); shortcuts.on("Escape", this.onEscape); + shortcuts.on("Cmd+/", this.onCommandSlash); } componentWillUnmount() { @@ -16060,6 +16127,10 @@ class App extends _react.Component { } } + onCommandSlash() { + this.toggleShortcutsModal(); + } + toggleSymbolModal(_, e) { var _props2 = this.props, selectedSource = _props2.selectedSource, @@ -16236,7 +16307,7 @@ class App extends _react.Component { } } -App.childContextTypes = { shortcuts: _react.PropTypes.object }; +App.childContextTypes = { shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => ({ selectedSource: (0, _selectors.getSelectedSource)(state), @@ -17195,9 +17266,11 @@ exports.evaluateExpressions = evaluateExpressions; var _selectors = __webpack_require__(242); +var _promise = __webpack_require__(193); + var _expressions = __webpack_require__(1177); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var parser = _interopRequireWildcard(_parser); @@ -17318,13 +17391,19 @@ function evaluateExpression(expression) { } var error = yield parser.hasSyntaxError(expression.input); - var frameId = (0, _selectors.getSelectedFrameId)(getState()); - var value = error ? { input: expression.input, result: error } : yield client.evaluate((0, _expressions.wrapExpression)(expression.input), { frameId }); + if (error) { + return dispatch({ + type: "EVALUATE_EXPRESSION", + input: expression.input, + value: { input: expression.input, result: error } + }); + } + var frameId = (0, _selectors.getSelectedFrameId)(getState()); return dispatch({ type: "EVALUATE_EXPRESSION", input: expression.input, - value + [_promise.PROMISE]: client.evaluate((0, _expressions.wrapExpression)(expression.input), { frameId }) }); }); @@ -17574,6 +17653,7 @@ var checkPendingBreakpoint = (() => { var sameSource = sourceUrl && sourceUrl === source.url; if (sameSource) { + yield dispatch((0, _loadSourceText.loadSourceText)(source)); yield dispatch((0, _breakpoints.syncBreakpoint)(source.id, pendingBreakpoint)); } }); @@ -17650,7 +17730,7 @@ var _editor = __webpack_require__(257); var _sourceMaps = __webpack_require__(797); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var parser = _interopRequireWildcard(_parser); @@ -18132,7 +18212,7 @@ exports.getPauseReason = getPauseReason; var _lodash = __webpack_require__(2); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } @@ -18420,7 +18500,7 @@ module.exports = escapeRegExp; Object.defineProperty(exports, "__esModule", { value: true }); -exports.showSourceText = exports.updateDocument = exports.updateLineNumberFormat = exports.resetLineNumberFormat = exports.clearDocuments = exports.removeDocument = exports.setDocument = exports.getDocument = undefined; +exports.showLoading = exports.showSourceText = exports.updateDocument = exports.updateLineNumberFormat = exports.resetLineNumberFormat = exports.clearDocuments = exports.removeDocument = exports.setDocument = exports.getDocument = undefined; var _source = __webpack_require__(233); @@ -18469,12 +18549,25 @@ function updateDocument(editor, sourceId) { if (!sourceId) { return; } + var doc = getDocument(sourceId) || editor.createDocument(); editor.replaceDocument(doc); updateLineNumberFormat(editor, sourceId); } +function showLoading(editor) { + if (getDocument("loading")) { + return; + } + + var doc = editor.createDocument(); + setDocument("loading", doc); + editor.replaceDocument(doc); + editor.setText(L10N.getStr("loadingText")); + editor.setMode({ name: "text" }); +} + function setEditorText(editor, source) { var text = source.text, sourceId = source.id; @@ -18526,6 +18619,7 @@ exports.resetLineNumberFormat = resetLineNumberFormat; exports.updateLineNumberFormat = updateLineNumberFormat; exports.updateDocument = updateDocument; exports.showSourceText = showSourceText; +exports.showLoading = showLoading; /***/ }), /* 261 */ @@ -18539,7 +18633,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.getMatchIndex = exports.removeOverlay = exports.findPrev = exports.findNext = exports.find = exports.buildQuery = undefined; -var _buildQuery = __webpack_require__(1138); +var _buildQuery = __webpack_require__(1211); var _buildQuery2 = _interopRequireDefault(_buildQuery); @@ -18935,8 +19029,6 @@ var _utils = __webpack_require__(18); var _collapseTree = __webpack_require__(41); -var _sortTree = __webpack_require__(794); - var _addToTree = __webpack_require__(40); function createTree(sources, debuggeeUrl) { @@ -18945,7 +19037,7 @@ function createTree(sources, debuggeeUrl) { (0, _addToTree.addToTree)(uncollapsedTree, source, debuggeeUrl); } - var sourceTree = (0, _sortTree.sortEntireTree)((0, _collapseTree.collapseTree)(uncollapsedTree), debuggeeUrl); + var sourceTree = (0, _collapseTree.collapseTree)(uncollapsedTree); return { uncollapsedTree, @@ -18974,6 +19066,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -19016,8 +19112,8 @@ class ToggleSearch extends _react.Component { exports.default = ToggleSearch; ToggleSearch.propTypes = { - kind: _react.PropTypes.string.isRequired, - toggle: _react.PropTypes.func.isRequired + kind: _propTypes2.default.string.isRequired, + toggle: _propTypes2.default.func.isRequired }; /***/ }), @@ -19084,78 +19180,7 @@ module.exports = hasPath; /* 301 */, /* 302 */, /* 303 */, -/* 304 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(84), - isSymbol = __webpack_require__(72); - -/** Used as references for various `Number` constants. */ -var NAN = 0 / 0; - -/** Used to match leading and trailing whitespace. */ -var reTrim = /^\s+|\s+$/g; - -/** Used to detect bad signed hexadecimal string values. */ -var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - -/** Used to detect binary string values. */ -var reIsBinary = /^0b[01]+$/i; - -/** Used to detect octal string values. */ -var reIsOctal = /^0o[0-7]+$/i; - -/** Built-in method references without a dependency on `root`. */ -var freeParseInt = parseInt; - -/** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ -function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); -} - -module.exports = toNumber; - - -/***/ }), +/* 304 */, /* 305 */ /***/ (function(module, exports, __webpack_require__) { @@ -19407,6 +19432,11 @@ var _getScopeBindings = (() => { sourceMaps = _ref2.sourceMaps; var sourceId = generatedLocation.sourceId; + var sourceRecord = (0, _selectors.getSource)(getState(), sourceId); + if (sourceRecord.get("isWasm")) { + return scopes; + } + yield dispatch((0, _sources.ensureParserHasSourceText)(sourceId)); return yield (0, _pause.updateScopeBindings)(scopes, generatedLocation, sourceMaps); @@ -19458,7 +19488,7 @@ var _breakpoints = __webpack_require__(245); var _breakpoints2 = __webpack_require__(236); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var parser = _interopRequireWildcard(_parser); @@ -19480,12 +19510,14 @@ function resumed() { return; } + var wasPausedInEval = (0, _selectors.pausedInEval)(getState()); + dispatch({ type: "RESUME", value: undefined }); - if (!(0, _selectors.isStepping)(getState())) { + if (!(0, _selectors.isStepping)(getState()) && !wasPausedInEval) { dispatch((0, _expressions.evaluateExpressions)()); } }; @@ -19554,7 +19586,11 @@ function paused(pauseInfo) { if (hiddenBreakpointLocation) { dispatch((0, _breakpoints.removeBreakpoint)(hiddenBreakpointLocation)); } - dispatch((0, _expressions.evaluateExpressions)()); + + if (!(0, _selectors.isEvaluatingExpression)(getState())) { + dispatch((0, _expressions.evaluateExpressions)()); + } + dispatch((0, _sources.selectSource)(frame.location.sourceId, { line: frame.location.line })); }); @@ -19818,7 +19854,7 @@ var _utils = __webpack_require__(234); var _sources2 = __webpack_require__(254); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var _wasm = __webpack_require__(23); @@ -20113,6 +20149,10 @@ Object.defineProperty(exports, "__esModule", { exports.Modal = undefined; exports.default = Slide; +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -20125,20 +20165,17 @@ var _Transition = __webpack_require__(333); var _Transition2 = _interopRequireDefault(_Transition); -__webpack_require__(952); +__webpack_require__(1226); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class Modal extends _react.Component { + constructor() { + var _temp; - constructor(props) { - super(props); - var self = this; - self.onClick = this.onClick.bind(this); - } - - onClick(e) { - e.stopPropagation(); + return _temp = super(...arguments), this.onClick = e => { + e.stopPropagation(); + }, _temp; } render() { @@ -20162,7 +20199,7 @@ class Modal extends _react.Component { exports.Modal = Modal; Modal.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; function Slide(_ref) { @@ -21593,7 +21630,7 @@ var _classnames2 = _interopRequireDefault(_classnames); var _resultList = __webpack_require__(343); -__webpack_require__(867); +__webpack_require__(1240); var _SearchInput = __webpack_require__(377); @@ -21825,7 +21862,7 @@ var _Svg = __webpack_require__(345); var _Svg2 = _interopRequireDefault(_Svg); -__webpack_require__(862); +__webpack_require__(1234); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -21874,6 +21911,7 @@ var svg = { pause: __webpack_require__(358), "pause-exceptions": __webpack_require__(359), plus: __webpack_require__(360), + preact: __webpack_require__(1233), prettyPrint: __webpack_require__(361), react: __webpack_require__(1000), "regex-match": __webpack_require__(362), @@ -22288,7 +22326,7 @@ var _Close = __webpack_require__(378); var _Close2 = _interopRequireDefault(_Close); -__webpack_require__(865); +__webpack_require__(1237); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -22432,7 +22470,7 @@ var _Svg = __webpack_require__(344); var _Svg2 = _interopRequireDefault(_Svg); -__webpack_require__(864); +__webpack_require__(1236); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -22476,7 +22514,7 @@ var _classnames = __webpack_require__(175); var _classnames2 = _interopRequireDefault(_classnames); -__webpack_require__(868); +__webpack_require__(1241); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -22633,7 +22671,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -__webpack_require__(863); +__webpack_require__(1235); var _devtoolsComponents = __webpack_require__(1007); @@ -22646,14 +22684,37 @@ class ManagedTree extends _react.Component { constructor(props) { super(); + this.setExpanded = (item, isExpanded) => { + var expanded = this.state.expanded; + var itemPath = this.props.getPath(item); + if (isExpanded) { + expanded.add(itemPath); + } else { + expanded.delete(itemPath); + } + this.setState({ expanded }); + + if (isExpanded && this.props.onExpand) { + this.props.onExpand(item, expanded); + } else if (!isExpanded && this.props.onCollapse) { + this.props.onCollapse(item, expanded); + } + }; + + this.focusItem = item => { + if (!this.props.disabledFocus && this.state.focusedItem !== item) { + this.setState({ focusedItem: item }); + + if (this.props.onFocus) { + this.props.onFocus(item); + } + } + }; + this.state = { expanded: props.expanded || new Set(), focusedItem: null }; - - var self = this; - self.setExpanded = this.setExpanded.bind(this); - self.focusItem = this.focusItem.bind(this); } componentWillReceiveProps(nextProps) { @@ -22672,23 +22733,6 @@ class ManagedTree extends _react.Component { } } - setExpanded(item, isExpanded) { - var expanded = this.state.expanded; - var itemPath = this.props.getPath(item); - if (isExpanded) { - expanded.add(itemPath); - } else { - expanded.delete(itemPath); - } - this.setState({ expanded }); - - if (isExpanded && this.props.onExpand) { - this.props.onExpand(item, expanded); - } else if (!isExpanded && this.props.onCollapse) { - this.props.onCollapse(item, expanded); - } - } - expandListItems(listItems) { var expanded = this.state.expanded; listItems.forEach(item => expanded.add(this.props.getPath(item))); @@ -22710,16 +22754,6 @@ class ManagedTree extends _react.Component { } } - focusItem(item) { - if (!this.props.disabledFocus && this.state.focusedItem !== item) { - this.setState({ focusedItem: item }); - - if (this.props.onFocus) { - this.props.onFocus(item); - } - } - } - render() { var _this = this; @@ -22757,8 +22791,6 @@ class ManagedTree extends _react.Component { } } -ManagedTree.propTypes = Object.assign({}, Tree.propTypes); - exports.default = ManagedTree; /***/ }), @@ -22804,6 +22836,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -22888,9 +22924,9 @@ var _EmptyLines2 = _interopRequireDefault(_EmptyLines); var _editor = __webpack_require__(257); -__webpack_require__(905); +__webpack_require__(1257); -__webpack_require__(906); +__webpack_require__(1258); var _devtoolsSourceEditor = __webpack_require__(994); @@ -22902,11 +22938,169 @@ var cssVars = { footerHeight: "var(--editor-footer-height)" }; + class Editor extends _react.PureComponent { constructor() { super(); + this.onToggleBreakpoint = (key, e) => { + e.preventDefault(); + var codeMirror = this.state.editor.codeMirror; + var selectedSource = this.props.selectedSource; + + var line = (0, _editor.getCursorLine)(codeMirror); + + if (!selectedSource) { + return; + } + + var sourceLine = (0, _editor.toSourceLine)(selectedSource.get("id"), line); + + if (e.shiftKey) { + this.toggleConditionalPanel(sourceLine); + } else { + this.props.toggleBreakpoint(sourceLine); + } + }; + + this.onEscape = (key, e) => { + if (!this.state.editor) { + return; + } + + var codeMirror = this.state.editor.codeMirror; + + if (codeMirror.listSelections().length > 1) { + codeMirror.execCommand("singleSelection"); + e.preventDefault(); + } + }; + + this.onSearchAgain = (_, e) => { + var _props = this.props, + query = _props.query, + searchModifiers = _props.searchModifiers; + var codeMirror = this.state.editor.editor.codeMirror; + + var ctx = { ed: this.state.editor, cm: codeMirror }; + + var direction = e.shiftKey ? "prev" : "next"; + (0, _editor.traverseResults)(e, ctx, query, direction, searchModifiers.toJS()); + }; + + this.onGutterClick = (cm, line, gutter, ev) => { + var _props2 = this.props, + selectedSource = _props2.selectedSource, + toggleBreakpoint = _props2.toggleBreakpoint, + addOrToggleDisabledBreakpoint = _props2.addOrToggleDisabledBreakpoint, + isEmptyLine = _props2.isEmptyLine, + continueToHere = _props2.continueToHere; + + // ignore right clicks in the gutter + + if (ev.ctrlKey && ev.button === 0 || ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) { + return; + } + + if (isEmptyLine(line)) { + return; + } + + if (this.isCbPanelOpen()) { + return this.closeConditionalPanel(); + } + + if (!selectedSource) { + return; + } + + if (gutter !== "CodeMirror-foldgutter") { + if (ev.altKey) { + continueToHere((0, _editor.toSourceLine)(selectedSource.get("id"), line)); + } else if (ev.shiftKey) { + addOrToggleDisabledBreakpoint((0, _editor.toSourceLine)(selectedSource.get("id"), line)); + } else { + toggleBreakpoint((0, _editor.toSourceLine)(selectedSource.get("id"), line)); + } + } + }; + + this.onGutterContextMenu = event => { + var _props3 = this.props, + selectedSource = _props3.selectedSource, + breakpoints = _props3.breakpoints, + toggleBreakpoint = _props3.toggleBreakpoint, + toggleDisabledBreakpoint = _props3.toggleDisabledBreakpoint, + isEmptyLine = _props3.isEmptyLine, + pauseData = _props3.pauseData, + continueToHere = _props3.continueToHere; + + + if (selectedSource && selectedSource.get("isBlackBoxed")) { + event.preventDefault(); + return; + } + + var sourceId = selectedSource ? selectedSource.get("id") : ""; + var line = (0, _editor.lineAtHeight)(this.state.editor, sourceId, event); + var breakpoint = breakpoints.find(bp => bp.location.line === line); + + if (isEmptyLine(line - 1)) { + return; + } + + (0, _GutterMenu2.default)({ + event, + line, + breakpoint, + toggleBreakpoint, + toggleDisabledBreakpoint, + pauseData, + continueToHere, + + showConditionalPanel: this.toggleConditionalPanel, + isCbPanelOpen: this.isCbPanelOpen(), + closeConditionalPanel: this.closeConditionalPanel + }); + }; + + this.toggleConditionalPanel = line => { + if (this.isCbPanelOpen()) { + return this.closeConditionalPanel(); + } + + var _props4 = this.props, + selectedLocation = _props4.selectedLocation, + setBreakpointCondition = _props4.setBreakpointCondition, + breakpoints = _props4.breakpoints; + + var sourceId = selectedLocation ? selectedLocation.sourceId : ""; + + var breakpoint = breakpoints.find(bp => bp.location.line === line); + var location = { sourceId, line }; + var condition = breakpoint ? breakpoint.condition : ""; + + var panel = (0, _ConditionalPanel.renderConditionalPanel)({ + condition, + setBreakpoint: value => setBreakpointCondition(location, { condition: value }), + closePanel: this.closeConditionalPanel + }); + + var editorLine = (0, _editor.toEditorLine)(sourceId, line); + this.cbPanel = this.state.editor.codeMirror.addLineWidget(editorLine, panel, { + coverGutter: true, + noHScroll: false + }); + this.cbPanel.node.querySelector("input").focus(); + }; + + this.closeConditionalPanel = () => { + this.props.toggleConditionalBreakpointPanel(null); + this.cbPanel.clear(); + this.cbPanel = null; + }; + this.cbPanel = null; this.pendingJumpLocation = null; this.lastJumpLine = null; @@ -22915,15 +23109,6 @@ class Editor extends _react.PureComponent { highlightedLineRange: null, editor: null }; - - var self = this; - self.closeConditionalPanel = this.closeConditionalPanel.bind(this); - self.onEscape = this.onEscape.bind(this); - self.onGutterClick = this.onGutterClick.bind(this); - self.onGutterContextMenu = this.onGutterContextMenu.bind(this); - self.onSearchAgain = this.onSearchAgain.bind(this); - self.onToggleBreakpoint = this.onToggleBreakpoint.bind(this); - self.toggleConditionalPanel = this.toggleConditionalPanel.bind(this); } componentWillReceiveProps(nextProps) { @@ -22990,9 +23175,9 @@ class Editor extends _react.PureComponent { this.cbPanel = null; var editor = this.setupEditor(); - var _props = this.props, - selectedSource = _props.selectedSource, - selectedLocation = _props.selectedLocation; + var _props5 = this.props, + selectedSource = _props5.selectedSource, + selectedLocation = _props5.selectedLocation; var shortcuts = this.context.shortcuts; @@ -23030,9 +23215,9 @@ class Editor extends _react.PureComponent { // This is in `componentDidUpdate` so helper functions can expect // `this.props` to be the current props. This lifecycle method is // responsible for updating the editor annotations. - var _props2 = this.props, - selectedLocation = _props2.selectedLocation, - selectedSource = _props2.selectedSource; + var _props6 = this.props, + selectedLocation = _props6.selectedLocation, + selectedSource = _props6.selectedSource; // If the location is different and a new line is requested, // update the pending jump line. Note that if jumping to a line in @@ -23059,26 +23244,6 @@ class Editor extends _react.PureComponent { } } - onToggleBreakpoint(key, e) { - e.preventDefault(); - var codeMirror = this.state.editor.codeMirror; - var selectedSource = this.props.selectedSource; - - var line = (0, _editor.getCursorLine)(codeMirror); - - if (!selectedSource) { - return; - } - - var sourceLine = (0, _editor.toSourceLine)(selectedSource.get("id"), line); - - if (e.shiftKey) { - this.toggleConditionalPanel(sourceLine); - } else { - this.props.toggleBreakpoint(sourceLine); - } - } - onKeyDown(e) { var codeMirror = this.state.editor.codeMirror; var key = e.key, @@ -23104,48 +23269,25 @@ class Editor extends _react.PureComponent { * split console. Restore it here, but preventDefault if and only if there * is a multiselection. */ - onEscape(key, e) { - if (!this.state.editor) { - return; - } - var codeMirror = this.state.editor.codeMirror; - - if (codeMirror.listSelections().length > 1) { - codeMirror.execCommand("singleSelection"); - e.preventDefault(); - } - } - - onSearchAgain(_, e) { - var _props3 = this.props, - query = _props3.query, - searchModifiers = _props3.searchModifiers; - var codeMirror = this.state.editor.editor.codeMirror; - - var ctx = { ed: this.state.editor, cm: codeMirror }; - - var direction = e.shiftKey ? "prev" : "next"; - (0, _editor.traverseResults)(e, ctx, query, direction, searchModifiers.toJS()); - } inSelectedFrameSource() { - var _props4 = this.props, - selectedLocation = _props4.selectedLocation, - selectedFrame = _props4.selectedFrame; + var _props7 = this.props, + selectedLocation = _props7.selectedLocation, + selectedFrame = _props7.selectedFrame; return selectedFrame && selectedLocation && selectedFrame.location.sourceId == selectedLocation.sourceId; } openMenu(event, editor) { - var _props5 = this.props, - selectedSource = _props5.selectedSource, - selectedLocation = _props5.selectedLocation, - showSource = _props5.showSource, - jumpToMappedLocation = _props5.jumpToMappedLocation, - addExpression = _props5.addExpression, - toggleBlackBox = _props5.toggleBlackBox, - getFunctionText = _props5.getFunctionText; + var _props8 = this.props, + selectedSource = _props8.selectedSource, + selectedLocation = _props8.selectedLocation, + showSource = _props8.showSource, + jumpToMappedLocation = _props8.jumpToMappedLocation, + addExpression = _props8.addExpression, + toggleBlackBox = _props8.toggleBlackBox, + getFunctionText = _props8.getFunctionText; return (0, _EditorMenu2.default)({ @@ -23162,86 +23304,10 @@ class Editor extends _react.PureComponent { }); } - onGutterClick(cm, line, gutter, ev) { - var _props6 = this.props, - selectedSource = _props6.selectedSource, - toggleBreakpoint = _props6.toggleBreakpoint, - addOrToggleDisabledBreakpoint = _props6.addOrToggleDisabledBreakpoint, - isEmptyLine = _props6.isEmptyLine, - continueToHere = _props6.continueToHere; - - // ignore right clicks in the gutter - - if (ev.ctrlKey && ev.button === 0 || ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) { - return; - } - - if (isEmptyLine(line)) { - return; - } - - if (this.isCbPanelOpen()) { - return this.closeConditionalPanel(); - } - - if (!selectedSource) { - return; - } - - if (gutter !== "CodeMirror-foldgutter") { - if (ev.altKey) { - continueToHere((0, _editor.toSourceLine)(selectedSource.get("id"), line)); - } else if (ev.shiftKey) { - addOrToggleDisabledBreakpoint((0, _editor.toSourceLine)(selectedSource.get("id"), line)); - } else { - toggleBreakpoint((0, _editor.toSourceLine)(selectedSource.get("id"), line)); - } - } - } - - onGutterContextMenu(event) { - var _props7 = this.props, - selectedSource = _props7.selectedSource, - breakpoints = _props7.breakpoints, - toggleBreakpoint = _props7.toggleBreakpoint, - toggleDisabledBreakpoint = _props7.toggleDisabledBreakpoint, - isEmptyLine = _props7.isEmptyLine, - pauseData = _props7.pauseData, - continueToHere = _props7.continueToHere; - - - if (selectedSource && selectedSource.get("isBlackBoxed")) { - event.preventDefault(); - return; - } - - var sourceId = selectedSource ? selectedSource.get("id") : ""; - var line = (0, _editor.lineAtHeight)(this.state.editor, sourceId, event); - var breakpoint = breakpoints.find(bp => bp.location.line === line); - - if (isEmptyLine(line - 1)) { - return; - } - - (0, _GutterMenu2.default)({ - event, - line, - breakpoint, - toggleBreakpoint, - toggleDisabledBreakpoint, - pauseData, - continueToHere, - - showConditionalPanel: this.toggleConditionalPanel, - isCbPanelOpen: this.isCbPanelOpen(), - closeConditionalPanel: this.closeConditionalPanel - }); - } - onClick(e) { - var _props8 = this.props, - selectedLocation = _props8.selectedLocation, - jumpToMappedLocation = _props8.jumpToMappedLocation; + var _props9 = this.props, + selectedLocation = _props9.selectedLocation, + jumpToMappedLocation = _props9.jumpToMappedLocation; if (e.metaKey && e.altKey) { @@ -23250,42 +23316,6 @@ class Editor extends _react.PureComponent { } } - toggleConditionalPanel(line) { - if (this.isCbPanelOpen()) { - return this.closeConditionalPanel(); - } - - var _props9 = this.props, - selectedLocation = _props9.selectedLocation, - setBreakpointCondition = _props9.setBreakpointCondition, - breakpoints = _props9.breakpoints; - - var sourceId = selectedLocation ? selectedLocation.sourceId : ""; - - var breakpoint = breakpoints.find(bp => bp.location.line === line); - var location = { sourceId, line }; - var condition = breakpoint ? breakpoint.condition : ""; - - var panel = (0, _ConditionalPanel.renderConditionalPanel)({ - condition, - setBreakpoint: value => setBreakpointCondition(location, { condition: value }), - closePanel: this.closeConditionalPanel - }); - - var editorLine = (0, _editor.toEditorLine)(sourceId, line); - this.cbPanel = this.state.editor.codeMirror.addLineWidget(editorLine, panel, { - coverGutter: true, - noHScroll: false - }); - this.cbPanel.node.querySelector("input").focus(); - } - - closeConditionalPanel() { - this.props.toggleConditionalBreakpointPanel(null); - this.cbPanel.clear(); - this.cbPanel = null; - } - isCbPanelOpen() { return !!this.cbPanel; } @@ -23348,7 +23378,7 @@ class Editor extends _react.PureComponent { } if (!(0, _source.isLoaded)(nextProps.selectedSource.toJS())) { - return this.showMessage(L10N.getStr("loadingText")); + return (0, _editor.showLoading)(this.state.editor); } if (nextProps.selectedSource.get("error")) { @@ -23365,9 +23395,6 @@ class Editor extends _react.PureComponent { return; } - this.state.editor.replaceDocument(this.state.editor.createDocument()); - this.state.editor.setText(msg); - this.state.editor.setMode({ name: "text" }); (0, _editor.resetLineNumberFormat)(this.state.editor); } @@ -23509,17 +23536,14 @@ class Editor extends _react.PureComponent { } render() { - var _props14 = this.props, - coverageOn = _props14.coverageOn, - pauseData = _props14.pauseData; + var coverageOn = this.props.coverageOn; return _react2.default.createElement( "div", { className: (0, _classnames2.default)("editor-wrapper", { - "coverage-on": coverageOn, - paused: !!pauseData && (0, _devtoolsConfig.isEnabled)("highlightScopeLines") + "coverage-on": coverageOn }) }, this.renderSearchBar(), @@ -23541,48 +23565,48 @@ class Editor extends _react.PureComponent { Editor.propTypes = { breakpoints: _reactImmutableProptypes2.default.map, - hitCount: _react.PropTypes.object, - selectedLocation: _react.PropTypes.object, + hitCount: _propTypes2.default.object, + selectedLocation: _propTypes2.default.object, selectedSource: _reactImmutableProptypes2.default.map, - highlightLineRange: _react.PropTypes.func, - clearHighlightLineRange: _react.PropTypes.func, - highlightedLineRange: _react.PropTypes.object, - searchOn: _react.PropTypes.bool, - addBreakpoint: _react.PropTypes.func.isRequired, - disableBreakpoint: _react.PropTypes.func.isRequired, - enableBreakpoint: _react.PropTypes.func.isRequired, - removeBreakpoint: _react.PropTypes.func.isRequired, - setBreakpointCondition: _react.PropTypes.func.isRequired, - selectSource: _react.PropTypes.func, - jumpToMappedLocation: _react.PropTypes.func, - toggleBlackBox: _react.PropTypes.func, - showSource: _react.PropTypes.func, - coverageOn: _react.PropTypes.bool, - pauseData: _react.PropTypes.object, - selectedFrame: _react.PropTypes.object, - addExpression: _react.PropTypes.func.isRequired, - horizontal: _react.PropTypes.bool, - query: _react.PropTypes.string.isRequired, + highlightLineRange: _propTypes2.default.func, + clearHighlightLineRange: _propTypes2.default.func, + highlightedLineRange: _propTypes2.default.object, + searchOn: _propTypes2.default.bool, + addBreakpoint: _propTypes2.default.func.isRequired, + disableBreakpoint: _propTypes2.default.func.isRequired, + enableBreakpoint: _propTypes2.default.func.isRequired, + removeBreakpoint: _propTypes2.default.func.isRequired, + setBreakpointCondition: _propTypes2.default.func.isRequired, + selectSource: _propTypes2.default.func, + jumpToMappedLocation: _propTypes2.default.func, + toggleBlackBox: _propTypes2.default.func, + showSource: _propTypes2.default.func, + coverageOn: _propTypes2.default.bool, + pauseData: _propTypes2.default.object, + selectedFrame: _propTypes2.default.object, + addExpression: _propTypes2.default.func.isRequired, + horizontal: _propTypes2.default.bool, + query: _propTypes2.default.string.isRequired, searchModifiers: _reactImmutableProptypes2.default.recordOf({ - caseSensitive: _react.PropTypes.bool.isRequired, - regexMatch: _react.PropTypes.bool.isRequired, - wholeWord: _react.PropTypes.bool.isRequired + caseSensitive: _propTypes2.default.bool.isRequired, + regexMatch: _propTypes2.default.bool.isRequired, + wholeWord: _propTypes2.default.bool.isRequired }).isRequired, - startPanelSize: _react.PropTypes.number, - endPanelSize: _react.PropTypes.number, - linesInScope: _react.PropTypes.array, - toggleBreakpoint: _react.PropTypes.func.isRequired, - addOrToggleDisabledBreakpoint: _react.PropTypes.func.isRequired, - toggleDisabledBreakpoint: _react.PropTypes.func.isRequired, - conditionalBreakpointPanel: _react.PropTypes.number, - toggleConditionalBreakpointPanel: _react.PropTypes.func.isRequired, - isEmptyLine: _react.PropTypes.func, - continueToHere: _react.PropTypes.func, - getFunctionText: _react.PropTypes.func + startPanelSize: _propTypes2.default.number, + endPanelSize: _propTypes2.default.number, + linesInScope: _propTypes2.default.array, + toggleBreakpoint: _propTypes2.default.func.isRequired, + addOrToggleDisabledBreakpoint: _propTypes2.default.func.isRequired, + toggleDisabledBreakpoint: _propTypes2.default.func.isRequired, + conditionalBreakpointPanel: _propTypes2.default.number, + toggleConditionalBreakpointPanel: _propTypes2.default.func.isRequired, + isEmptyLine: _propTypes2.default.func, + continueToHere: _propTypes2.default.func, + getFunctionText: _propTypes2.default.func }; Editor.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => { @@ -23653,7 +23677,7 @@ var _PaneToggle = __webpack_require__(428); var _PaneToggle2 = _interopRequireDefault(_PaneToggle); -__webpack_require__(875); +__webpack_require__(1248); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23832,7 +23856,7 @@ var _Svg = __webpack_require__(344); var _Svg2 = _interopRequireDefault(_Svg); -__webpack_require__(874); +__webpack_require__(1247); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23888,6 +23912,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -23910,7 +23938,7 @@ var _selectors = __webpack_require__(242); var _editor = __webpack_require__(257); -var _search = __webpack_require__(1115); +var _search = __webpack_require__(1210); var _resultList = __webpack_require__(343); @@ -23926,7 +23954,7 @@ var _SearchInput = __webpack_require__(377); var _SearchInput2 = _interopRequireDefault(_SearchInput); -__webpack_require__(876); +__webpack_require__(1249); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23947,28 +23975,249 @@ function getShortcuts() { class SearchBar extends _react.Component { constructor(props) { - super(props); + var _this; + + _this = super(props); + + this.onEscape = e => { + this.closeSearch(e); + }; + + this.clearSearch = () => { + var _props = this.props, + ed = _props.editor, + query = _props.query, + modifiers = _props.modifiers; + + if (ed && modifiers) { + var ctx = { ed, cm: ed.codeMirror }; + (0, _editor.removeOverlay)(ctx, query, modifiers.toJS()); + } + }; + + this.closeSearch = e => { + var _props2 = this.props, + editor = _props2.editor, + setFileSearchQuery = _props2.setFileSearchQuery, + searchOn = _props2.searchOn; + + + if (editor && searchOn) { + setFileSearchQuery(""); + this.clearSearch(); + this.props.setActiveSearch(); + this.props.clearHighlightLineRange(); + e.stopPropagation(); + e.preventDefault(); + } + }; + + this.toggleSearch = e => { + e.stopPropagation(); + e.preventDefault(); + var editor = this.props.editor; + + + if (!this.props.searchOn) { + this.props.setActiveSearch("file"); + } + + if (this.props.searchOn && editor) { + var selection = editor.codeMirror.getSelection(); + this.setSearchValue(selection); + if (selection !== "") { + this.doSearch(selection); + } + this.selectSearchInput(); + } + }; + + this.setSearchValue = value => { + var searchInput = this.searchInput(); + if (value == "" || !searchInput) { + return; + } + + searchInput.value = value; + }; + + this.selectSearchInput = () => { + var searchInput = this.searchInput(); + if (searchInput) { + searchInput.setSelectionRange(0, searchInput.value.length); + searchInput.focus(); + } + }; + + this.searchInput = () => { + var node = (0, _reactDom.findDOMNode)(this); + if (node instanceof HTMLElement) { + var input = node.querySelector("input"); + if (input instanceof HTMLInputElement) { + return input; + } + } + return null; + }; + + this.doSearch = query => { + var _props3 = this.props, + selectedSource = _props3.selectedSource, + setFileSearchQuery = _props3.setFileSearchQuery; + + if (!selectedSource || !selectedSource.get("text")) { + return; + } + + setFileSearchQuery(query); + + this.searchContents(query); + }; + + this.updateSearchResults = (characterIndex, line, matches) => { + var matchIndex = matches.findIndex(elm => elm.line === line && elm.ch === characterIndex); + this.props.updateSearchResults({ + matches, + matchIndex, + count: matches.length, + index: characterIndex + }); + }; + + this.searchContents = (() => { + var _ref = _asyncToGenerator(function* (query) { + var _props4 = _this.props, + selectedSource = _props4.selectedSource, + modifiers = _props4.modifiers, + ed = _props4.editor; + + + if (!query || !ed || !selectedSource || !selectedSource.get("text") || !modifiers) { + return; + } + + var ctx = { ed, cm: ed.codeMirror }; + + var _modifiers = modifiers.toJS(); + var matches = yield (0, _search.getMatches)(query, selectedSource.get("text"), _modifiers); + + var _find = (0, _editor.find)(ctx, query, true, _modifiers), + ch = _find.ch, + line = _find.line; + + _this.updateSearchResults(ch, line, matches); + }); + + return function (_x) { + return _ref.apply(this, arguments); + }; + })(); + + this.traverseResults = (e, rev) => { + e.stopPropagation(); + e.preventDefault(); + var ed = this.props.editor; + + if (!ed) { + return; + } + + var ctx = { ed, cm: ed.codeMirror }; + + var _props5 = this.props, + query = _props5.query, + modifiers = _props5.modifiers, + matches = _props5.searchResults.matches; + + + if (query === "") { + this.props.setActiveSearch("file"); + } + + if (modifiers) { + var matchedLocations = matches || []; + + var _ref2 = rev ? (0, _editor.findPrev)(ctx, query, true, modifiers.toJS()) : (0, _editor.findNext)(ctx, query, true, modifiers.toJS()), + ch = _ref2.ch, + line = _ref2.line; + + this.updateSearchResults(ch, line, matchedLocations); + } + }; + + this.onChange = e => { + return this.doSearch(e.target.value); + }; + + this.onKeyUp = e => { + if (e.key !== "Enter" && e.key !== "F3") { + return; + } + + this.traverseResults(e, e.shiftKey); + e.preventDefault(); + }; + + this.renderSearchModifiers = () => { + var _props6 = this.props, + modifiers = _props6.modifiers, + toggleFileSearchModifier = _props6.toggleFileSearchModifier; + + + function SearchModBtn(_ref3) { + var modVal = _ref3.modVal, + className = _ref3.className, + svgName = _ref3.svgName, + tooltip = _ref3.tooltip; + + var preppedClass = (0, _classnames2.default)(className, { + active: modifiers && modifiers.get(modVal) + }); + return _react2.default.createElement( + "button", + { + className: preppedClass, + onClick: () => toggleFileSearchModifier(modVal), + title: tooltip + }, + _react2.default.createElement(_Svg2.default, { name: svgName }) + ); + } + + return _react2.default.createElement( + "div", + { className: "search-modifiers" }, + _react2.default.createElement( + "span", + { className: "search-type-name" }, + L10N.getStr("symbolSearch.searchModifier.modifiersLabel") + ), + _react2.default.createElement(SearchModBtn, { + modVal: "regexMatch", + className: "regex-match-btn", + svgName: "regex-match", + tooltip: L10N.getStr("symbolSearch.searchModifier.regex") + }), + _react2.default.createElement(SearchModBtn, { + modVal: "caseSensitive", + className: "case-sensitive-btn", + svgName: "case-match", + tooltip: L10N.getStr("symbolSearch.searchModifier.caseSensitive") + }), + _react2.default.createElement(SearchModBtn, { + modVal: "wholeWord", + className: "whole-word-btn", + svgName: "whole-word-match", + tooltip: L10N.getStr("symbolSearch.searchModifier.wholeWord") + }) + ); + }; + this.state = { selectedResultIndex: 0, count: 0, index: -1 }; - - var self = this; - self.onEscape = this.onEscape.bind(this); - self.clearSearch = this.clearSearch.bind(this); - self.closeSearch = this.closeSearch.bind(this); - self.toggleSearch = this.toggleSearch.bind(this); - self.setSearchValue = this.setSearchValue.bind(this); - self.selectSearchInput = this.selectSearchInput.bind(this); - self.searchInput = this.searchInput.bind(this); - self.doSearch = this.doSearch.bind(this); - self.searchContents = this.searchContents.bind(this); - self.traverseResults = this.traverseResults.bind(this); - self.onChange = this.onChange.bind(this); - self.onKeyUp = this.onKeyUp.bind(this); - self.buildSummaryMsg = this.buildSummaryMsg.bind(this); - self.renderSearchModifiers = this.renderSearchModifiers.bind(this); } componentWillUnmount() { @@ -23988,7 +24237,6 @@ class SearchBar extends _react.Component { componentDidMount() { // overwrite searchContents with a debounced version to reduce the // frequency of queries which improves perf on large files - // $FlowIgnore this.searchContents = (0, _lodash.debounce)(this.searchContents, 100); var shortcuts = this.context.shortcuts; @@ -24018,192 +24266,16 @@ class SearchBar extends _react.Component { } } - onEscape(e) { - this.closeSearch(e); - } - - clearSearch() { - var _props = this.props, - ed = _props.editor, - query = _props.query, - modifiers = _props.modifiers; - - if (ed && modifiers) { - var ctx = { ed, cm: ed.codeMirror }; - (0, _editor.removeOverlay)(ctx, query, modifiers.toJS()); - } - } - - closeSearch(e) { - var _props2 = this.props, - editor = _props2.editor, - setFileSearchQuery = _props2.setFileSearchQuery, - searchOn = _props2.searchOn; - - - if (editor && searchOn) { - setFileSearchQuery(""); - this.clearSearch(); - this.props.setActiveSearch(); - this.props.clearHighlightLineRange(); - e.stopPropagation(); - e.preventDefault(); - } - } - - toggleSearch(e) { - e.stopPropagation(); - e.preventDefault(); - var editor = this.props.editor; - - - if (!this.props.searchOn) { - this.props.setActiveSearch("file"); - } - - if (this.props.searchOn && editor) { - var selection = editor.codeMirror.getSelection(); - this.setSearchValue(selection); - if (selection !== "") { - this.doSearch(selection); - } - this.selectSearchInput(); - } - } - - setSearchValue(value) { - var searchInput = this.searchInput(); - if (value == "" || !searchInput) { - return; - } - - searchInput.value = value; - } - - selectSearchInput() { - var searchInput = this.searchInput(); - if (searchInput) { - searchInput.setSelectionRange(0, searchInput.value.length); - searchInput.focus(); - } - } - - searchInput() { - var node = (0, _reactDom.findDOMNode)(this); - if (node instanceof HTMLElement) { - var input = node.querySelector("input"); - if (input instanceof HTMLInputElement) { - return input; - } - } - return null; - } - - doSearch(query) { - var _props3 = this.props, - selectedSource = _props3.selectedSource, - setFileSearchQuery = _props3.setFileSearchQuery; - - if (!selectedSource || !selectedSource.get("text")) { - return; - } - - setFileSearchQuery(query); - - this.searchContents(query); - } - - updateSearchResults(characterIndex, line, matches) { - var matchIndex = matches.findIndex(elm => elm.line === line && elm.ch === characterIndex); - this.props.updateSearchResults({ - matches, - matchIndex, - count: matches.length, - index: characterIndex - }); - } - - searchContents(query) { - var _this = this; - - return _asyncToGenerator(function* () { - var _props4 = _this.props, - selectedSource = _props4.selectedSource, - modifiers = _props4.modifiers, - ed = _props4.editor; - - - if (!query || !ed || !selectedSource || !selectedSource.get("text") || !modifiers) { - return; - } - - var ctx = { ed, cm: ed.codeMirror }; - - var _modifiers = modifiers.toJS(); - var matches = yield (0, _search.getMatches)(query, selectedSource.get("text"), _modifiers); - - var _find = (0, _editor.find)(ctx, query, true, _modifiers), - ch = _find.ch, - line = _find.line; - - _this.updateSearchResults(ch, line, matches); - })(); - } - - traverseResults(e, rev) { - e.stopPropagation(); - e.preventDefault(); - var ed = this.props.editor; - - if (!ed) { - return; - } - - var ctx = { ed, cm: ed.codeMirror }; - - var _props5 = this.props, - query = _props5.query, - modifiers = _props5.modifiers, - matches = _props5.searchResults.matches; - - - if (query === "") { - this.props.setActiveSearch("file"); - } - - if (modifiers) { - var matchedLocations = matches || []; - - var _ref = rev ? (0, _editor.findPrev)(ctx, query, true, modifiers.toJS()) : (0, _editor.findNext)(ctx, query, true, modifiers.toJS()), - ch = _ref.ch, - line = _ref.line; - - this.updateSearchResults(ch, line, matchedLocations); - } - } - // Handlers - onChange(e) { - return this.doSearch(e.target.value); - } - - onKeyUp(e) { - if (e.key !== "Enter" && e.key !== "F3") { - return; - } - - this.traverseResults(e, e.shiftKey); - e.preventDefault(); - } // Renderers buildSummaryMsg() { - var _props6 = this.props, - _props6$searchResults = _props6.searchResults, - matchIndex = _props6$searchResults.matchIndex, - count = _props6$searchResults.count, - index = _props6$searchResults.index, - query = _props6.query; + var _props7 = this.props, + _props7$searchResults = _props7.searchResults, + matchIndex = _props7$searchResults.matchIndex, + count = _props7$searchResults.count, + index = _props7$searchResults.index, + query = _props7.query; if (query.trim() == "") { @@ -24221,61 +24293,6 @@ class SearchBar extends _react.Component { return L10N.getFormatStr("editor.searchResults", matchIndex + 1, count); } - renderSearchModifiers() { - var _props7 = this.props, - modifiers = _props7.modifiers, - toggleFileSearchModifier = _props7.toggleFileSearchModifier; - - - function SearchModBtn(_ref2) { - var modVal = _ref2.modVal, - className = _ref2.className, - svgName = _ref2.svgName, - tooltip = _ref2.tooltip; - - var preppedClass = (0, _classnames2.default)(className, { - active: modifiers && modifiers.get(modVal) - }); - return _react2.default.createElement( - "button", - { - className: preppedClass, - onClick: () => toggleFileSearchModifier(modVal), - title: tooltip - }, - _react2.default.createElement(_Svg2.default, { name: svgName }) - ); - } - - return _react2.default.createElement( - "div", - { className: "search-modifiers" }, - _react2.default.createElement( - "span", - { className: "search-type-name" }, - L10N.getStr("symbolSearch.searchModifier.modifiersLabel") - ), - _react2.default.createElement(SearchModBtn, { - modVal: "regexMatch", - className: "regex-match-btn", - svgName: "regex-match", - tooltip: L10N.getStr("symbolSearch.searchModifier.regex") - }), - _react2.default.createElement(SearchModBtn, { - modVal: "caseSensitive", - className: "case-sensitive-btn", - svgName: "case-match", - tooltip: L10N.getStr("symbolSearch.searchModifier.caseSensitive") - }), - _react2.default.createElement(SearchModBtn, { - modVal: "wholeWord", - className: "whole-word-btn", - svgName: "whole-word-match", - tooltip: L10N.getStr("symbolSearch.searchModifier.wholeWord") - }) - ); - } - renderSearchType() { return _react2.default.createElement( "div", @@ -24327,7 +24344,7 @@ class SearchBar extends _react.Component { } SearchBar.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => { @@ -24557,229 +24574,8 @@ exports.default = (0, _reactRedux.connect)(state => { /* 648 */, /* 649 */, /* 650 */, -/* 651 */ -/***/ (function(module, exports, __webpack_require__) { - -var isObject = __webpack_require__(84), - now = __webpack_require__(652), - toNumber = __webpack_require__(304); - -/** Error message constants. */ -var FUNC_ERROR_TEXT = 'Expected a function'; - -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeMax = Math.max, - nativeMin = Math.min; - -/** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ -function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; - - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; -} - -module.exports = debounce; - - -/***/ }), -/* 652 */ -/***/ (function(module, exports, __webpack_require__) { - -var root = __webpack_require__(8); - -/** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ -var now = function() { - return root.Date.now(); -}; - -module.exports = now; - - -/***/ }), +/* 651 */, +/* 652 */, /* 653 */, /* 654 */, /* 655 */ @@ -25106,11 +24902,12 @@ var _BracketArrow = __webpack_require__(1029); var _BracketArrow2 = _interopRequireDefault(_BracketArrow); -__webpack_require__(880); +__webpack_require__(1253); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class Popover extends _react.Component { + constructor() { super(); this.onMouseLeave = this.onMouseLeave.bind(this); @@ -25271,14 +25068,6 @@ class Popover extends _react.Component { } } -Popover.propTypes = { - target: _react.PropTypes.object, - targetPosition: _react.PropTypes.object, - children: _react.PropTypes.object, - onMouseLeave: _react.PropTypes.func, - type: _react.PropTypes.string -}; - Popover.defaultProps = { onMouseLeave: () => {}, type: "popover" @@ -25322,7 +25111,7 @@ var _Close = __webpack_require__(378); var _Close2 = _interopRequireDefault(_Close); -__webpack_require__(873); +__webpack_require__(1246); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -25599,6 +25388,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -25669,7 +25462,7 @@ var _Scopes2 = __webpack_require__(731); var _Scopes3 = _interopRequireDefault(_Scopes2); -__webpack_require__(921); +__webpack_require__(1267); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -25853,18 +25646,18 @@ class SecondaryPanes extends _react.Component { } SecondaryPanes.propTypes = { - evaluateExpressions: _react.PropTypes.func.isRequired, - pauseData: _react.PropTypes.object, - horizontal: _react.PropTypes.bool, + evaluateExpressions: _propTypes2.default.func.isRequired, + pauseData: _propTypes2.default.object, + horizontal: _propTypes2.default.bool, breakpoints: _reactImmutableProptypes2.default.map.isRequired, - breakpointsDisabled: _react.PropTypes.bool, - breakpointsLoading: _react.PropTypes.bool, - toggleAllBreakpoints: _react.PropTypes.func.isRequired, - toggleShortcutsModal: _react.PropTypes.func + breakpointsDisabled: _propTypes2.default.bool, + breakpointsLoading: _propTypes2.default.bool, + toggleAllBreakpoints: _propTypes2.default.func.isRequired, + toggleShortcutsModal: _propTypes2.default.func }; SecondaryPanes.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => ({ @@ -25907,7 +25700,7 @@ var _Close2 = _interopRequireDefault(_Close); var _devtoolsReps = __webpack_require__(924); -__webpack_require__(908); +__webpack_require__(1260); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -26152,7 +25945,7 @@ var _Close = __webpack_require__(378); var _Close2 = _interopRequireDefault(_Close); -__webpack_require__(907); +__webpack_require__(1259); var _lodash = __webpack_require__(2); @@ -26160,6 +25953,8 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + function isCurrentlyPausedAtBreakpoint(pause, breakpoint) { if (!pause || pause.isInterrupted) { return false; @@ -26170,8 +25965,12 @@ function isCurrentlyPausedAtBreakpoint(pause, breakpoint) { return bpId === pausedId; } +function getBreakpointFilename(source) { + return source && source.toJS ? (0, _source.getFilename)(source.toJS()) : ""; +} + function renderSourceLocation(source, line, column) { - var filename = source ? (0, _source.getFilename)(source.toJS()) : null; + var filename = getBreakpointFilename(source); var isWasm = source && source.get("isWasm"); var columnVal = (0, _devtoolsConfig.isEnabled)("columnBreakpoints") && column ? `:${column}` : ""; var bpLocation = isWasm ? `0x${line.toString(16).toUpperCase()}` : `${line}${columnVal}`; @@ -26424,16 +26223,16 @@ class Breakpoints extends _react.PureComponent { onClick: () => this.selectBreakpoint(breakpoint), onContextMenu: e => this.showContextMenu(e, breakpoint) }, + _react2.default.createElement("input", { + type: "checkbox", + className: "breakpoint-checkbox", + checked: !isDisabled, + onChange: () => this.handleCheckbox(breakpoint), + onClick: ev => ev.stopPropagation() + }), _react2.default.createElement( "label", { className: "breakpoint-label", title: breakpoint.text }, - _react2.default.createElement("input", { - type: "checkbox", - className: "breakpoint-checkbox", - checked: !isDisabled, - onChange: () => this.handleCheckbox(breakpoint), - onClick: ev => ev.stopPropagation() - }), renderSourceLocation(breakpoint.location.source, line, column) ), _react2.default.createElement( @@ -26455,7 +26254,7 @@ class Breakpoints extends _react.PureComponent { "div", { className: "pane-info" }, L10N.getStr("breakpoints.none") - ) : breakpoints.valueSeq().map(bp => this.renderBreakpoint(bp)); + ) : (0, _lodash.sortBy)([].concat(_toConsumableArray(breakpoints.valueSeq())), [bp => getBreakpointFilename(bp.location.source), bp => bp.location.line]).map(bp => this.renderBreakpoint(bp)); return _react2.default.createElement( "div", @@ -26523,7 +26322,7 @@ var _ManagedTree = __webpack_require__(419); var _ManagedTree2 = _interopRequireDefault(_ManagedTree); -__webpack_require__(850); +__webpack_require__(1216); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -26760,7 +26559,7 @@ var _scopes = __webpack_require__(732); var _devtoolsReps = __webpack_require__(924); -__webpack_require__(850); +__webpack_require__(1216); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27057,7 +26856,7 @@ var _Close = __webpack_require__(378); var _Close2 = _interopRequireDefault(_Close); -__webpack_require__(915); +__webpack_require__(1264); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27171,7 +26970,7 @@ var _Svg = __webpack_require__(344); var _Svg2 = _interopRequireDefault(_Svg); -__webpack_require__(917); +__webpack_require__(1266); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27182,13 +26981,42 @@ class Accordion extends _react.Component { constructor(props) { super(); + this.renderContainer = (item, i) => { + var _state = this.state, + opened = _state.opened, + created = _state.created; + + var containerClassName = `${item.header.toLowerCase().replace(/\s/g, "-")}-pane`; + + return _react2.default.createElement( + "div", + { className: containerClassName, key: i }, + _react2.default.createElement( + "div", + { className: "_header", onClick: () => this.handleHeaderClick(i) }, + _react2.default.createElement(_Svg2.default, { name: "arrow", className: opened[i] ? "expanded" : "" }), + item.header, + item.buttons ? _react2.default.createElement( + "div", + { className: "header-buttons" }, + item.buttons + ) : null + ), + created[i] || opened[i] ? _react2.default.createElement( + "div", + { + className: "_content", + style: { display: opened[i] ? "block" : "none" } + }, + (0, _react.createElement)(item.component, item.componentProps || {}) + ) : null + ); + }; + this.state = { opened: props.items.map(item => item.opened), created: [] }; - - var self = this; - self.renderContainer = this.renderContainer.bind(this); } componentWillReceiveProps(nextProps) { @@ -27221,38 +27049,6 @@ class Accordion extends _react.Component { this.setState({ opened, created }); } - renderContainer(item, i) { - var _state = this.state, - opened = _state.opened, - created = _state.created; - - var containerClassName = `${item.header.toLowerCase().replace(/\s/g, "-")}-pane`; - - return _react2.default.createElement( - "div", - { className: containerClassName, key: i }, - _react2.default.createElement( - "div", - { className: "_header", onClick: () => this.handleHeaderClick(i) }, - _react2.default.createElement(_Svg2.default, { name: "arrow", className: opened[i] ? "expanded" : "" }), - item.header, - item.buttons ? _react2.default.createElement( - "div", - { className: "header-buttons" }, - item.buttons - ) : null - ), - created[i] || opened[i] ? _react2.default.createElement( - "div", - { - className: "_content", - style: { display: opened[i] ? "block" : "none" } - }, - (0, _react.createElement)(item.component, item.componentProps || {}) - ) : null - ); - } - render() { return _react2.default.createElement( "div", @@ -27279,6 +27075,10 @@ Object.defineProperty(exports, "__esModule", { var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -27303,7 +27103,7 @@ var _actions = __webpack_require__(244); var _actions2 = _interopRequireDefault(_actions); -__webpack_require__(918); +__webpack_require__(1215); var _devtoolsModules = __webpack_require__(830); @@ -27473,7 +27273,7 @@ class CommandBar extends _react.Component { } CommandBar.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => { @@ -27520,7 +27320,7 @@ var _PaneToggle = __webpack_require__(428); var _PaneToggle2 = _interopRequireDefault(_PaneToggle); -__webpack_require__(922); +__webpack_require__(1268); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -27559,7 +27359,36 @@ class WelcomeBox extends _react.Component { { className: "welcomebox" }, _react2.default.createElement( "div", - { className: "alignlabel" }, + { className: "alignlabel small-size-layout" }, + _react2.default.createElement( + "div", + { className: "shortcutFunction" }, + _react2.default.createElement( + "p", + { onClick: setActiveSearch.bind(null, "source") }, + _react2.default.createElement( + "span", + { className: "shortcutKey" }, + searchSourcesShortcut + ), + searchSourcesLabel + ), + _react2.default.createElement( + "p", + { onClick: setActiveSearch.bind(null, "project") }, + _react2.default.createElement( + "span", + { className: "shortcutKey" }, + searchProjectShortcut + ), + searchProjectLabel + ) + ), + this.renderToggleButton() + ), + _react2.default.createElement( + "div", + { className: "alignlabel normal-layout" }, _react2.default.createElement( "div", { className: "shortcutKeys" }, @@ -27587,8 +27416,7 @@ class WelcomeBox extends _react.Component { { onClick: setActiveSearch.bind(null, "project") }, searchProjectLabel ) - ), - this.renderToggleButton() + ) ) ); } @@ -27651,7 +27479,7 @@ var _lodash = __webpack_require__(2); var _text = __webpack_require__(389); -__webpack_require__(923); +__webpack_require__(1269); var _PaneToggle = __webpack_require__(428); @@ -28001,7 +27829,7 @@ class SourceTabs extends _react.PureComponent { key: source.get("id"), onClick: () => selectSource(source.get("id")), onContextMenu: e => this.onTabContextMenu(e, source.get("id")), - title: (0, _source.getFilename)(source.toJS()) + title: (0, _source.getFileURL)(source.toJS()) }, sourceAnnotation, _react2.default.createElement( @@ -28122,7 +27950,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -__webpack_require__(935); +__webpack_require__(1270); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -28409,7 +28237,7 @@ var _lodash = __webpack_require__(2); var _frame = __webpack_require__(1014); -__webpack_require__(872); +__webpack_require__(1245); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -28523,19 +28351,25 @@ var findScopeByName = exports.findScopeByName = (() => { }; })(); +exports.containsPosition = containsPosition; exports.findClosestScope = findClosestScope; -var _parser = __webpack_require__(827); - -var _contains = __webpack_require__(1127); +var _parser = __webpack_require__(1208); function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } +function containsPosition(a, b) { + var startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column; + var endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column; + + return startsBefore && endsAfter; +} + function findClosestScope(functions, location) { return functions.reduce((found, currNode) => { - if (currNode.name === "anonymous" || !(0, _contains.containsPosition)(currNode.location, location)) { + if (currNode.name === "anonymous" || !containsPosition(currNode.location, location)) { return found; } @@ -28608,9 +28442,7 @@ var _redux = __webpack_require__(3); var _reactRedux = __webpack_require__(1189); -var _debounce = __webpack_require__(651); - -var _debounce2 = _interopRequireDefault(_debounce); +var _lodash = __webpack_require__(2); var _Popup = __webpack_require__(810); @@ -28633,7 +28465,7 @@ class Preview extends _react.PureComponent { var self = this; self.onScroll = this.onScroll.bind(this); - self.onMouseOver = (0, _debounce2.default)(this.onMouseOver, 40); + self.onMouseOver = (0, _lodash.debounce)(this.onMouseOver, 40); } componentDidMount() { @@ -28757,7 +28589,7 @@ var _PreviewFunction2 = _interopRequireDefault(_PreviewFunction); var _editor = __webpack_require__(257); -__webpack_require__(881); +__webpack_require__(1254); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -28766,6 +28598,12 @@ var Rep = _devtoolsReps2.default.REPS.Rep, ObjectInspectorUtils = _devtoolsReps2.default.ObjectInspectorUtils; var ObjectInspector = _devtoolsReps2.default.ObjectInspector; var getChildren = ObjectInspectorUtils.getChildren; + + +function isReactComponent(roots) { + return roots.some(root => root.name === "_reactInternalInstance"); +} + class Popup extends _react.Component { componentDidMount() { @@ -28826,10 +28664,23 @@ class Popup extends _react.Component { } renderObjectPreview(expression, root) { + var loadedObjects = this.props.loadedObjects; + + var getObjectProperties = id => loadedObjects[id]; + var roots = this.getChildren(root, getObjectProperties); + + if (!roots) { + return null; + } + + if (isReactComponent(roots)) { + roots = roots.filter(r => ["state", "props"].includes(r.name)); + } + return _react2.default.createElement( "div", { className: "preview-popup" }, - this.renderObjectInspector(root) + this.renderObjectInspector(roots) ); } @@ -28847,19 +28698,13 @@ class Popup extends _react.Component { ); } - renderObjectInspector(root) { + renderObjectInspector(roots) { var _props2 = this.props, loadObjectProperties = _props2.loadObjectProperties, loadedObjects = _props2.loadedObjects, openLink = _props2.openLink; - var getObjectProperties = id => loadedObjects[id]; - var roots = this.getChildren(root, getObjectProperties); - - if (!roots) { - return null; - } return _react2.default.createElement(ObjectInspector, { roots: roots, @@ -28930,7 +28775,7 @@ class Popup extends _react.Component { } getPreviewType(value) { - if (typeof value == "number" || typeof value == "boolean" || value.type == "null" || value.type == "undefined" || value.class === "Function") { + if (typeof value == "number" || typeof value == "boolean" || typeof value == "string" && value.length < 10 || typeof value == "number" && value.toString().length < 10 || value.type == "null" || value.type == "undefined" || value.class === "Function") { return "tooltip"; } @@ -28944,7 +28789,6 @@ class Popup extends _react.Component { value = _props3.value, expression = _props3.expression; - var type = this.getPreviewType(value); return _react2.default.createElement( @@ -28977,42 +28821,7 @@ exports.default = (0, _reactRedux.connect)(state => ({ /* 824 */, /* 825 */, /* 826 */, -/* 827 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.getOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined; - -var _devtoolsUtils = __webpack_require__(900); - -var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; - - -var dispatcher = new WorkerDispatcher(); -var startParserWorker = exports.startParserWorker = dispatcher.start.bind(dispatcher); -var stopParserWorker = exports.stopParserWorker = dispatcher.stop.bind(dispatcher); - -var getClosestExpression = exports.getClosestExpression = dispatcher.task("getClosestExpression"); -var getSymbols = exports.getSymbols = dispatcher.task("getSymbols"); -var getScopes = exports.getScopes = dispatcher.task("getScopes"); -var getVariablesInScope = exports.getVariablesInScope = dispatcher.task("getVariablesInScope"); -var getOutOfScopeLocations = exports.getOutOfScopeLocations = dispatcher.task("getOutOfScopeLocations"); -var clearSymbols = exports.clearSymbols = dispatcher.task("clearSymbols"); -var clearScopes = exports.clearScopes = dispatcher.task("clearScopes"); -var clearASTs = exports.clearASTs = dispatcher.task("clearASTs"); -var getNextStep = exports.getNextStep = dispatcher.task("getNextStep"); -var getEmptyLines = exports.getEmptyLines = dispatcher.task("getEmptyLines"); -var hasSource = exports.hasSource = dispatcher.task("hasSource"); -var setSource = exports.setSource = dispatcher.task("setSource"); -var clearSources = exports.clearSources = dispatcher.task("clearSources"); -var hasSyntaxError = exports.hasSyntaxError = dispatcher.task("hasSyntaxError"); - -/***/ }), +/* 827 */, /* 828 */ /***/ (function(module, exports, __webpack_require__) { @@ -29176,204 +28985,44 @@ module.exports = { /* 847 */, /* 848 */, /* 849 */, -/* 850 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 851 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 852 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 853 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 854 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 850 */, +/* 851 */, +/* 852 */, +/* 853 */, +/* 854 */, /* 855 */ /***/ (function(module, exports) { module.exports = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAABqCAMAAAAC5xbnAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAFZaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CkzCJ1kAAAMAUExURUxpcf/fQOF4Wf6qob2GSbyGTP61q++hVlpCNO+ATLuESaZzPYdWLZ1uN/KOQywvJ/OGDfeTGWRSMlpFNvqrQ/yNkPipLfeTGviRGyobJAYCC5BgL/y2MKJrRg0gKH5ULfSTIWhnYyIeJv5/g7K1tfiSGviWIIZgPP+jn6KnqJxqNvmWH/qdTJNkM/6GjPmdKX5JIKiIafeVHTcuLK9uHvTn0/iUH5NiKQUbM/eTH0ExL/6hmv/TStTCqvidK/6Oi/uTkOnZv/mgNLaHbZppFu6ooPeMGYJVJOzbu5pqOap2RY+WnZaOgv+cmahkY/LjzvaEE+vew/2blzs+Ov6enQohIsVvb/+QkP6Bg4+YntB4de7Ru7yfg6KEaf+movj07s7Husx9atqYPJVKKLqESf/47v22GuJOM/3LLf/////ZY//37fyzGP3y4v2rFv3JLP3z5fuiEt9HM/3CKAAAAN1BL//+9f7NLtk7KP726NY0ILB4P/7XYvukH95HLf/88v65Gvy6J/7IKPPizLZ7QPqPEPru3N1AJ7+ITP+vprqAQ+p5IPiZGbV/Rfz8/PyzJv+lmP7VOfitIvqzT/zozeTMtf/RLvycCcSKTP29Hv/ocf/Btv3LOOdpHQQaI/7RY+JcJaltNP66r/3AM6OEMPCMH+nq6/Lz9JpiLzk3M/nYxE40H7WTMcgvHk9AMsLEwyQsL/u8ANrEqurWwJp2Jtrc3WRNR//76fzPsmJHI+FZHvfo1+WiHf3BV/p4dHVdMwABKfDALbV6Kt9PJ91+YHY/L6OVhJksJyIdGcUjB4VrMLd9OMqiL7EqIEJAP/3LXtu5maAFBP7OQ/yWj5GXl7w7K8GLHH1RLNyuLXklJ83Q0WYzLs2THIJJC/+PeXp4cIoABOe4LTUlJ//hbMWXYISKivqqA8udeemXhXtaHOiHc9YLAM1AKI+Ec7ideFVgYNs0BrgSAJh3YcRwII1ZGMCsj2QCAteBEXqDgviWNfW4esd1S8e4ofbDnNVeSrxWUew/xBkAAABkdFJOUwD+EP7//v4CAwX8/mb9HhH/MP3+/TT9TdYm/oP90bA4bPtYefztff7J+buL991SyUn+Y9v62T+cfp3S9P5co9TrkLj++vmqnHCp90X+nf3EvKx27ZH14bSWoqznwX6h/sly7fPC0KykAAAQBUlEQVRo3tyYe0xTWR7Hb+nwKKs4IK9UnAED+CIiLMvE9ZH1Oc64Pnc0O7O7/0nDo8/0BtKUptQ+VgzSUqCVR0oKXWhpAx0oQsOrGDWkQ8AVFggBFBWVSZTERxzHcXZ/59wWWakOGdl/9isgve39nO/9nd/5/c6BIP6/Fcj4X4EDA+Eb/4+00nTkPJAICcW/en6sJB2FJTQmJgp+i00lVtQ/wLYmJ0bFRpfQEnYk7tPx0vGzrNyEhtbR1BKuurpEreaqS0qi4SGIFZpmwIRG19FiWGxZdYlMxpJVVxcpD6UTKxIhYDASi7iyEhmFxz8lXIHyUOgKzDDQ05PrhDKMV9ct4LkCQULsB/Ph9tTIEhpNpi6pk7FldTRZhQfPZXMlWz+QD95jY2ggoZomZHO16jqtlqsVYjyL9cF8BhGlRvQSobYuMjy8lFJ4JODZLDbwUz8EzyBCIhE8kyeMLO0eqqnJR6qp6Q4XAB7xE0KAH8hgMH5d4PdA3Et4vDx1aU12dr5H2fmlAqADnsXdQfzq9QWrKQbRMzMBn79I2d0YD3x2AqSn3+5TET5X4/tGDoIH3lqC6bw82X/h73rwMIAkkTj8l4Ba+qkl3hjvK334OiOZRuN58DWL8JVDXvcsffJJToAmoDZg2+IigStSYOg7Fx5c/XTd51siaTqgv42/Wzkk8eDVyiRR7TCdHlC1aQFFtYOQ2H3h4e9I3EAi6JurPVevqkuw+UweK3wBn323ksKzIfQS/UvNMF2D8H7YPlVJ/aL2JHXDHaVRvgoffOLP06Akdh4Puxe+wQO8srJGgtKexRYIJMokOoVn4BRFt4cmJpcO1UCCZQ/t8Z0yERrNTo1m+j4PWT8nRPhsr3WEj2QVQFYK9Hrlxy81dE1hQNVRz2yGpO4LR8bxx2uSQnzYZxDbAgI0GA8SgioQ3sOuvAt4rqRIiVUE/MKAgMJtuKVF7YCgLCyR7PzuWJ/4CHpt4cOHSXqJRKvVqtVqbThatDVDQ90gKAuIXQRvqiH4SRpqZqmg5NekxN3btWvXTdCu/Jp9PiYXSvymqoOXX9TdrNMWUZJERkokEgEWlLaYOpCMfV9f9PTL/RvXHoS8REEZGtq1yzbY1NQ3PnMOKfNmeKjv6NQetL6IjLlJo1XfrPaKl5kH0unOfYt0X69/+Y9nrvl5O/PBV4zkGLBbzTvXZxkYcJtclnH4JEQ2JtF3UztaldJvvfbiPgJVfEsJHMeAIsNLf/zx9euOxk5V24h98PJpw3oiNaY6D+zydLawTN2AxdZks5n6YARhtJ+P1A8k/DZV7Tcw48obGzs6Hr7uQLqRlvb06VPz1HV+hrQ4Kwu+srIaNpPMy2dCiER1Jg+nWa9jfMbkmAmzNbl6+/ryzhVF+VpZDOAXriVnGwBRb59ApKwJst8sNjrJWQxui6tHIzSTd85AQQstEiK+LtPhOu0IGze5HW6bZSDMMS7Y4TM6ML1Hn5A/FAOimYzH+M3kmOKiwsycBy51FeN/j3N7nwxqx8yArs80MGC3rbWFjdvcpqbT9iLcEnzuP1aRcQ0Y34x4DXGk+YJCYbSSE+hlGzmCxownNxBowcZKhJk6k3t8QKfrC3OZTO4ZGMI9OaoVpPreETGINX9itgG+fnMDZddqVIjF4jEUHfg324zcz5J/I4JQX0tg5fF6bb0mGzzBTN9a+1q3ze4arWBxT7yrrh1+To7gOCPVz5PXxK9eKRTmfngar9qYU+sDcZHcIxGOh7mbIGdMjj7duLt3IOzAZBcLdxyfdc3vd3IrM76+obi4oaF+4hZ559nVnp6eV0Yr83IzXIXcaWi7Rf5GvB1uh6ZfVDBqt/eGmUx2l6lvJk83bjA4cN1L9I3fm6V60M+c/2F29lbcIEnap4wYL3522kAOxs2OjIzMzpNjwZe2UGaiuXOuXnvvQNO422RymYQFXQfmtAXQ76MZS6MDdUeVm9N6z0lSsjqnzGKx8WcjTO6U9Y7nKukU+5//8lM8uVslcw63axwnfa/bNTnZVUE1zKL0JfahoRwvzskQNd54nPLkScqTKbPRKEYTi2Q0ms0bx65Zr21crfjobPD5dajUQ+pztc8cWsuAyW1yTjpHnaOjk97txNv2YV6l0pycDKmqDCRvfZCWRqEVlIzmMeuY+IK/v//Z4Evr1xBBcH8yt0DL7rIarKNOg8uRZp1zjVI9Lfrt1EfzCuYz4Isjb5XDCC33FIoLFxUKsdG82jzmtPYbmAeuXElL+84/GEUnCKc+G5rM5NykY+7ZXJfT5ewqADirgpuwFH84F7FBIlX54+vPf2q5sd/8bAo0t9pJMg12i+HxjfLW8hv3rpz1P7sKRyckAbXIgoKCtEmHY9RlmKyAVyzY6u55Kzhe86AcPoff+Ueyv99iSXn8+Dkg5U9Ii2WQvCUv44hEfFXLd8GX1lEN+pAAB4PFKhh1OA84RyvYbDgIRCf6LTG/my+l8Bl8DkfEeURa7OTjMg6H097efp0ctNj7W8rk8JKTkVsefOkLXKOIKKV3e1XQNdplvcLVKxN2RDF8TOze3IyMBbyqvdViHyQfcdo5ZRw+5zoJ5h/J5Sp4iyPKyG25soXA0fGL1gu4XgmevlCeiA0hfB6Sjhd78SLkUQSODU1ywKva2x/+s8lwx2Oen5Mj7aTco9RXCjzSK5XRW0MXNj5L8ibXExsUfMC3kBbDvzra28vK2jume3puPyrzms+Rqu595jn6pn+sx2wIyqEoP7zTDPRdbhbwlP3Wy8x/90x3lEHv0tALNT3lco95jF+HowvxOaHHex8qKEGMd+0wg46/wUP0+Sr5rdtQb6Y1AYWwqYFtTaPXPOA7L26HvMeFJFaJgpJO/Y3gPdvvk960R+EBfNlPP08P02sDKNFr5Z0eOuAbD6zB+CAi6JOxNE9Q3n8u2d0ufWMfwqNqHB4upESn0wsbVRwvPUfa8jllPYjYMGjYQPzyHwQWLauF8Hc2VtUiVXU0NnZyvN7BPH//dk9FXPPbwU+I5ZyGFq8rD58v4nNUWBw+n5pVCp/xV5w3EQxiQxNzAzULv6y9uYv5OD35lHDKiLxv5PIjUKhDdh6N+AP9m2WfCoNOSqUZix8AY7H4b+Bgfu8RtBMJKaw9M4wOEYHLPBYSezszUMl/8wQibF60cA33g+b45t2QNat2Hjw2XPjVMo/p8KEjX8fL+ainLBrhzVBI0lyRfGKieGL9Z1+sN35/7Bi96uDy3EPqfB3fVh+f0sqBEGHYIix+JZVKOY0P4toaiidSLp0//5HxzrHhnaeWeTw/srkNth8jt//+fXnnfzq1vpC2rjAe9F4bc80MhhZCpqIWnDJLhw8V+2BhD4Wtb13pnvZ0axzahN6QeU0w/ol6r0muFldbRSK2I7F/Fh2KsqogGmOUzGGpobMOdFKmqN10o66Ubuw79yaptrGc5PeQnHvP+X7fd77z7zvnnpq6iApJRx1CTcv9f2d2t/cLPG0jswSsiQ/XN3uSk3DOqI7JPj/paWvzjIzOm7Z3P371o62lRuQET4H/r47bOhdffXtLtWtm5tVP2zyzdppX/tCb+dUXSXieKYAoqd9TsMZYGZ/qlsoxs7nY2Tk8PGwDDP31n297W/W70+0yWZm1l/39BTQhPOwt1uA5Ri7LvjAoGc/omL4T39W6tre3d3e5efXwuK3lwtqu2WRyfNiud/oYHbs/+PXgJ/a7vXO5YriAwa4pCs4+7fcsgfE6k8NYXeVgdDrGxDFrS5XfjKh3dAx6bSjXu0w63d6fnpFZYaA3S4Y1YGFAFXYR5NLI4IMdE/C4DQaRRsT+YOXLRyjB9HVUdOvdVkitLXlOrs7NYU4HctlpC6Gwf1qQs2ey6hhfbYXB2ceI5IzOO7oakBSZ3GD+tT7Q61WfLPh5DtN4sF5LkDTN5yxzyHhXA+yPfEzYet3CfjhhcrVXG/UOoGcWLubMzWkw5zK5TAuBEU892OGsopHVRuSDMEL+SMpXa6joRvViTP5L61m4M6XkHDojYEWOtQKJ0c2aIgj5GcbEILBu2Kx1IPN1oXuXcI1Hc0Yh35W/bDazJisHLQj0LkcEf/v7wrA6GlAWC6rZALbxYsdUCgMhl8vhdjtrgcPQADCKaJx4cqK9o70DQcyqdTscrr6d4vR4+LMv3u5oB0bxNKdC3OoDIHXzl8mpmxWRJ/Gox9jQ3l57uyQu89VTYXHEAGg0RqyfnKo2iK8MYo6ovaJxIh7zZVk/3ZTEgbYbUF9eHglNn/zWaKg4BIOxobzqbi5+19FkgPFQ7W4IzlEw+gZ695OJ+vLublQRBHSShILu+l9xhxV0nZLvq43l+mvOZpUKGs7lGovCNeb/B96qmpudTlCmr6qSIu76jgwN7qSQXjqhd6ugQ/isVqm3M1HsrOzAW6vP5xvrg77lULmdSEt5/XQJLn2uHzEj0uhgZaxh7KyEoqpAL8tyvjGXQ9Wsn8D0jlxWEmCjzCKvVAWOY1nWuxIyA9iDgGduzIHrHVnWAhfl5oAUxL3zYeythLiDxPCDikDKj9V3IMwt9cJ0gJhZs9e7EAgs7y/7/aMS1OuP9h6FsbfnNYerwsHEUIJHn14sSQHz8opanZH/4vXroaFOCUOro6vPL8wCnj9fzVlZDgQWxNIsF8rC7ThexA3Uk/lKCrbhGzcgPKgJY3wcYu+WlvEbNlvnH3fzJzPUoANUcKFSvJYF55gXlgcmlZYmu91O03Rww3al7ko4yqkTgx74rxzegGzYpivzkYqFUCnWvHAMmjZwL59qEqkRyCA/BOGmqKGyBoWYEPDYFsmglA06LMpJ9co9DZ7zc9cHlE0RbpHfPv1syHZVCs9QhDY+vMhP28loAYIghPySdMwpp5iyC/RBkGTTNL+BNvw223Dn0ItnQSAnD5YQD40wh22acEhUUmAPTgftBI/+p4M0+VYJBX8GM/aG1YTiFfS7CkjkZ2gRkiTfzRXSsEOF9Myud+nf6IgBBU9l4y/mWuII+qMArpfjrycxvfM+4PtG7ACF8dEr+KI41tpU2en4zCcFbRwrOXj/DB2rDRUIsYzPlMfzZRU6TxFBvsVLkoQEkjysRMErs+MxXgw0lQIflSf5ri6eoAVBsAgCbKR4eIoqIGkqLT52VNPzSguaSwiQJ2gqs/CMVpsmQQvb2M8EqJ1YF1qgzsf9TRu5x0JRYKygIJTa7Lemq3RNWhGtgMpAGSqeXnNg5rEIlBJAFWVLNZKnSpC4NEWQd5uiBEtaAhcuYIuVOYPQZQdx+eFNn1wuT5WlzWxtbm5tbWUmYDzQHz93J6U1+fHZx3mxB8flnp6UO9eTW88dT+Bzf6osr+d+T0pKMsgnxTzeb0XZ6NguLwHnpMpOtYJ4a2tya1ls+rOIHZ2s5SV22SXv8kdlZWWXvzwe+/5F3rnrwH39cVkizhFFUpOSUo/O/uBUHuBUkiwxRD+tH3V/5HC5hO5zvUcWhsCx9991OIT/AVwXLXUhLDYVAAAAAElFTkSuQmCC" /***/ }), -/* 856 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 857 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 858 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 859 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 860 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 861 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 862 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 863 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 864 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 865 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 866 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 867 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 868 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 869 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 870 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 871 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 872 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 873 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 874 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 875 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 876 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 877 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 878 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 879 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 880 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 881 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 882 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 856 */, +/* 857 */, +/* 858 */, +/* 859 */, +/* 860 */, +/* 861 */, +/* 862 */, +/* 863 */, +/* 864 */, +/* 865 */, +/* 866 */, +/* 867 */, +/* 868 */, +/* 869 */, +/* 870 */, +/* 871 */, +/* 872 */, +/* 873 */, +/* 874 */, +/* 875 */, +/* 876 */, +/* 877 */, +/* 878 */, +/* 879 */, +/* 880 */, +/* 881 */, +/* 882 */, /* 883 */ /***/ (function(module, exports, __webpack_require__) { @@ -31315,11 +30964,11 @@ var _devtoolsLaunchpad = __webpack_require__(131); var _devtoolsSourceMap = __webpack_require__(898); -var _search = __webpack_require__(1115); +var _search = __webpack_require__(1210); -var _prettyPrint = __webpack_require__(903); +var _prettyPrint = __webpack_require__(1213); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var _createStore = __webpack_require__(189); @@ -31627,59 +31276,7 @@ module.exports = { }; /***/ }), -/* 903 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.prettyPrint = exports.stopPrettyPrintWorker = exports.startPrettyPrintWorker = undefined; - -var prettyPrint = exports.prettyPrint = (() => { - var _ref = _asyncToGenerator(function* (_ref2) { - var source = _ref2.source, - url = _ref2.url; - - var indent = 2; - - (0, _assert2.default)((0, _source.isJavaScript)(source), "Can't prettify non-javascript files."); - - return yield _prettyPrint({ - url, - indent, - source: source.text - }); - }); - - return function prettyPrint(_x) { - return _ref.apply(this, arguments); - }; -})(); - -var _devtoolsUtils = __webpack_require__(900); - -var _source = __webpack_require__(233); - -var _assert = __webpack_require__(223); - -var _assert2 = _interopRequireDefault(_assert); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } - -var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; - - -var dispatcher = new WorkerDispatcher(); -var startPrettyPrintWorker = exports.startPrettyPrintWorker = dispatcher.start.bind(dispatcher); -var stopPrettyPrintWorker = exports.stopPrettyPrintWorker = dispatcher.stop.bind(dispatcher); -var _prettyPrint = dispatcher.task("prettyPrint"); - -/***/ }), +/* 903 */, /* 904 */ /***/ (function(module, exports, __webpack_require__) { @@ -31737,11 +31334,16 @@ function updatePreview(target, editor, _ref) { } var invalidToken = tokenText === "" || tokenText.match(/[(){}\|&%,.;=<>\+-/\*\s]/); + var invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0; + var isUpdating = preview && preview.updating; + var inScope = linesInScope && linesInScope.includes(location.line); - if (invalidTarget || !inScope || isUpdating || invalidToken) { + var invaildType = target.className === "cm-string" || target.className === "cm-number" || target.className === "cm-atom"; + + if (invalidTarget || !inScope || isUpdating || invalidToken || invaildType) { return; } @@ -31749,36 +31351,11 @@ function updatePreview(target, editor, _ref) { } /***/ }), -/* 905 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 906 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 907 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 908 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 909 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 905 */, +/* 906 */, +/* 907 */, +/* 908 */, +/* 909 */, /* 910 */ /***/ (function(module, exports, __webpack_require__) { @@ -31803,7 +31380,7 @@ var dom = React.DOM, PropTypes = React.PropTypes; -__webpack_require__(861); +__webpack_require__(1232); /** * This component represents a Splitter. The splitter supports vertical @@ -32106,24 +31683,9 @@ var Draggable = React.createClass({ module.exports = Draggable; /***/ }), -/* 913 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 914 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 915 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 913 */, +/* 914 */, +/* 915 */, /* 916 */ /***/ (function(module, exports, __webpack_require__) { @@ -32663,18 +32225,8 @@ module.exports = Draggable; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792))) /***/ }), -/* 917 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 918 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 917 */, +/* 918 */, /* 919 */ /***/ (function(module, exports) { @@ -32687,24 +32239,9 @@ module.exports = "" /***/ }), -/* 921 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 922 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 923 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 921 */, +/* 922 */, +/* 923 */, /* 924 */ /***/ (function(module, exports, __webpack_require__) { @@ -32773,7 +32310,7 @@ module.exports = { * 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/. */ -__webpack_require__(877); +__webpack_require__(1250); // Load all existing rep templates var Undefined = __webpack_require__(929); @@ -33858,12 +33395,7 @@ module.exports = { }; /***/ }), -/* 935 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 935 */, /* 936 */ /***/ (function(module, exports, __webpack_require__) { @@ -35546,12 +35078,7 @@ module.exports = { }; /***/ }), -/* 952 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 952 */, /* 953 */ /***/ (function(module, exports, __webpack_require__) { @@ -36401,16 +35928,11 @@ module.exports = { /* 960 */ /***/ (function(module, exports) { -module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySource): This is the text that appears in the\n# context menu to copy the selected source of file open.\ncopySource=Copy\ncopySource.accesskey=y\n\n# LOCALIZATION NOTE (copySourceUri2): This is the text that appears in the\n# context menu to copy the source URI of file open.\ncopySourceUri2=Copy source URI\ncopySourceUri2.accesskey=u\n\n# LOCALIZATION NOTE (copyFunction): This is the text that appears in the\n# context menu to copy the function the user selected\ncopyFunction.label=Copy function\ncopyFunction.accesskey=F\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy stack trace\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step in %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step out %S\n\n# LOCALIZATION NOTE (workersHeader): The text to display in the events\n# header.\nworkersHeader=Workers\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display.\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the\n# full project text search for searching all the files the debugger has seen.\nprojectTextSearch.key=CmdOrCtrl+Shift+F\n\n# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the\n# modal for searching functions in a file.\nfunctionSearch.key=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE (toggleBreakpoint.key): A key shortcut to toggle\n# breakpoints.\ntoggleBreakpoint.key=CmdOrCtrl+B\n\n# LOCALIZATION NOTE (toggleCondPanel.key): A key shortcut to toggle\n# the conditional breakpoint panel.\ntoggleCondPanel.key=CmdOrCtrl+Shift+B\n\n# LOCALIZATION NOTE (stepOut.key): A key shortcut to\n# step out.\nstepOut.key=Shift+F11\n\n# LOCALIZATION NOTE (shortcuts.header.editor): Sections header in\n# the shortcuts modal for keyboard shortcuts related to editing.\nshortcuts.header.editor=Editor\n\n# LOCALIZATION NOTE (shortcuts.header.stepping): Sections header in\n# the shortcuts modal for keyboard shortcuts related to stepping.\nshortcuts.header.stepping=Stepping\n\n# LOCALIZATION NOTE (shortcuts.header.search): Sections header in\n# the shortcuts modal for keyboard shortcuts related to search.\nshortcuts.header.search=Search\n\n# LOCALIZATION NOTE (projectTextSearch.placeholder): A placeholder shown\n# when searching across all of the files in a project.\nprojectTextSearch.placeholder=Find in files…\n\n# LOCALIZATION NOTE (projectTextSearch.noResults): The center pane Text Search\n# message when the query did not match any text of all files in a project.\nprojectTextSearch.noResults=No results found\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf2.label=Enable\nbreakpointMenuItem.enableSelf2.accesskey=E\nbreakpointMenuItem.disableSelf2.label=Disable\nbreakpointMenuItem.disableSelf2.accesskey=D\nbreakpointMenuItem.deleteSelf2.label=Remove\nbreakpointMenuItem.deleteSelf2.accesskey=R\nbreakpointMenuItem.enableOthers2.label=Enable others\nbreakpointMenuItem.enableOthers2.accesskey=o\nbreakpointMenuItem.disableOthers2.label=Disable others\nbreakpointMenuItem.disableOthers2.accesskey=s\nbreakpointMenuItem.deleteOthers2.label=Remove others\nbreakpointMenuItem.deleteOthers2.accesskey=h\nbreakpointMenuItem.enableAll2.label=Enable all\nbreakpointMenuItem.enableAll2.accesskey=b\nbreakpointMenuItem.disableAll2.label=Disable all\nbreakpointMenuItem.disableAll2.accesskey=k\nbreakpointMenuItem.deleteAll2.label=Remove all\nbreakpointMenuItem.deleteAll2.accesskey=a\nbreakpointMenuItem.removeCondition2.label=Remove condition\nbreakpointMenuItem.removeCondition2.accesskey=c\nbreakpointMenuItem.addCondition2.label=Add condition\nbreakpointMenuItem.addCondition2.accesskey=A\nbreakpointMenuItem.editCondition2.label=Edit condition\nbreakpointMenuItem.editCondition2.accesskey=n\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.enableSelf.accesskey=E\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.disableSelf.accesskey=D\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.deleteSelf.accesskey=R\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.enableOthers.accesskey=o\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.disableOthers.accesskey=s\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.deleteOthers.accesskey=h\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.enableAll.accesskey=b\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.disableAll.accesskey=k\nbreakpointMenuItem.deleteAll=Remove all breakpoints\nbreakpointMenuItem.deleteAll.accesskey=a\nbreakpointMenuItem.removeCondition.label=Remove breakpoint condition\nbreakpointMenuItem.removeCondition.accesskey=c\nbreakpointMenuItem.editCondition.label=Edit breakpoint condition\nbreakpointMenuItem.editCondition.accesskey=n\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=No results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.continueToHere.label): Editor gutter context\n# menu item for jumping to a new paused location\neditor.continueToHere.label=Continue to here\neditor.continueToHere.accesskey=H\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add conditional breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable framework grouping\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable framework grouping\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=Generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add watch expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close other tabs\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in tree\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy link address\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty print source\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox source\nsourceFooter.blackbox.accesskey=B\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed source\n\n# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated\n# with a code coverage button\nsourceFooter.codeCoverage=Code coverage\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (outline.header): Outline left sidebar header\noutline.header=Outline\n\n# LOCALIZATION NOTE (outline.noFunctions): Outline text when there are no functions to display\noutline.noFunctions=No functions\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (welcome.findInFiles): The center pane welcome panel's\n# search prompt. e.g. cmd+f to search for files. On windows, it's ctrl+shift+f, on\n# a mac we use the unicode character.\nwelcome.findInFiles=%S to find in files\n\n# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome\n# panel. %S is replaced by the keyboard shortcut to search for functions.\nwelcome.searchFunction=%S to search for functions in file\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults2=No results found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText3=Error loading this URI: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.modifiersLabel): A label\n# preceding the group of modifiers\nsymbolSearch.searchModifier.modifiersLabel=Modifiers:\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n\n# LOCALIZATION NOTE (anonymous): The text that is displayed when the\n# display name is null.\nanonymous=(anonymous)\n\n# LOCALIZATION NOTE (shortcuts.toggleBreakpoint): text describing\n# keyboard shortcut action for toggling breakpoint\nshortcuts.toggleBreakpoint=Toggle Breakpoint\n\n# LOCALIZATION NOTE (shortcuts.toggleCondPanel): text describing\n# keyboard shortcut action for toggling conditional panel keyboard\nshortcuts.toggleCondPanel=Toggle Conditional Panel\n\n# LOCALIZATION NOTE (shortcuts.pauseOrResume): text describing\n# keyboard shortcut action for pause of resume\nshortcuts.pauseOrResume=Pause/Resume\n\n# LOCALIZATION NOTE (shortcuts.stepOver): text describing\n# keyboard shortcut action for stepping over\nshortcuts.stepOver=Step Over\n\n# LOCALIZATION NOTE (shortcuts.stepIn): text describing\n# keyboard shortcut action for stepping in\nshortcuts.stepIn=Step In\n\n# LOCALIZATION NOTE (shortcuts.stepOut): text describing\n# keyboard shortcut action for stepping out\nshortcuts.stepOut=Step Out\n\n# LOCALIZATION NOTE (shortcuts.fileSearch): text describing\n# keyboard shortcut action for source file search\nshortcuts.fileSearch=Source File Search\n\n# LOCALIZATION NOTE (shortcuts.searchAgain): text describing\n# keyboard shortcut action for searching again\nshortcuts.searchAgain=Search Again\n\n# LOCALIZATION NOTE (shortcuts.projectSearch): text describing\n# keyboard shortcut action for full project search\nshortcuts.projectSearch=Full Project Search\n\n# LOCALIZATION NOTE (shortcuts.functionSearch): text describing\n# keyboard shortcut action for function search\nshortcuts.functionSearch=Function Search\n" +module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySource): This is the text that appears in the\n# context menu to copy the selected source of file open.\ncopySource=Copy\ncopySource.accesskey=y\n\n# LOCALIZATION NOTE (copySourceUri2): This is the text that appears in the\n# context menu to copy the source URI of file open.\ncopySourceUri2=Copy source URI\ncopySourceUri2.accesskey=u\n\n# LOCALIZATION NOTE (copyFunction): This is the text that appears in the\n# context menu to copy the function the user selected\ncopyFunction.label=Copy function\ncopyFunction.accesskey=F\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy stack trace\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step in %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step out %S\n\n# LOCALIZATION NOTE (workersHeader): The text to display in the events\n# header.\nworkersHeader=Workers\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display.\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the\n# full project text search for searching all the files the debugger has seen.\nprojectTextSearch.key=CmdOrCtrl+Shift+F\n\n# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the\n# modal for searching functions in a file.\nfunctionSearch.key=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE (toggleBreakpoint.key): A key shortcut to toggle\n# breakpoints.\ntoggleBreakpoint.key=CmdOrCtrl+B\n\n# LOCALIZATION NOTE (toggleCondPanel.key): A key shortcut to toggle\n# the conditional breakpoint panel.\ntoggleCondPanel.key=CmdOrCtrl+Shift+B\n\n# LOCALIZATION NOTE (stepOut.key): A key shortcut to\n# step out.\nstepOut.key=Shift+F11\n\n# LOCALIZATION NOTE (shortcuts.header.editor): Sections header in\n# the shortcuts modal for keyboard shortcuts related to editing.\nshortcuts.header.editor=Editor\n\n# LOCALIZATION NOTE (shortcuts.header.stepping): Sections header in\n# the shortcuts modal for keyboard shortcuts related to stepping.\nshortcuts.header.stepping=Stepping\n\n# LOCALIZATION NOTE (shortcuts.header.search): Sections header in\n# the shortcuts modal for keyboard shortcuts related to search.\nshortcuts.header.search=Search\n\n# LOCALIZATION NOTE (projectTextSearch.placeholder): A placeholder shown\n# when searching across all of the files in a project.\nprojectTextSearch.placeholder=Find in files…\n\n# LOCALIZATION NOTE (projectTextSearch.noResults): The center pane Text Search\n# message when the query did not match any text of all files in a project.\nprojectTextSearch.noResults=No results found\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf2.label=Enable\nbreakpointMenuItem.enableSelf2.accesskey=E\nbreakpointMenuItem.disableSelf2.label=Disable\nbreakpointMenuItem.disableSelf2.accesskey=D\nbreakpointMenuItem.deleteSelf2.label=Remove\nbreakpointMenuItem.deleteSelf2.accesskey=R\nbreakpointMenuItem.enableOthers2.label=Enable others\nbreakpointMenuItem.enableOthers2.accesskey=o\nbreakpointMenuItem.disableOthers2.label=Disable others\nbreakpointMenuItem.disableOthers2.accesskey=s\nbreakpointMenuItem.deleteOthers2.label=Remove others\nbreakpointMenuItem.deleteOthers2.accesskey=h\nbreakpointMenuItem.enableAll2.label=Enable all\nbreakpointMenuItem.enableAll2.accesskey=b\nbreakpointMenuItem.disableAll2.label=Disable all\nbreakpointMenuItem.disableAll2.accesskey=k\nbreakpointMenuItem.deleteAll2.label=Remove all\nbreakpointMenuItem.deleteAll2.accesskey=a\nbreakpointMenuItem.removeCondition2.label=Remove condition\nbreakpointMenuItem.removeCondition2.accesskey=c\nbreakpointMenuItem.addCondition2.label=Add condition\nbreakpointMenuItem.addCondition2.accesskey=A\nbreakpointMenuItem.editCondition2.label=Edit condition\nbreakpointMenuItem.editCondition2.accesskey=n\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.enableSelf.accesskey=E\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.disableSelf.accesskey=D\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.deleteSelf.accesskey=R\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.enableOthers.accesskey=o\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.disableOthers.accesskey=s\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.deleteOthers.accesskey=h\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.enableAll.accesskey=b\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.disableAll.accesskey=k\nbreakpointMenuItem.deleteAll=Remove all breakpoints\nbreakpointMenuItem.deleteAll.accesskey=a\nbreakpointMenuItem.removeCondition.label=Remove breakpoint condition\nbreakpointMenuItem.removeCondition.accesskey=c\nbreakpointMenuItem.editCondition.label=Edit breakpoint condition\nbreakpointMenuItem.editCondition.accesskey=n\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=No results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.continueToHere.label): Editor gutter context\n# menu item for jumping to a new paused location\neditor.continueToHere.label=Continue to here\neditor.continueToHere.accesskey=H\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add conditional breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable framework grouping\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable framework grouping\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=Generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add watch expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close other tabs\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in tree\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy link address\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty print source\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox source\nsourceFooter.blackbox.accesskey=B\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed source\n\n# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated\n# with a code coverage button\nsourceFooter.codeCoverage=Code coverage\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (outline.header): Outline left sidebar header\noutline.header=Outline\n\n# LOCALIZATION NOTE (outline.noFunctions): Outline text when there are no functions to display\noutline.noFunctions=No functions\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (welcome.findInFiles): The center pane welcome panel's\n# search prompt. e.g. cmd+f to search for files. On windows, it's ctrl+shift+f, on\n# a mac we use the unicode character.\nwelcome.findInFiles=%S to find in files\n\n# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome\n# panel. %S is replaced by the keyboard shortcut to search for functions.\nwelcome.searchFunction=%S to search for functions in file\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults2=No results found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText3): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText3=Error loading this URI: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.modifiersLabel): A label\n# preceding the group of modifiers\nsymbolSearch.searchModifier.modifiersLabel=Modifiers:\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n\n# LOCALIZATION NOTE (anonymous): The text that is displayed when the\n# display name is null.\nanonymous=(anonymous)\n\n# LOCALIZATION NOTE (shortcuts.toggleBreakpoint): text describing\n# keyboard shortcut action for toggling breakpoint\nshortcuts.toggleBreakpoint=Toggle Breakpoint\n\n# LOCALIZATION NOTE (shortcuts.toggleCondPanel): text describing\n# keyboard shortcut action for toggling conditional panel keyboard\nshortcuts.toggleCondPanel=Toggle Conditional Panel\n\n# LOCALIZATION NOTE (shortcuts.pauseOrResume): text describing\n# keyboard shortcut action for pause of resume\nshortcuts.pauseOrResume=Pause/Resume\n\n# LOCALIZATION NOTE (shortcuts.stepOver): text describing\n# keyboard shortcut action for stepping over\nshortcuts.stepOver=Step Over\n\n# LOCALIZATION NOTE (shortcuts.stepIn): text describing\n# keyboard shortcut action for stepping in\nshortcuts.stepIn=Step In\n\n# LOCALIZATION NOTE (shortcuts.stepOut): text describing\n# keyboard shortcut action for stepping out\nshortcuts.stepOut=Step Out\n\n# LOCALIZATION NOTE (shortcuts.fileSearch): text describing\n# keyboard shortcut action for source file search\nshortcuts.fileSearch=Source File Search\n\n# LOCALIZATION NOTE (shortcuts.searchAgain): text describing\n# keyboard shortcut action for searching again\nshortcuts.searchAgain=Search Again\n\n# LOCALIZATION NOTE (shortcuts.projectSearch): text describing\n# keyboard shortcut action for full project search\nshortcuts.projectSearch=Full Project Search\n\n# LOCALIZATION NOTE (shortcuts.functionSearch): text describing\n# keyboard shortcut action for function search\nshortcuts.functionSearch=Function Search\n\n# LOCALIZATION NOTE (shortcuts.buttonName): text describing\n# keyboard shortcut button text\nshortcuts.buttonName=Keyboard shortcuts\n" /***/ }), /* 961 */, -/* 962 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 962 */, /* 963 */, /* 964 */, /* 965 */ @@ -38762,6 +38284,10 @@ Object.defineProperty(exports, "__esModule", { }); exports.getAndProcessFrames = getAndProcessFrames; +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -38778,9 +38304,9 @@ var _Frame = __webpack_require__(1013); var _Frame2 = _interopRequireDefault(_Frame); -var _Group2 = __webpack_require__(1015); +var _Group = __webpack_require__(1015); -var _Group3 = _interopRequireDefault(_Group2); +var _Group2 = _interopRequireDefault(_Group); var _WhyPaused = __webpack_require__(1120); @@ -38796,14 +38322,10 @@ var _clipboard = __webpack_require__(423); var _selectors = __webpack_require__(242); -__webpack_require__(914); +__webpack_require__(1263); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var FrameComponent = (0, _react.createFactory)(_Frame2.default); - -var Group = (0, _react.createFactory)(_Group3.default); - var NUM_FRAMES_SHOWN = 7; class Frames extends _react.Component { @@ -38881,23 +38403,23 @@ class Frames extends _react.Component { return _react2.default.createElement( "ul", null, - framesOrGroups.map(frameOrGroup => frameOrGroup.id ? FrameComponent({ + framesOrGroups.map(frameOrGroup => frameOrGroup.id ? _react2.default.createElement(_Frame2.default, { frame: frameOrGroup, toggleFrameworkGrouping: this.toggleFrameworkGrouping, copyStackTrace: this.copyStackTrace, - frameworkGroupingOn, - selectFrame, - selectedFrame, - toggleBlackBox, + frameworkGroupingOn: frameworkGroupingOn, + selectFrame: selectFrame, + selectedFrame: selectedFrame, + toggleBlackBox: toggleBlackBox, key: frameOrGroup.id - }) : Group({ + }) : _react2.default.createElement(_Group2.default, { group: frameOrGroup, toggleFrameworkGrouping: this.toggleFrameworkGrouping, copyStackTrace: this.copyStackTrace, - frameworkGroupingOn, - selectFrame, - selectedFrame, - toggleBlackBox, + frameworkGroupingOn: frameworkGroupingOn, + selectFrame: selectFrame, + selectedFrame: selectedFrame, + toggleBlackBox: toggleBlackBox, key: frameOrGroup[0].id })) ); @@ -38947,13 +38469,13 @@ class Frames extends _react.Component { } Frames.propTypes = { - frames: _react.PropTypes.array, - frameworkGroupingOn: _react.PropTypes.bool.isRequired, - toggleFrameworkGrouping: _react.PropTypes.func.isRequired, - selectedFrame: _react.PropTypes.object, - selectFrame: _react.PropTypes.func.isRequired, - toggleBlackBox: _react.PropTypes.func, - pause: _react.PropTypes.object + frames: _propTypes2.default.array, + frameworkGroupingOn: _propTypes2.default.bool.isRequired, + toggleFrameworkGrouping: _propTypes2.default.func.isRequired, + selectedFrame: _propTypes2.default.object, + selectFrame: _propTypes2.default.func.isRequired, + toggleBlackBox: _propTypes2.default.func, + pause: _propTypes2.default.object }; function getSourceForFrame(sources, frame) { @@ -39225,6 +38747,10 @@ function isDojo(frame) { return getFrameUrl(frame).match(/dojo/i); } +function isPreact(frame) { + return getFrameUrl(frame).match(/preact/i); +} + function getLibraryFromUrl(frame) { // @TODO each of these fns calls getFrameUrl, just call it once // (assuming there's not more complex logic to identify a lib) @@ -39237,6 +38763,11 @@ function getLibraryFromUrl(frame) { return "jQuery"; } + // Needs to remain before "react", otherwise "react" can also match "preact" + if (isPreact(frame)) { + return "Preact"; + } + if (isReact(frame)) { return "React"; } @@ -39476,7 +39007,7 @@ var _FrameMenu = __webpack_require__(1032); var _FrameMenu2 = _interopRequireDefault(_FrameMenu); -__webpack_require__(909); +__webpack_require__(1261); var _Frame = __webpack_require__(1013); @@ -39484,8 +39015,6 @@ var _Frame2 = _interopRequireDefault(_Frame); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var FrameComponent = (0, _react.createFactory)(_Frame2.default); - function FrameLocation(_ref) { var frame = _ref.frame; @@ -39502,16 +39031,19 @@ function FrameLocation(_ref) { ); } + FrameLocation.displayName = "FrameLocation"; class Group extends _react.Component { constructor() { super(...arguments); - this.state = { expanded: false }; - var self = this; - self.toggleFrames = this.toggleFrames.bind(this); + this.toggleFrames = () => { + this.setState({ expanded: !this.state.expanded }); + }; + + this.state = { expanded: false }; } onContextMenu(event) { @@ -39526,10 +39058,6 @@ class Group extends _react.Component { (0, _FrameMenu2.default)(frame, frameworkGroupingOn, { copyStackTrace, toggleFrameworkGrouping, toggleBlackBox }, event); } - toggleFrames() { - this.setState({ expanded: !this.state.expanded }); - } - renderFrames() { var _props2 = this.props, group = _props2.group, @@ -39548,17 +39076,17 @@ class Group extends _react.Component { return _react2.default.createElement( "div", { className: "frames-list" }, - group.map(frame => FrameComponent({ - frame, - copyStackTrace, - toggleFrameworkGrouping, - frameworkGroupingOn, - selectFrame, - selectedFrame, - toggleBlackBox, - key: frame.id, + group.map(frame => _react2.default.createElement(_Frame2.default, { + copyStackTrace: copyStackTrace, + frame: frame, + frameworkGroupingOn: frameworkGroupingOn, hideLocation: true, - shouldMapDisplayName: false + key: frame.id, + selectedFrame: selectedFrame, + selectFrame: selectFrame, + shouldMapDisplayName: false, + toggleBlackBox: toggleBlackBox, + toggleFrameworkGrouping: toggleFrameworkGrouping })) ); } @@ -39721,7 +39249,7 @@ var _classnames = __webpack_require__(175); var _classnames2 = _interopRequireDefault(_classnames); -__webpack_require__(879); +__webpack_require__(1252); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -40255,7 +39783,7 @@ var _sources = __webpack_require__(254); var _promise = __webpack_require__(193); -var _parser = __webpack_require__(827); +var _parser = __webpack_require__(1208); var _devtoolsSourceMap = __webpack_require__(898); @@ -40478,6 +40006,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -40498,7 +40030,7 @@ var _SearchInput = __webpack_require__(377); var _SearchInput2 = _interopRequireDefault(_SearchInput); -__webpack_require__(866); +__webpack_require__(1238); var _sourcesTree = __webpack_require__(39); @@ -40706,17 +40238,17 @@ class TextSearch extends _react.Component { exports.default = TextSearch; TextSearch.propTypes = { - sources: _react.PropTypes.object, - results: _react.PropTypes.array, - query: _react.PropTypes.string, - closeActiveSearch: _react.PropTypes.func, - searchSources: _react.PropTypes.func, - selectSource: _react.PropTypes.func, - searchBottomBar: _react.PropTypes.object + sources: _propTypes2.default.object, + results: _propTypes2.default.array, + query: _propTypes2.default.string, + closeActiveSearch: _propTypes2.default.func, + searchSources: _propTypes2.default.func, + selectSource: _propTypes2.default.func, + searchBottomBar: _propTypes2.default.object }; TextSearch.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; /***/ }), @@ -40770,31 +40302,7 @@ TextSearch.contextTypes = { /* 1112 */, /* 1113 */, /* 1114 */, -/* 1115 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.findSourceMatches = exports.searchSources = exports.getMatches = exports.stopSearchWorker = exports.startSearchWorker = undefined; - -var _devtoolsUtils = __webpack_require__(900); - -var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; - - -var dispatcher = new WorkerDispatcher(); -var startSearchWorker = exports.startSearchWorker = dispatcher.start.bind(dispatcher); -var stopSearchWorker = exports.stopSearchWorker = dispatcher.stop.bind(dispatcher); - -var getMatches = exports.getMatches = dispatcher.task("getMatches"); -var searchSources = exports.searchSources = dispatcher.task("searchSources"); -var findSourceMatches = exports.findSourceMatches = dispatcher.task("findSourceMatches"); - -/***/ }), +/* 1115 */, /* 1116 */, /* 1117 */ /***/ (function(module, exports) { @@ -40833,7 +40341,7 @@ var _lodash = __webpack_require__(2); var _pause = __webpack_require__(255); -__webpack_require__(913); +__webpack_require__(1262); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -40958,34 +40466,7 @@ function getInScopeLines(state) { module.exports = "" /***/ }), -/* 1127 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.containsPosition = containsPosition; -exports.containsLocation = containsLocation; -exports.nodeContainsPosition = nodeContainsPosition; -function containsPosition(a, b) { - var startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column; - var endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column; - - return startsBefore && endsAfter; -} - -function containsLocation(a, b) { - return containsPosition(a, b.start) && containsPosition(a, b.end); -} - -function nodeContainsPosition(node, position) { - return containsPosition(node.loc, position); -} - -/***/ }), +/* 1127 */, /* 1128 */ /***/ (function(module, exports, __webpack_require__) { @@ -41027,7 +40508,7 @@ function inToolbox() { } if (!inToolbox()) { - __webpack_require__(854); + __webpack_require__(1224); } function createPopup(doc) { @@ -41698,93 +41179,7 @@ function createSyncData(pendingBreakpoint, location, generatedLocation) { } /***/ }), -/* 1138 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = buildQuery; - -var _escapeRegExp = __webpack_require__(259); - -var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Ignore doing outline matches for less than 3 whitespaces - * - * @memberof utils/source-search - * @static - */ -function ignoreWhiteSpace(str) { - return (/^\s{0,2}$/.test(str) ? "(?!\\s*.*)" : str - ); -} - - -function wholeMatch(query, wholeWord) { - if (query === "" || !wholeWord) { - return query; - } - - return `\\b${query}\\b`; -} - -function buildFlags(caseSensitive, isGlobal) { - if (caseSensitive && isGlobal) { - return "g"; - } - - if (!caseSensitive && isGlobal) { - return "gi"; - } - - if (!caseSensitive && !isGlobal) { - return "i"; - } - - return; -} - -function buildQuery(originalQuery, modifiers, _ref) { - var _ref$isGlobal = _ref.isGlobal, - isGlobal = _ref$isGlobal === undefined ? false : _ref$isGlobal, - _ref$ignoreSpaces = _ref.ignoreSpaces, - ignoreSpaces = _ref$ignoreSpaces === undefined ? false : _ref$ignoreSpaces; - var caseSensitive = modifiers.caseSensitive, - regexMatch = modifiers.regexMatch, - wholeWord = modifiers.wholeWord; - - - if (originalQuery === "") { - return new RegExp(originalQuery); - } - - var query = originalQuery; - if (ignoreSpaces) { - query = ignoreWhiteSpace(query); - } - - if (!regexMatch) { - query = (0, _escapeRegExp2.default)(query); - } - - query = wholeMatch(query, wholeWord); - var flags = buildFlags(caseSensitive, isGlobal); - - if (flags) { - return new RegExp(query, flags); - } - - return new RegExp(query); -} - -/***/ }), +/* 1138 */, /* 1139 */ /***/ (function(module, exports, __webpack_require__) { @@ -41795,6 +41190,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -41823,7 +41222,7 @@ var _prefs = __webpack_require__(226); var _selectors = __webpack_require__(242); -__webpack_require__(869); +__webpack_require__(1242); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -41950,21 +41349,21 @@ class ProjectSearch extends _react.Component { } ProjectSearch.propTypes = { - sources: _react.PropTypes.object.isRequired, - results: _react.PropTypes.object, - textSearchQuery: _react.PropTypes.string, - setActiveSearch: _react.PropTypes.func.isRequired, - closeActiveSearch: _react.PropTypes.func.isRequired, - searchSources: _react.PropTypes.func, - activeSearch: _react.PropTypes.string, - selectSource: _react.PropTypes.func.isRequired, - sourceSearchQuery: _react.PropTypes.string, - setSourceSearchQuery: _react.PropTypes.func, - clearSourceSearchQuery: _react.PropTypes.func + sources: _propTypes2.default.object.isRequired, + results: _propTypes2.default.object, + textSearchQuery: _propTypes2.default.string, + setActiveSearch: _propTypes2.default.func.isRequired, + closeActiveSearch: _propTypes2.default.func.isRequired, + searchSources: _propTypes2.default.func, + activeSearch: _propTypes2.default.string, + selectSource: _propTypes2.default.func.isRequired, + sourceSearchQuery: _propTypes2.default.string, + setSourceSearchQuery: _propTypes2.default.func, + clearSourceSearchQuery: _propTypes2.default.func }; ProjectSearch.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; exports.default = (0, _reactRedux.connect)(state => ({ @@ -41987,6 +41386,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -42038,7 +41441,7 @@ class SourceSearch extends _react.Component { exports.default = SourceSearch; SourceSearch.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; /***/ }), @@ -42070,7 +41473,7 @@ var _selectors = __webpack_require__(242); var _devtoolsConfig = __webpack_require__(828); -__webpack_require__(870); +__webpack_require__(1243); var _classnames = __webpack_require__(175); @@ -42316,7 +41719,7 @@ var _actions2 = _interopRequireDefault(_actions); var _selectors = __webpack_require__(242); -__webpack_require__(871); +__webpack_require__(1244); var _PreviewFunction = __webpack_require__(798); @@ -42418,7 +41821,7 @@ var _actions2 = _interopRequireDefault(_actions); var _selectors = __webpack_require__(242); -__webpack_require__(1161); +__webpack_require__(1256); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -42489,6 +41892,10 @@ var _redux = __webpack_require__(3); var _reactRedux = __webpack_require__(1189); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -42611,8 +42018,7 @@ class SourcesTree extends _react.Component { for (var source of newSet) { (0, _sourcesTree.addToTree)(uncollapsedTree, source, this.props.debuggeeUrl); } - var unsortedTree = (0, _sourcesTree.collapseTree)(uncollapsedTree); - sourceTree = (0, _sourcesTree.sortEntireTree)(unsortedTree, nextProps.debuggeeUrl); + sourceTree = (0, _sourcesTree.collapseTree)(uncollapsedTree); } this.setState({ @@ -42633,7 +42039,7 @@ class SourcesTree extends _react.Component { } getIcon(item, depth) { - if (item.path === "/webpack://") { + if (item.path === "/Webpack") { return _react2.default.createElement(_Svg2.default, { name: "webpack" }); } @@ -42676,17 +42082,16 @@ class SourcesTree extends _react.Component { renderItem(item, depth, focused, _, expanded, _ref) { var setExpanded = _ref.setExpanded; - var arrow = _react2.default.createElement(_Svg2.default, { + var arrow = (0, _sourcesTree.nodeHasChildren)(item) ? _react2.default.createElement(_Svg2.default, { name: "arrow", className: (0, _classnames2.default)({ - expanded: expanded, - hidden: !(0, _sourcesTree.nodeHasChildren)(item) + expanded: expanded }), onClick: e => { e.stopPropagation(); setExpanded(item, !expanded); } - }); + }) : _react2.default.createElement("i", { className: "no-arrow" }); var icon = this.getIcon(item, depth); var paddingDir = "paddingRight"; @@ -42698,7 +42103,7 @@ class SourcesTree extends _react.Component { "div", { className: (0, _classnames2.default)("node", { focused }), - style: { [paddingDir]: `${depth * 15}px` }, + style: { [paddingDir]: `${depth * 15 + 5}px` }, key: item.path, onClick: () => { this.selectItem(item); @@ -42775,12 +42180,12 @@ class SourcesTree extends _react.Component { SourcesTree.propTypes = { sources: _reactImmutableProptypes2.default.map.isRequired, - selectSource: _react.PropTypes.func.isRequired, - shownSource: _react.PropTypes.string, + selectSource: _propTypes2.default.func.isRequired, + shownSource: _propTypes2.default.string, selectedSource: _reactImmutableProptypes2.default.map, - debuggeeUrl: _react.PropTypes.string.isRequired, - setExpandedState: _react.PropTypes.func, - expanded: _react.PropTypes.any + debuggeeUrl: _propTypes2.default.string.isRequired, + setExpandedState: _propTypes2.default.func, + expanded: _propTypes2.default.any }; exports.default = (0, _reactRedux.connect)(state => { @@ -42808,7 +42213,7 @@ var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); -__webpack_require__(1162); +__webpack_require__(1265); var _reactRedux = __webpack_require__(1189); @@ -42922,7 +42327,7 @@ var _require = __webpack_require__(0), PropTypes = _require.PropTypes; var Tree = createFactory(__webpack_require__(1007).Tree); -__webpack_require__(878); +__webpack_require__(1251); var classnames = __webpack_require__(175); var Svg = __webpack_require__(1151); @@ -44109,18 +43514,8 @@ exports.default = (0, _reactRedux.connect)(state => { /***/ }), /* 1160 */, -/* 1161 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), -/* 1162 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin - -/***/ }), +/* 1161 */, +/* 1162 */, /* 1163 */, /* 1164 */, /* 1165 */ @@ -44174,37 +43569,34 @@ var _react = __webpack_require__(0); var _editor = __webpack_require__(257); -__webpack_require__(882); +__webpack_require__(1255); class CallSite extends _react.Component { constructor() { super(); + this.addCallSite = nextProps => { + var _ref = nextProps || this.props, + editor = _ref.editor, + callSite = _ref.callSite, + breakpoint = _ref.breakpoint, + source = _ref.source; + + var className = !breakpoint ? "call-site" : "call-site-bp"; + var sourceId = source.get("id"); + var editorRange = (0, _editor.toEditorRange)(sourceId, callSite.location); + this.marker = (0, _editor.markText)(editor, className, editorRange); + }; + + this.clearCallSite = () => { + if (this.marker) { + this.marker.clear(); + this.marker = null; + } + }; + this.marker = undefined; - var self = this; - self.addCallSite = this.addCallSite.bind(this); - self.clearCallSite = this.clearCallSite.bind(this); - } - - addCallSite(nextProps) { - var _ref = nextProps || this.props, - editor = _ref.editor, - callSite = _ref.callSite, - breakpoint = _ref.breakpoint, - source = _ref.source; - - var className = !breakpoint ? "call-site" : "call-site-bp"; - var sourceId = source.get("id"); - var editorRange = (0, _editor.toEditorRange)(sourceId, callSite.location); - this.marker = (0, _editor.markText)(editor, className, editorRange); - } - - clearCallSite() { - if (this.marker) { - this.marker.clear(); - this.marker = null; - } } shouldComponentUpdate(nextProps) { @@ -44411,20 +43803,10 @@ exports.findFunctionText = findFunctionText; var _astBreakpointLocation = __webpack_require__(804); +var _indentation = __webpack_require__(1214); + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } -function getIndentation(lines) { - var firstLine = lines[0]; - var secondLine = lines[1]; - var lastLine = lines[lines.length - 1]; - - var _getIndentation = line => line && line.match(/^\s*/)[0].length; - - var indentations = [_getIndentation(firstLine), _getIndentation(secondLine), _getIndentation(lastLine)]; - - return Math.max.apply(Math, indentations.concat([0])); -} - function findFunctionText(line, source, symbols) { var func = (0, _astBreakpointLocation.findClosestScope)(symbols.functions, { line, column: Infinity }); if (!func) { @@ -44439,12 +43821,10 @@ function findFunctionText(line, source, symbols) { var firstLine = lines[start.line - 1].slice(start.column); var lastLine = lines[end.line - 1].slice(0, end.column); var middle = lines.slice(start.line, end.line - 1); - var functionLines = [firstLine].concat(_toConsumableArray(middle), [lastLine]); + var functionText = [firstLine].concat(_toConsumableArray(middle), [lastLine]).join("\n"); + var indentedFunctionText = (0, _indentation.correctIndentation)(functionText); - var indentation = getIndentation(functionLines); - var formattedLines = functionLines.map(_line => _line.replace(new RegExp(`^\\s{0,${indentation - 1}}`), "")); - - return formattedLines.join("\n").trim(); + return indentedFunctionText; } /***/ }), @@ -44458,6 +43838,10 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _propTypes = __webpack_require__(20); + +var _propTypes2 = _interopRequireDefault(_propTypes); + var _react = __webpack_require__(0); var _react2 = _interopRequireDefault(_react); @@ -44488,7 +43872,7 @@ var _ResultList = __webpack_require__(383); var _ResultList2 = _interopRequireDefault(_ResultList); -__webpack_require__(962); +__webpack_require__(1271); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -44506,19 +43890,141 @@ class SymbolModal extends _react.Component { constructor(props) { super(props); - this.state = { results: null, query: "", resultsIndex: 0 }; - var self = this; - self.onClick = this.onClick.bind(this); - self.closeModal = this.closeModal.bind(this); - self.onChange = this.onChange.bind(this); - self.onKeyUp = this.onKeyUp.bind(this); - self.updateResults = this.updateResults.bind(this); - self.traverseResults = this.traverseResults.bind(this); - self.renderResults = this.renderResults.bind(this); - self.buildSummaryMsg = this.buildSummaryMsg.bind(this); - self.buildPlaceHolder = this.buildPlaceHolder.bind(this); - self.selectResultItem = this.selectResultItem.bind(this); + this.onClick = e => { + e.stopPropagation(); + }; + + this.onChange = e => { + var selectedSource = this.props.selectedSource; + + if (!selectedSource || !selectedSource.get("text")) { + return; + } + + this.setState({ query: e.target.value }); + return this.updateResults(e.target.value); + }; + + this.closeModal = () => { + this.props.closeActiveSearch(); + this.props.clearHighlightLineRange(); + }; + + this.selectResultItem = (e, item) => { + var _props = this.props, + selectSource = _props.selectSource, + selectedSource = _props.selectedSource; + + + if (!selectedSource || !item) { + return; + } + + selectSource(selectedSource.get("id"), { + line: item.location.start.line + }); + + this.closeModal(); + }; + + this.updateResults = query => { + var _props2 = this.props, + symbolType = _props2.symbolType, + symbols = _props2.symbols; + + + var symbolSearchResults = symbols[symbolType]; + if (query == "") { + this.setState({ results: symbolSearchResults }); + return; + } + + symbolSearchResults = (0, _fuzzaldrinPlus.filter)(symbolSearchResults, query, { + key: "value" + }); + + this.setState({ results: symbolSearchResults }); + }; + + this.traverseResults = direction => { + var _state = this.state, + resultsIndex = _state.resultsIndex, + results = _state.results; + + var resultCount = this.resultsCount(); + var index = resultsIndex + direction; + var nextIndex = (index + resultCount) % resultCount; + + this.setState({ resultsIndex: nextIndex }); + + if (results) { + this.onSelectResultItem(results[nextIndex]); + } + }; + + this.onKeyUp = e => { + e.preventDefault(); + var enabled = this.props.enabled; + var _state2 = this.state, + results = _state2.results, + resultsIndex = _state2.resultsIndex; + + + if (!enabled || !results) { + return; + } + + if (e.key === "ArrowUp") { + this.traverseResults(-1); + } else if (e.key === "ArrowDown") { + this.traverseResults(1); + } else if (e.key === "Enter") { + this.selectResultItem(e, results[resultsIndex]); + this.closeModal(); + } else if (e.key === "Tab") { + this.closeModal(); + } + }; + + this.renderResults = () => { + var _state3 = this.state, + resultsIndex = _state3.resultsIndex, + results = _state3.results; + var enabled = this.props.enabled; + + if (!enabled || !results) { + return null; + } + + return _react2.default.createElement(_ResultList2.default, { + key: "results", + items: results, + selected: resultsIndex, + selectItem: this.selectResultItem, + ref: "resultList" + }); + }; + + this.buildSummaryMsg = () => { + var resultsIndex = this.state.resultsIndex; + + var count = this.resultsCount(); + + if (count > 1) { + return L10N.getFormatStr("editor.searchResults", resultsIndex + 1, count); + } else if (count === 1) { + return L10N.getFormatStr("editor.singleResult"); + } + }; + + this.buildPlaceHolder = () => { + var symbolType = this.props.symbolType; + + return L10N.getFormatStr(`symbolSearch.search.${symbolType}Placeholder`); + }; + + this.state = { results: null, query: "", resultsIndex: 0 }; } componentDidMount() { @@ -44535,78 +44041,6 @@ class SymbolModal extends _react.Component { } } - onClick(e) { - e.stopPropagation(); - } - - onChange(e) { - var selectedSource = this.props.selectedSource; - - if (!selectedSource || !selectedSource.get("text")) { - return; - } - - this.setState({ query: e.target.value }); - return this.updateResults(e.target.value); - } - - closeModal() { - this.props.closeActiveSearch(); - this.props.clearHighlightLineRange(); - } - - selectResultItem(e, item) { - var _props = this.props, - selectSource = _props.selectSource, - selectedSource = _props.selectedSource; - - - if (!selectedSource || !item) { - return; - } - - selectSource(selectedSource.get("id"), { - line: item.location.start.line - }); - - this.closeModal(); - } - - updateResults(query) { - var _props2 = this.props, - symbolType = _props2.symbolType, - symbols = _props2.symbols; - - - var symbolSearchResults = symbols[symbolType]; - if (query == "") { - this.setState({ results: symbolSearchResults }); - return; - } - - symbolSearchResults = (0, _fuzzaldrinPlus.filter)(symbolSearchResults, query, { - key: "value" - }); - - this.setState({ results: symbolSearchResults }); - } - - traverseResults(direction) { - var _state = this.state, - resultsIndex = _state.resultsIndex, - results = _state.results; - - var resultCount = this.resultsCount(); - var index = resultsIndex + direction; - var nextIndex = (index + resultCount) % resultCount; - - this.setState({ resultsIndex: nextIndex }); - - if (results) { - this.onSelectResultItem(results[nextIndex]); - } - } - onSelectResultItem(item) { var _props3 = this.props, selectSource = _props3.selectSource, @@ -44630,49 +44064,6 @@ class SymbolModal extends _react.Component { } } - onKeyUp(e) { - e.preventDefault(); - var enabled = this.props.enabled; - var _state2 = this.state, - results = _state2.results, - resultsIndex = _state2.resultsIndex; - - - if (!enabled || !results) { - return; - } - - if (e.key === "ArrowUp") { - this.traverseResults(-1); - } else if (e.key === "ArrowDown") { - this.traverseResults(1); - } else if (e.key === "Enter") { - this.selectResultItem(e, results[resultsIndex]); - this.closeModal(); - } else if (e.key === "Tab") { - this.closeModal(); - } - } - - renderResults() { - var _state3 = this.state, - resultsIndex = _state3.resultsIndex, - results = _state3.results; - var enabled = this.props.enabled; - - if (!enabled || !results) { - return null; - } - - return _react2.default.createElement(_ResultList2.default, { - key: "results", - items: results, - selected: resultsIndex, - selectItem: this.selectResultItem, - ref: "resultList" - }); - } - renderInput() { var query = this.state.query; @@ -44694,28 +44085,10 @@ class SymbolModal extends _react.Component { ); } - buildSummaryMsg() { - var resultsIndex = this.state.resultsIndex; - - var count = this.resultsCount(); - - if (count > 1) { - return L10N.getFormatStr("editor.searchResults", resultsIndex + 1, count); - } else if (count === 1) { - return L10N.getFormatStr("editor.singleResult"); - } - } - resultsCount() { return this.state.results ? this.state.results.length : 0; } - buildPlaceHolder() { - var symbolType = this.props.symbolType; - - return L10N.getFormatStr(`symbolSearch.search.${symbolType}Placeholder`); - } - render() { var enabled = this.props.enabled; @@ -44734,7 +44107,7 @@ class SymbolModal extends _react.Component { } SymbolModal.contextTypes = { - shortcuts: _react.PropTypes.object + shortcuts: _propTypes2.default.object }; function _getFormattedSymbols(state, source) { @@ -44954,6 +44327,7 @@ exports.sanitizeInput = sanitizeInput; exports.wrapExpression = wrapExpression; exports.getValue = getValue; +var _indentation = __webpack_require__(1214); // replace quotes and slashes that could interfere with the evaluation. function sanitizeInput(input) { @@ -44969,13 +44343,13 @@ function sanitizeInput(input) { function wrapExpression(input) { - return `eval(\` + return (0, _indentation.correctIndentation)(` try { ${sanitizeInput(input)} } catch (e) { e } - \`)`.trim(); + `); } function getValue(expression) { @@ -45134,7 +44508,7 @@ var _classnames2 = _interopRequireDefault(_classnames); var _text = __webpack_require__(389); -__webpack_require__(1182); +__webpack_require__(1227); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -45254,17 +44628,10 @@ class ShortcutsModal extends _react.Component { ); } } - exports.ShortcutsModal = ShortcutsModal; -ShortcutsModal.displayName = "ShortcutsModal"; - -/***/ }), -/* 1182 */ -/***/ (function(module, exports) { - -// removed by extract-text-webpack-plugin /***/ }), +/* 1182 */, /* 1183 */ /***/ (function(module, exports) { @@ -45341,7 +44708,7 @@ var _Svg = __webpack_require__(344); var _Svg2 = _interopRequireDefault(_Svg); -__webpack_require__(918); +__webpack_require__(1215); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -45366,7 +44733,7 @@ function debugBtn(onClick, type, className, tooltip) { class UtilsBar extends _react.Component { renderUtilButtons() { - return [debugBtn(this.props.toggleShortcutsModal, "shortcut", "active", "shortcuts", false)]; + return [debugBtn(this.props.toggleShortcutsModal, "shortcut", "active", L10N.getStr("shortcuts.buttonName"), false)]; } render() { @@ -46749,6 +46116,687 @@ function replaceOriginalVariableName(expression, generatedScopes) { module.exports = { replaceOriginalVariableName }; +/***/ }), +/* 1207 */, +/* 1208 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.hasSyntaxError = exports.clearSources = exports.setSource = exports.hasSource = exports.getEmptyLines = exports.getNextStep = exports.clearASTs = exports.clearScopes = exports.clearSymbols = exports.getOutOfScopeLocations = exports.getVariablesInScope = exports.getScopes = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined; + +var _devtoolsUtils = __webpack_require__(900); + +var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; + + +var dispatcher = new WorkerDispatcher(); +var startParserWorker = exports.startParserWorker = dispatcher.start.bind(dispatcher); +var stopParserWorker = exports.stopParserWorker = dispatcher.stop.bind(dispatcher); + +var getClosestExpression = exports.getClosestExpression = dispatcher.task("getClosestExpression"); +var getSymbols = exports.getSymbols = dispatcher.task("getSymbols"); +var getScopes = exports.getScopes = dispatcher.task("getScopes"); +var getVariablesInScope = exports.getVariablesInScope = dispatcher.task("getVariablesInScope"); +var getOutOfScopeLocations = exports.getOutOfScopeLocations = dispatcher.task("getOutOfScopeLocations"); +var clearSymbols = exports.clearSymbols = dispatcher.task("clearSymbols"); +var clearScopes = exports.clearScopes = dispatcher.task("clearScopes"); +var clearASTs = exports.clearASTs = dispatcher.task("clearASTs"); +var getNextStep = exports.getNextStep = dispatcher.task("getNextStep"); +var getEmptyLines = exports.getEmptyLines = dispatcher.task("getEmptyLines"); +var hasSource = exports.hasSource = dispatcher.task("hasSource"); +var setSource = exports.setSource = dispatcher.task("setSource"); +var clearSources = exports.clearSources = dispatcher.task("clearSources"); +var hasSyntaxError = exports.hasSyntaxError = dispatcher.task("hasSyntaxError"); + +/***/ }), +/* 1209 */, +/* 1210 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.findSourceMatches = exports.searchSources = exports.getMatches = exports.stopSearchWorker = exports.startSearchWorker = undefined; + +var _devtoolsUtils = __webpack_require__(900); + +var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; + + +var dispatcher = new WorkerDispatcher(); +var startSearchWorker = exports.startSearchWorker = dispatcher.start.bind(dispatcher); +var stopSearchWorker = exports.stopSearchWorker = dispatcher.stop.bind(dispatcher); + +var getMatches = exports.getMatches = dispatcher.task("getMatches"); +var searchSources = exports.searchSources = dispatcher.task("searchSources"); +var findSourceMatches = exports.findSourceMatches = dispatcher.task("findSourceMatches"); + +/***/ }), +/* 1211 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = buildQuery; + +var _escapeRegExp = __webpack_require__(259); + +var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Ignore doing outline matches for less than 3 whitespaces + * + * @memberof utils/source-search + * @static + */ +function ignoreWhiteSpace(str) { + return (/^\s{0,2}$/.test(str) ? "(?!\\s*.*)" : str + ); +} + + +function wholeMatch(query, wholeWord) { + if (query === "" || !wholeWord) { + return query; + } + + return `\\b${query}\\b`; +} + +function buildFlags(caseSensitive, isGlobal) { + if (caseSensitive && isGlobal) { + return "g"; + } + + if (!caseSensitive && isGlobal) { + return "gi"; + } + + if (!caseSensitive && !isGlobal) { + return "i"; + } + + return; +} + +function buildQuery(originalQuery, modifiers, _ref) { + var _ref$isGlobal = _ref.isGlobal, + isGlobal = _ref$isGlobal === undefined ? false : _ref$isGlobal, + _ref$ignoreSpaces = _ref.ignoreSpaces, + ignoreSpaces = _ref$ignoreSpaces === undefined ? false : _ref$ignoreSpaces; + var caseSensitive = modifiers.caseSensitive, + regexMatch = modifiers.regexMatch, + wholeWord = modifiers.wholeWord; + + + if (originalQuery === "") { + return new RegExp(originalQuery); + } + + var query = originalQuery; + if (ignoreSpaces) { + query = ignoreWhiteSpace(query); + } + + if (!regexMatch) { + query = (0, _escapeRegExp2.default)(query); + } + + query = wholeMatch(query, wholeWord); + var flags = buildFlags(caseSensitive, isGlobal); + + if (flags) { + return new RegExp(query, flags); + } + + return new RegExp(query); +} + +/***/ }), +/* 1212 */, +/* 1213 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.prettyPrint = exports.stopPrettyPrintWorker = exports.startPrettyPrintWorker = undefined; + +var prettyPrint = exports.prettyPrint = (() => { + var _ref = _asyncToGenerator(function* (_ref2) { + var source = _ref2.source, + url = _ref2.url; + + var indent = 2; + + (0, _assert2.default)((0, _source.isJavaScript)(source), "Can't prettify non-javascript files."); + + return yield _prettyPrint({ + url, + indent, + source: source.text + }); + }); + + return function prettyPrint(_x) { + return _ref.apply(this, arguments); + }; +})(); + +var _devtoolsUtils = __webpack_require__(900); + +var _source = __webpack_require__(233); + +var _assert = __webpack_require__(223); + +var _assert2 = _interopRequireDefault(_assert); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher; + + +var dispatcher = new WorkerDispatcher(); +var startPrettyPrintWorker = exports.startPrettyPrintWorker = dispatcher.start.bind(dispatcher); +var stopPrettyPrintWorker = exports.stopPrettyPrintWorker = dispatcher.stop.bind(dispatcher); +var _prettyPrint = dispatcher.task("prettyPrint"); + +/***/ }), +/* 1214 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.correctIndentation = correctIndentation; +function getIndentation(lines) { + var firstLine = lines[0]; + var secondLine = lines[1]; + var lastLine = lines[lines.length - 1]; + + var _getIndentation = line => line && line.match(/^\s*/)[0].length; + + var indentations = [_getIndentation(firstLine), _getIndentation(secondLine), _getIndentation(lastLine)]; + + return Math.max.apply(Math, indentations); +} + +function correctIndentation(text) { + var lines = text.trim().split("\n"); + var indentation = getIndentation(lines); + var formattedLines = lines.map(_line => _line.replace(new RegExp(`^\\s{0,${indentation - 1}}`), "")); + + return formattedLines.join("\n"); +} + +/***/ }), +/* 1215 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1216 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1217 */, +/* 1218 */, +/* 1219 */, +/* 1220 */, +/* 1221 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1222 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1223 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1224 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1225 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1226 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1227 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1228 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1229 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1230 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1231 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1232 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1233 */ +/***/ (function(module, exports) { + +module.exports = "" + +/***/ }), +/* 1234 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1235 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1236 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1237 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1238 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1239 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getDomain = getDomain; +exports.findNodeInContents = findNodeInContents; +exports.createTreeNodeMatcher = createTreeNodeMatcher; + +var _url = __webpack_require__(334); + +var _utils = __webpack_require__(18); + +/* + * Gets domain from url (without www prefix) + */ +function getDomain(url) { + var _parse = (0, _url.parse)(url), + host = _parse.host; + + if (!host) { + return null; + } + return host.startsWith("www.") ? host.substr("www.".length) : host; +} + +/* + * Checks if node name matches debugger host/domain. + */ +function isExactDomainMatch(part, debuggeeHost) { + return part.startsWith("www.") ? part.substr("www.".length) === debuggeeHost : part === debuggeeHost; +} + +/* + * Function to assist with node search for a defined sorted order, see e.g. + * `createTreeNodeMatcher`. Returns negative number if the node + * stands earlier in sorting order, positive number if the node stands later + * in sorting order, or zero if the node is found. + */ + + +/* + * Performs a binary search to insert a node into contents. Returns positive + * number, index of the found child, or negative number, which can be used + * to calculate a position where a new node can be inserted (`-index - 1`). + * The matcher is a function that returns result of comparision of a node with + * lookup value. + */ +function findNodeInContents(tree, matcher) { + var contents = tree.contents; + + if (contents.length === 0) { + return { found: false, index: 0 }; + } + var left = 0; + var right = contents.length - 1; + while (left < right) { + var middle = Math.floor((left + right) / 2); + if (matcher(contents[middle]) < 0) { + left = middle + 1; + } else { + right = middle; + } + } + var result = matcher(contents[left]); + if (result === 0) { + return { found: true, index: left }; + } + return { found: false, index: result > 0 ? left : left + 1 }; +} + +var IndexName = "(index)"; + +function createTreeNodeMatcherWithIndex() { + return node => node.name === IndexName ? 0 : 1; +} + +function createTreeNodeMatcherWithDebuggeeHost(debuggeeHost) { + return node => { + if (node.name === IndexName) { + return -1; + } + return isExactDomainMatch(node.name, debuggeeHost) ? 0 : 1; + }; +} + +function createTreeNodeMatcherWithNameAndOther(part, isDir, debuggeeHost) { + return node => { + if (node.name === IndexName) { + return -1; + } + if (debuggeeHost && isExactDomainMatch(node.name, debuggeeHost)) { + return -1; + } + var nodeIsDir = (0, _utils.nodeHasChildren)(node); + if (nodeIsDir && !isDir) { + return -1; + } else if (!nodeIsDir && isDir) { + return 1; + } + return node.name.localeCompare(part); + }; +} + +/* + * Creates a matcher for findNodeInContents. + * The sorting order of nodes during comparison is: + * - "(index)" node + * - root node with the debuggee host/domain + * - hosts/directories (not files) sorted by name + * - files sorted by name + */ +function createTreeNodeMatcher(part, isDir, debuggeeHost) { + if (part === IndexName) { + // Specialied matcher, when we are looking for "(index)" position. + return createTreeNodeMatcherWithIndex(); + } + if (debuggeeHost && isExactDomainMatch(part, debuggeeHost)) { + // Specialied matcher, when we are looking for domain position. + return createTreeNodeMatcherWithDebuggeeHost(debuggeeHost); + } + // Rest of the cases, without mentioned above. + return createTreeNodeMatcherWithNameAndOther(part, isDir, debuggeeHost); +} + +/***/ }), +/* 1240 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1241 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1242 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1243 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1244 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1245 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1246 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1247 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1248 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1249 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1250 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1251 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1252 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1253 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1254 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1255 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1256 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1257 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1258 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1259 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1260 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1261 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1262 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1263 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1264 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1265 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1266 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1267 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1268 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1269 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1270 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 1271 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + /***/ }) /******/ ]); }); \ No newline at end of file diff --git a/devtools/client/debugger/new/parser-worker.js b/devtools/client/debugger/new/parser-worker.js index 7eeeffbba271..a217da70f4bb 100644 --- a/devtools/client/debugger/new/parser-worker.js +++ b/devtools/client/debugger/new/parser-worker.js @@ -70,7 +70,7 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 339); +/******/ return __webpack_require__(__webpack_require__.s = 1272); /******/ }) /************************************************************************/ /******/ ([ @@ -3849,13 +3849,7 @@ module.exports = toNumber; /* 336 */, /* 337 */, /* 338 */, -/* 339 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(961); - - -/***/ }), +/* 339 */, /* 340 */ /***/ (function(module, exports, __webpack_require__) { @@ -28470,63 +28464,7 @@ module.exports = basePropertyDeep; /***/ }), -/* 842 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -exports.getNextStep = getNextStep; - -var _debuggerHtml = __webpack_require__(843); - -var _types = __webpack_require__(844); - -var _closest = __webpack_require__(1055); - -var _helpers = __webpack_require__(1052); - -function getNextStep(source, pausedPosition) { - var awaitExpression = getAwaitExpression(source, pausedPosition); - if (!awaitExpression) { - return null; - } - var awaitStatement = awaitExpression.getStatementParent(); - return getLocationAfterAwaitExpression(awaitStatement, pausedPosition); -} - -function getAwaitExpression(source, pausedPosition) { - var closestPath = (0, _closest.getClosestPath)(source, pausedPosition); - - if (!closestPath) { - return null; - } - - if ((0, _helpers.isAwaitExpression)(closestPath)) { - return closestPath; - } - - return closestPath.find(p => p.isAwaitExpression()); -} - -function getLocationAfterAwaitExpression(statement, position) { - var nextStatement = statement.getSibling(statement.key + 1); - if (nextStatement.node) { - return _extends({}, nextStatement.node.loc.start, { - sourceId: position.sourceId - }); - } - - return null; -} - -/***/ }), +/* 842 */, /* 843 */ /***/ (function(module, exports, __webpack_require__) { @@ -28534,72 +28472,8 @@ function getLocationAfterAwaitExpression(statement, position) { /***/ }), -/* 844 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/***/ }), -/* 845 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = getEmptyLines; - -var _uniq = __webpack_require__(561); - -var _uniq2 = _interopRequireDefault(_uniq); - -var _difference = __webpack_require__(1129); - -var _difference2 = _interopRequireDefault(_difference); - -var _ast = __webpack_require__(1051); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var commentTokens = ["CommentBlock", "CommentLine"]; - -function fillRange(start, end) { - return Array(end - start + 1).fill().map((item, index) => start + index); -} - -// Populates a pre-filled array of every line number, -// then removes lines which were found to be executable -function getLines(ast) { - return fillRange(0, ast.tokens[ast.tokens.length - 1].loc.end.line); -} - -// The following sequence stores lines which have executable code -// (contents other than comments or EOF, regardless of line position) -function getExecutableLines(ast) { - var lines = ast.tokens.filter(token => !commentTokens.includes(token.type) && (!token.type || token.type.label && token.type.label != "eof")).map(token => token.loc.start.line - 1); - - return (0, _uniq2.default)(lines); -} - -function getEmptyLines(sourceToJS) { - if (!sourceToJS) { - return null; - } - - var ast = (0, _ast.getAst)(sourceToJS); - if (!ast || !ast.comments) { - return []; - } - - var executableLines = getExecutableLines(ast); - var lines = getLines(ast); - return (0, _difference2.default)(lines, executableLines); -} - -/***/ }), +/* 844 */, +/* 845 */, /* 846 */, /* 847 */, /* 848 */, @@ -28887,65 +28761,7 @@ module.exports = { /* 958 */, /* 959 */, /* 960 */, -/* 961 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _closest = __webpack_require__(1055); - -var _scopes = __webpack_require__(1049); - -var _getSymbols = __webpack_require__(1050); - -var _getSymbols2 = _interopRequireDefault(_getSymbols); - -var _ast = __webpack_require__(1051); - -var _getScopes = __webpack_require__(1186); - -var _getScopes2 = _interopRequireDefault(_getScopes); - -var _sources = __webpack_require__(1171); - -var _getOutOfScopeLocations = __webpack_require__(1072); - -var _getOutOfScopeLocations2 = _interopRequireDefault(_getOutOfScopeLocations); - -var _steps = __webpack_require__(842); - -var _getEmptyLines = __webpack_require__(845); - -var _getEmptyLines2 = _interopRequireDefault(_getEmptyLines); - -var _validate = __webpack_require__(1207); - -var _devtoolsUtils = __webpack_require__(900); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var workerHandler = _devtoolsUtils.workerUtils.workerHandler; - - -self.onmessage = workerHandler({ - getClosestExpression: _closest.getClosestExpression, - getOutOfScopeLocations: _getOutOfScopeLocations2.default, - getSymbols: _getSymbols2.default, - getScopes: _getScopes2.default, - clearSymbols: _getSymbols.clearSymbols, - clearScopes: _getScopes.clearScopes, - clearASTs: _ast.clearASTs, - hasSource: _sources.hasSource, - setSource: _sources.setSource, - clearSources: _sources.clearSources, - getVariablesInScope: _scopes.getVariablesInScope, - getNextStep: _steps.getNextStep, - getEmptyLines: _getEmptyLines2.default, - hasSyntaxError: _validate.hasSyntaxError -}); - -/***/ }), +/* 961 */, /* 962 */, /* 963 */ /***/ (function(module, exports, __webpack_require__) { @@ -29260,787 +29076,13 @@ exports.parseScriptTags = parseScriptTags; /* 1046 */, /* 1047 */, /* 1048 */, -/* 1049 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); - -exports.getVariablesInLocalScope = getVariablesInLocalScope; -exports.getVariablesInScope = getVariablesInScope; -exports.isExpressionInScope = isExpressionInScope; - -var _toPairs = __webpack_require__(795); - -var _toPairs2 = _interopRequireDefault(_toPairs); - -var _uniq = __webpack_require__(561); - -var _uniq2 = _interopRequireDefault(_uniq); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function getScopeVariables(scope) { - var bindings = scope.bindings; - - - return (0, _toPairs2.default)(bindings).map((_ref) => { - var _ref2 = _slicedToArray(_ref, 2), - name = _ref2[0], - binding = _ref2[1]; - - return { - name, - references: binding.referencePaths - }; - }); -} - -function getScopeChain(scope) { - var scopes = []; - - do { - scopes.push(scope); - } while (scope = scope.parent); - - return scopes; -} - -function getVariablesInLocalScope(scope) { - return getScopeVariables(scope); -} - -function getVariablesInScope(scope) { - var _ref3; - - var scopes = getScopeChain(scope); - var scopeVars = scopes.map(getScopeVariables); - var vars = (_ref3 = [{ name: "this" }, { name: "arguments" }]).concat.apply(_ref3, _toConsumableArray(scopeVars)).map(variable => variable.name); - return (0, _uniq2.default)(vars); -} - -function isExpressionInScope(expression, scope) { - if (!scope) { - return false; - } - - var variables = getVariablesInScope(scope); - var firstPart = expression.split(/\./)[0]; - return variables.includes(firstPart); -} - -/***/ }), -/* 1050 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = getSymbols; -exports.formatSymbols = formatSymbols; -exports.clearSymbols = clearSymbols; - -var _ast = __webpack_require__(1051); - -var _helpers = __webpack_require__(1052); - -var _babelTypes = __webpack_require__(493); - -var t = _interopRequireWildcard(_babelTypes); - -var _getFunctionName = __webpack_require__(1053); - -var _getFunctionName2 = _interopRequireDefault(_getFunctionName); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -var symbolDeclarations = new Map(); - -function getFunctionParameterNames(path) { - return path.node.params.map(param => param.name); -} - -function getVariableNames(path) { - if (t.isObjectProperty(path) && !(0, _helpers.isFunction)(path.node.value)) { - return [{ - name: path.node.key.name, - location: path.node.loc - }]; - } - - if (!path.node.declarations) { - return path.node.params.map(dec => ({ - name: dec.name, - location: dec.loc - })); - } - - return path.node.declarations.map(dec => ({ - name: dec.id.name, - location: dec.loc - })); -} - -function getComments(ast) { - if (!ast || !ast.comments) { - return []; - } - return ast.comments.map(comment => ({ - name: comment.location, - location: comment.loc - })); -} - -function getClassName(path) { - var classDeclaration = path.findParent(_p => _p.isClassDeclaration()); - if (!classDeclaration) { - return null; - } - - return classDeclaration.node.id.name; -} - -function extractSymbols(source) { - var functions = []; - var variables = []; - var memberExpressions = []; - var callExpressions = []; - var objectProperties = []; - var identifiers = []; - - var ast = (0, _ast.traverseAst)(source, { - enter(path) { - if ((0, _helpers.isVariable)(path)) { - variables.push.apply(variables, _toConsumableArray(getVariableNames(path))); - } - - if ((0, _helpers.isFunction)(path)) { - functions.push({ - name: (0, _getFunctionName2.default)(path), - klass: getClassName(path), - location: path.node.loc, - parameterNames: getFunctionParameterNames(path), - identifier: path.node.id - }); - } - - if (t.isClassDeclaration(path)) { - variables.push({ - name: path.node.id.name, - location: path.node.loc - }); - } - - if (t.isObjectProperty(path)) { - var _path$node$key$loc = path.node.key.loc, - start = _path$node$key$loc.start, - end = _path$node$key$loc.end, - identifierName = _path$node$key$loc.identifierName; - - objectProperties.push({ - name: identifierName, - location: { start, end }, - expression: getSnippet(path) - }); - } - - if (t.isMemberExpression(path)) { - var _path$node$property$l = path.node.property.loc, - _start = _path$node$property$l.start, - _end = _path$node$property$l.end; - - memberExpressions.push({ - name: path.node.property.name, - location: { start: _start, end: _end }, - expressionLocation: path.node.loc, - expression: getSnippet(path) - }); - } - - if (t.isCallExpression(path)) { - var callee = path.node.callee; - if (!t.isMemberExpression(callee)) { - var _callee$loc = callee.loc, - _start2 = _callee$loc.start, - _end2 = _callee$loc.end, - _identifierName = _callee$loc.identifierName; - - callExpressions.push({ - name: _identifierName, - location: { start: _start2, end: _end2 } - }); - } - } - - if (t.isIdentifier(path)) { - var _path$node$loc = path.node.loc, - _start3 = _path$node$loc.start, - _end3 = _path$node$loc.end; - - - identifiers.push({ - name: path.node.name, - expression: path.node.name, - location: { start: _start3, end: _end3 } - }); - } - - if (t.isThisExpression(path.node)) { - var _path$node$loc2 = path.node.loc, - _start4 = _path$node$loc2.start, - _end4 = _path$node$loc2.end; - - identifiers.push({ - name: "this", - location: { start: _start4, end: _end4 }, - expressionLocation: path.node.loc, - expression: "this" - }); - } - - if (t.isVariableDeclarator(path)) { - var node = path.node.id; - var _path$node$loc3 = path.node.loc, - _start5 = _path$node$loc3.start, - _end5 = _path$node$loc3.end; - - - identifiers.push({ - name: node.name, - expression: node.name, - location: { start: _start5, end: _end5 } - }); - } - } - }); - - // comments are extracted separately from the AST - var comments = getComments(ast); - - return { - functions, - variables, - callExpressions, - memberExpressions, - objectProperties, - comments, - identifiers - }; -} - -function getSymbols(source) { - if (symbolDeclarations.has(source.id)) { - var _symbols = symbolDeclarations.get(source.id); - if (_symbols) { - return _symbols; - } - } - - var symbols = extractSymbols(source); - symbolDeclarations.set(source.id, symbols); - return symbols; -} - -function extendSnippet(name, expression, path, prevPath) { - var computed = path && path.node.computed; - var prevComputed = prevPath && prevPath.node.computed; - var prevArray = t.isArrayExpression(prevPath); - var array = t.isArrayExpression(path); - - if (expression === "") { - if (computed) { - return `[${name}]`; - } - return name; - } - - if (computed || array) { - if (prevComputed || prevArray) { - return `[${name}]${expression}`; - } - return `[${name}].${expression}`; - } - - if (prevComputed || prevArray) { - return `${name}${expression}`; - } - - return `${name}.${expression}`; -} - -function getMemberSnippet(node) { - var expression = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; - - if (t.isMemberExpression(node)) { - var _name = node.property.name; - - return getMemberSnippet(node.object, extendSnippet(_name, expression)); - } - - if (t.isCallExpression(node)) { - return ""; - } - - if (t.isThisExpression(node)) { - return `this.${expression}`; - } - - if (t.isIdentifier(node)) { - return `${node.name}.${expression}`; - } - - return expression; -} - -function getObjectSnippet(path, prevPath) { - var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ""; - - if (!path) { - return expression; - } - - var name = path.node.key.name; - - var extendedExpression = extendSnippet(name, expression, path, prevPath); - - var nextPrevPath = path; - var nextPath = path.parentPath && path.parentPath.parentPath; - - return getSnippet(nextPath, nextPrevPath, extendedExpression); -} - -function getArraySnippet(path, prevPath, expression) { - var index = prevPath.parentPath.key; - var extendedExpression = extendSnippet(index, expression, path, prevPath); - - var nextPrevPath = path; - var nextPath = path.parentPath && path.parentPath.parentPath; - - return getSnippet(nextPath, nextPrevPath, extendedExpression); -} - -function getSnippet(path, prevPath) { - var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ""; - - if (t.isVariableDeclaration(path)) { - var node = path.node.declarations[0]; - var _name2 = node.id.name; - return extendSnippet(_name2, expression, path, prevPath); - } - - if (t.isVariableDeclarator(path)) { - var _node = path.node.id; - if (t.isObjectPattern(_node)) { - return expression; - } - - var _name3 = _node.name; - var prop = extendSnippet(_name3, expression, path, prevPath); - return prop; - } - - if (t.isAssignmentExpression(path)) { - var _node2 = path.node.left; - var _name4 = t.isMemberExpression(_node2) ? getMemberSnippet(_node2) : _node2.name; - - var _prop = extendSnippet(_name4, expression, path, prevPath); - return _prop; - } - - if ((0, _helpers.isFunction)(path)) { - return expression; - } - - if (t.isIdentifier(path)) { - var _node3 = path.node; - return `${_node3.name}.${expression}`; - } - - if (t.isObjectProperty(path)) { - return getObjectSnippet(path, prevPath, expression); - } - - if (t.isObjectExpression(path)) { - var parentPath = prevPath && prevPath.parentPath; - return getObjectSnippet(parentPath, prevPath, expression); - } - - if (t.isMemberExpression(path)) { - return getMemberSnippet(path.node, expression); - } - - if (t.isArrayExpression(path)) { - return getArraySnippet(path, prevPath, expression); - } -} - -function formatSymbols(source) { - var symbols = getSymbols(source); - - function formatLocation(loc) { - if (!loc) { - return ""; - } - var start = loc.start, - end = loc.end; - - - var startLoc = `(${start.line}, ${start.column})`; - var endLoc = `(${end.line}, ${end.column})`; - return `[${startLoc}, ${endLoc}]`; - } - - function summarize(symbol) { - var loc = formatLocation(symbol.location); - var exprLoc = formatLocation(symbol.expressionLocation); - var params = symbol.parameterNames ? symbol.parameterNames.join(", ") : ""; - var expression = symbol.expression || ""; - var klass = symbol.klass || ""; - return `${loc} ${exprLoc} ${expression} ${symbol.name} ${params} ${klass}`; - } - - return Object.keys(symbols).map(name => `${name}:\n ${symbols[name].map(summarize).join("\n")}`); -} - -function clearSymbols() { - symbolDeclarations = new Map(); -} - -/***/ }), -/* 1051 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.parseExpression = parseExpression; -exports.getAst = getAst; -exports.clearASTs = clearASTs; -exports.traverseAst = traverseAst; - -var _parseScriptTags = __webpack_require__(1023); - -var _parseScriptTags2 = _interopRequireDefault(_parseScriptTags); - -var _babylon = __webpack_require__(435); - -var babylon = _interopRequireWildcard(_babylon); - -var _babelTraverse = __webpack_require__(436); - -var _babelTraverse2 = _interopRequireDefault(_babelTraverse); - -var _isEmpty = __webpack_require__(963); - -var _isEmpty2 = _interopRequireDefault(_isEmpty); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var ASTs = new Map(); - -function _parse(code, opts) { - return babylon.parse(code, Object.assign({}, opts, { - sourceType: "module", - plugins: ["jsx", "flow", "objectRestSpread"] - })); -} - -function parse(text, opts) { - var ast = void 0; - if (!text) { - return; - } - - try { - ast = _parse(text, opts); - } catch (error) { - ast = {}; - } - - return ast; -} - -// Custom parser for parse-script-tags that adapts its input structure to -// our parser's signature -function htmlParser(_ref) { - var source = _ref.source, - line = _ref.line; - - return parse(source, { - startLine: line - }); -} - -function parseExpression(expression, opts) { - return babylon.parseExpression(expression, Object.assign({}, opts, { sourceType: "script" })); -} - -function getAst(source) { - if (!source || !source.text) { - return {}; - } - - if (ASTs.has(source.id)) { - return ASTs.get(source.id); - } - - var ast = {}; - if (source.contentType == "text/html") { - ast = (0, _parseScriptTags2.default)(source.text, htmlParser) || {}; - } else if (source.contentType == "text/javascript") { - ast = parse(source.text); - } - - ASTs.set(source.id, ast); - return ast; -} - -function clearASTs() { - ASTs = new Map(); -} - -function traverseAst(source, visitor) { - var ast = getAst(source); - if ((0, _isEmpty2.default)(ast)) { - return null; - } - - (0, _babelTraverse2.default)(ast, visitor); - return ast; -} - -/***/ }), -/* 1052 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.isLexicalScope = isLexicalScope; -exports.isFunction = isFunction; -exports.isAwaitExpression = isAwaitExpression; -exports.isVariable = isVariable; -exports.getMemberExpression = getMemberExpression; - -var _babelTypes = __webpack_require__(493); - -var t = _interopRequireWildcard(_babelTypes); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function isLexicalScope(path) { - return t.isBlockStatement(path) || isFunction(path) || t.isProgram(path); -} - -function isFunction(path) { - return t.isFunction(path) || t.isArrowFunctionExpression(path) || t.isObjectMethod(path) || t.isClassMethod(path); -} - -function isAwaitExpression(path) { - return t.isAwaitExpression(path) || t.isAwaitExpression(path.container.init) || t.isAwaitExpression(path.parentPath); -} - -function isVariable(path) { - return t.isVariableDeclaration(path) || isFunction(path) && path.node.params.length || t.isObjectProperty(path) && !isFunction(path.node.value); -} - -function getMemberExpression(root) { - function _getMemberExpression(node, expr) { - if (t.isMemberExpression(node)) { - expr = [node.property.name].concat(expr); - return _getMemberExpression(node.object, expr); - } - - if (t.isCallExpression(node)) { - return []; - } - - if (t.isThisExpression(node)) { - return ["this"].concat(expr); - } - - return [node.name].concat(expr); - } - - var expr = _getMemberExpression(root, []); - return expr.join("."); -} - -/***/ }), -/* 1053 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = getFunctionName; -function getFunctionName(path) { - if (path.node.id) { - return path.node.id.name; - } - - var parent = path.parent; - if (parent.type == "ObjectProperty") { - return parent.key.name; - } - - if (parent.type == "ObjectExpression" || path.node.type == "ClassMethod") { - return path.node.key.name; - } - - if (parent.type == "VariableDeclarator") { - return parent.id.name; - } - - if (parent.type == "AssignmentExpression") { - if (parent.left.type == "MemberExpression") { - return parent.left.property.name; - } - - return parent.left.name; - } - - return "anonymous"; -} - -/***/ }), +/* 1049 */, +/* 1050 */, +/* 1051 */, +/* 1052 */, +/* 1053 */, /* 1054 */, -/* 1055 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getClosestExpression = getClosestExpression; -exports.getClosestScope = getClosestScope; -exports.getClosestPath = getClosestPath; - -var _babelTypes = __webpack_require__(493); - -var t = _interopRequireWildcard(_babelTypes); - -var _ast = __webpack_require__(1051); - -var _helpers = __webpack_require__(1052); - -var _contains = __webpack_require__(1127); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function getNodeValue(node) { - if (t.isThisExpression(node)) { - return "this"; - } - - return node.name; -} - -function getClosestMemberExpression(source, token, location) { - var expression = null; - (0, _ast.traverseAst)(source, { - enter(path) { - var node = path.node; - - if (!(0, _contains.nodeContainsPosition)(node, location)) { - return path.skip(); - } - - if (t.isMemberExpression(node) && node.property.name === token) { - var memberExpression = (0, _helpers.getMemberExpression)(node); - expression = { - expression: memberExpression, - location: node.loc - }; - } - } - }); - - return expression; -} - -function getClosestExpression(source, token, location) { - var memberExpression = getClosestMemberExpression(source, token, location); - if (memberExpression) { - return memberExpression; - } - - var path = getClosestPath(source, location); - if (!path || !path.node) { - return; - } - - var node = path.node; - - return { expression: getNodeValue(node), location: node.loc }; -} - -function getClosestScope(source, location) { - var closestPath = null; - - (0, _ast.traverseAst)(source, { - enter(path) { - if (!(0, _contains.nodeContainsPosition)(path.node, location)) { - return path.skip(); - } - - if ((0, _helpers.isLexicalScope)(path)) { - closestPath = path; - } - } - }); - - if (!closestPath) { - return; - } - - return closestPath.scope; -} - -function getClosestPath(source, location) { - var closestPath = null; - - (0, _ast.traverseAst)(source, { - enter(path) { - if (!(0, _contains.nodeContainsPosition)(path.node, location)) { - return path.skip(); - } - closestPath = path; - } - }); - - return closestPath; -} - -/***/ }), +/* 1055 */, /* 1056 */ /***/ (function(module, exports, __webpack_require__) { @@ -30129,106 +29171,7 @@ Object.defineProperty(module, 'exports', { /* 1069 */, /* 1070 */, /* 1071 */, -/* 1072 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -var _get = __webpack_require__(1073); - -var _get2 = _interopRequireDefault(_get); - -var _contains = __webpack_require__(1127); - -var _getSymbols2 = __webpack_require__(1050); - -var _getSymbols3 = _interopRequireDefault(_getSymbols2); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function findSymbols(source) { - var _getSymbols = (0, _getSymbols3.default)(source), - functions = _getSymbols.functions, - comments = _getSymbols.comments; - - return { functions, comments }; -} - -/** - * Returns the location for a given function path. If the path represents a - * function declaration, the location will begin after the function identifier - * but before the function parameters. - */ - -function getLocation(func) { - var location = _extends({}, func.location); - - // if the function has an identifier, start the block after it so the - // identifier is included in the "scope" of its parent - var identifierEnd = (0, _get2.default)("identifier.loc.end", func); - if (identifierEnd) { - location.start = identifierEnd; - } - - return location; -} - -/** - * Reduces an array of locations to remove items that are completely enclosed - * by another location in the array. - */ -function removeOverlaps(locations, location) { - // support reducing without an initializing array - if (!Array.isArray(locations)) { - locations = [locations]; - } - - var contains = locations.filter(a => (0, _contains.containsLocation)(a, location)).length > 0; - - if (!contains) { - locations.push(location); - } - - return locations; -} - -/** - * Sorts an array of locations by start position - */ -function sortByStart(a, b) { - if (a.start.line < b.start.line) { - return -1; - } else if (a.start.line === b.start.line) { - return a.start.column - b.start.column; - } - - return 1; -} - -/** - * Returns an array of locations that are considered out of scope for the given - * location. - */ -function getOutOfScopeLocations(source, position) { - var _findSymbols = findSymbols(source), - functions = _findSymbols.functions, - comments = _findSymbols.comments; - - var commentLocations = comments.map(c => c.location); - - return functions.map(getLocation).concat(commentLocations).filter(loc => !(0, _contains.containsPosition)(loc, position)).reduce(removeOverlaps, []).sort(sortByStart); -} - -exports.default = getOutOfScopeLocations; - -/***/ }), +/* 1072 */, /* 1073 */ /***/ (function(module, exports, __webpack_require__) { @@ -32821,34 +31764,7 @@ module.exports = toPath; /* 1124 */, /* 1125 */, /* 1126 */, -/* 1127 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.containsPosition = containsPosition; -exports.containsLocation = containsLocation; -exports.nodeContainsPosition = nodeContainsPosition; -function containsPosition(a, b) { - var startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column; - var endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column; - - return startsBefore && endsAfter; -} - -function containsLocation(a, b) { - return containsPosition(a, b.start) && containsPosition(a, b.end); -} - -function nodeContainsPosition(node, position) { - return containsPosition(node.loc, position); -} - -/***/ }), +/* 1127 */, /* 1128 */, /* 1129 */ /***/ (function(module, exports, __webpack_require__) { @@ -33040,43 +31956,7 @@ module.exports = isArrayLikeObject; /* 1168 */, /* 1169 */, /* 1170 */, -/* 1171 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.hasSource = hasSource; -exports.setSource = setSource; -exports.getSource = getSource; -exports.clearSources = clearSources; - - -var cachedSources = new Map(); - -function hasSource(sourceId) { - return cachedSources.has(sourceId); -} - -function setSource(source) { - cachedSources.set(source.id, source); -} - -function getSource(sourceId) { - if (!cachedSources.has(sourceId)) { - throw new Error(`${sourceId} was not provided.`); - } - return cachedSources.get(sourceId); -} - -function clearSources() { - cachedSources = new Map(); -} - -/***/ }), +/* 1171 */, /* 1172 */, /* 1173 */, /* 1174 */, @@ -33091,44 +31971,7 @@ function clearSources() { /* 1183 */, /* 1184 */, /* 1185 */, -/* 1186 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = getScopes; -exports.clearScopes = clearScopes; - -var _ast = __webpack_require__(1051); - -var _sources = __webpack_require__(1171); - -var _parser = __webpack_require__(1187); - -var parsedScopesCache = new Map(); - -function getScopes(location) { - var sourceId = location.sourceId; - - var parsedScopes = parsedScopesCache.get(sourceId); - if (!parsedScopes) { - var visitor = (0, _parser.createParseJSScopeVisitor)(sourceId); - (0, _ast.traverseAst)((0, _sources.getSource)(sourceId), visitor.traverseVisitor); - parsedScopes = visitor.toParsedScopes(); - parsedScopesCache.set(sourceId, parsedScopes); - } - return (0, _parser.findScopes)(parsedScopes, location); -} - -function clearScopes() { - parsedScopesCache = new Map(); -} - -/***/ }), +/* 1186 */, /* 1187 */ /***/ (function(module, exports) { @@ -33391,7 +32234,1245 @@ module.exports = { /* 1204 */, /* 1205 */, /* 1206 */, -/* 1207 */ +/* 1207 */, +/* 1208 */, +/* 1209 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.parseExpression = parseExpression; +exports.getAst = getAst; +exports.clearASTs = clearASTs; +exports.traverseAst = traverseAst; + +var _parseScriptTags = __webpack_require__(1023); + +var _parseScriptTags2 = _interopRequireDefault(_parseScriptTags); + +var _babylon = __webpack_require__(435); + +var babylon = _interopRequireWildcard(_babylon); + +var _babelTraverse = __webpack_require__(436); + +var _babelTraverse2 = _interopRequireDefault(_babelTraverse); + +var _isEmpty = __webpack_require__(963); + +var _isEmpty2 = _interopRequireDefault(_isEmpty); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var ASTs = new Map(); + +function _parse(code, opts) { + return babylon.parse(code, Object.assign({}, opts, { + sourceType: "module", + plugins: ["jsx", "flow", "objectRestSpread"] + })); +} + +function parse(text, opts) { + var ast = void 0; + if (!text) { + return; + } + + try { + ast = _parse(text, opts); + } catch (error) { + ast = {}; + } + + return ast; +} + +// Custom parser for parse-script-tags that adapts its input structure to +// our parser's signature +function htmlParser(_ref) { + var source = _ref.source, + line = _ref.line; + + return parse(source, { + startLine: line + }); +} + +function parseExpression(expression, opts) { + return babylon.parseExpression(expression, Object.assign({}, opts, { sourceType: "script" })); +} + +function getAst(source) { + if (!source || !source.text) { + return {}; + } + + if (ASTs.has(source.id)) { + return ASTs.get(source.id); + } + + var ast = {}; + var contentType = source.contentType; + + if (contentType == "text/html") { + ast = (0, _parseScriptTags2.default)(source.text, htmlParser) || {}; + } else if (contentType && contentType.includes("javascript")) { + ast = parse(source.text); + } + + ASTs.set(source.id, ast); + return ast; +} + +function clearASTs() { + ASTs = new Map(); +} + +function traverseAst(source, visitor) { + var ast = getAst(source); + if ((0, _isEmpty2.default)(ast)) { + return null; + } + + (0, _babelTraverse2.default)(ast, visitor); + return ast; +} + +/***/ }), +/* 1210 */, +/* 1211 */, +/* 1212 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.isLexicalScope = isLexicalScope; +exports.isFunction = isFunction; +exports.isAwaitExpression = isAwaitExpression; +exports.isYieldExpression = isYieldExpression; +exports.isVariable = isVariable; +exports.getMemberExpression = getMemberExpression; + +var _babelTypes = __webpack_require__(493); + +var t = _interopRequireWildcard(_babelTypes); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function isLexicalScope(path) { + return t.isBlockStatement(path) || isFunction(path) || t.isProgram(path); +} + +function isFunction(path) { + return t.isFunction(path) || t.isArrowFunctionExpression(path) || t.isObjectMethod(path) || t.isClassMethod(path); +} + +function isAwaitExpression(path) { + return t.isAwaitExpression(path) || t.isAwaitExpression(path.container.init) || t.isAwaitExpression(path.parentPath); +} + +function isYieldExpression(path) { + return t.isYieldExpression(path) || t.isYieldExpression(path.container.init) || t.isYieldExpression(path.parentPath); +} + +function isVariable(path) { + return t.isVariableDeclaration(path) || isFunction(path) && path.node.params.length || t.isObjectProperty(path) && !isFunction(path.node.value); +} + +function getMemberExpression(root) { + function _getMemberExpression(node, expr) { + if (t.isMemberExpression(node)) { + expr = [node.property.name].concat(expr); + return _getMemberExpression(node.object, expr); + } + + if (t.isCallExpression(node)) { + return []; + } + + if (t.isThisExpression(node)) { + return ["this"].concat(expr); + } + + return [node.name].concat(expr); + } + + var expr = _getMemberExpression(root, []); + return expr.join("."); +} + +/***/ }), +/* 1213 */, +/* 1214 */, +/* 1215 */, +/* 1216 */, +/* 1217 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getClosestExpression = getClosestExpression; +exports.getClosestScope = getClosestScope; +exports.getClosestPath = getClosestPath; + +var _babelTypes = __webpack_require__(493); + +var t = _interopRequireWildcard(_babelTypes); + +var _ast = __webpack_require__(1209); + +var _helpers = __webpack_require__(1212); + +var _contains = __webpack_require__(1218); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function getNodeValue(node) { + if (t.isThisExpression(node)) { + return "this"; + } + + return node.name; +} + +function getClosestMemberExpression(source, token, location) { + var expression = null; + (0, _ast.traverseAst)(source, { + enter(path) { + var node = path.node; + + if (!(0, _contains.nodeContainsPosition)(node, location)) { + return path.skip(); + } + + if (t.isMemberExpression(node) && node.property.name === token) { + var memberExpression = (0, _helpers.getMemberExpression)(node); + expression = { + expression: memberExpression, + location: node.loc + }; + } + } + }); + + return expression; +} + +function getClosestExpression(source, token, location) { + var memberExpression = getClosestMemberExpression(source, token, location); + if (memberExpression) { + return memberExpression; + } + + var path = getClosestPath(source, location); + if (!path || !path.node) { + return; + } + + var node = path.node; + + return { expression: getNodeValue(node), location: node.loc }; +} + +function getClosestScope(source, location) { + var closestPath = null; + + (0, _ast.traverseAst)(source, { + enter(path) { + if (!(0, _contains.nodeContainsPosition)(path.node, location)) { + return path.skip(); + } + + if ((0, _helpers.isLexicalScope)(path)) { + closestPath = path; + } + } + }); + + if (!closestPath) { + return; + } + + return closestPath.scope; +} + +function getClosestPath(source, location) { + var closestPath = null; + + (0, _ast.traverseAst)(source, { + enter(path) { + if (!(0, _contains.nodeContainsPosition)(path.node, location)) { + return path.skip(); + } + closestPath = path; + } + }); + + return closestPath; +} + +/***/ }), +/* 1218 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.containsPosition = containsPosition; +exports.containsLocation = containsLocation; +exports.nodeContainsPosition = nodeContainsPosition; +function containsPosition(a, b) { + var startsBefore = a.start.line < b.line || a.start.line === b.line && a.start.column <= b.column; + var endsAfter = a.end.line > b.line || a.end.line === b.line && a.end.column >= b.column; + + return startsBefore && endsAfter; +} + +function containsLocation(a, b) { + return containsPosition(a, b.start) && containsPosition(a, b.end); +} + +function nodeContainsPosition(node, position) { + return containsPosition(node.loc, position); +} + +/***/ }), +/* 1219 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getSymbols; +exports.formatSymbols = formatSymbols; +exports.clearSymbols = clearSymbols; + +var _ast = __webpack_require__(1209); + +var _helpers = __webpack_require__(1212); + +var _babelTypes = __webpack_require__(493); + +var t = _interopRequireWildcard(_babelTypes); + +var _getFunctionName = __webpack_require__(1275); + +var _getFunctionName2 = _interopRequireDefault(_getFunctionName); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +var symbolDeclarations = new Map(); + +function getFunctionParameterNames(path) { + return path.node.params.map(param => param.name); +} + +function getVariableNames(path) { + if (t.isObjectProperty(path) && !(0, _helpers.isFunction)(path.node.value)) { + return [{ + name: path.node.key.name, + location: path.node.loc + }]; + } + + if (!path.node.declarations) { + return path.node.params.map(dec => ({ + name: dec.name, + location: dec.loc + })); + } + + return path.node.declarations.map(dec => ({ + name: dec.id.name, + location: dec.loc + })); +} + +function getComments(ast) { + if (!ast || !ast.comments) { + return []; + } + return ast.comments.map(comment => ({ + name: comment.location, + location: comment.loc + })); +} + +function getClassName(path) { + var classDeclaration = path.findParent(_p => _p.isClassDeclaration()); + if (!classDeclaration) { + return null; + } + + return classDeclaration.node.id.name; +} + +function extractSymbols(source) { + var functions = []; + var variables = []; + var memberExpressions = []; + var callExpressions = []; + var objectProperties = []; + var identifiers = []; + + var ast = (0, _ast.traverseAst)(source, { + enter(path) { + if ((0, _helpers.isVariable)(path)) { + variables.push.apply(variables, _toConsumableArray(getVariableNames(path))); + } + + if ((0, _helpers.isFunction)(path)) { + functions.push({ + name: (0, _getFunctionName2.default)(path), + klass: getClassName(path), + location: path.node.loc, + parameterNames: getFunctionParameterNames(path), + identifier: path.node.id + }); + } + + if (t.isClassDeclaration(path)) { + variables.push({ + name: path.node.id.name, + location: path.node.loc + }); + } + + if (t.isObjectProperty(path)) { + var _path$node$key$loc = path.node.key.loc, + start = _path$node$key$loc.start, + end = _path$node$key$loc.end, + identifierName = _path$node$key$loc.identifierName; + + objectProperties.push({ + name: identifierName, + location: { start, end }, + expression: getSnippet(path) + }); + } + + if (t.isMemberExpression(path)) { + var _path$node$property$l = path.node.property.loc, + _start = _path$node$property$l.start, + _end = _path$node$property$l.end; + + memberExpressions.push({ + name: path.node.property.name, + location: { start: _start, end: _end }, + expressionLocation: path.node.loc, + expression: getSnippet(path) + }); + } + + if (t.isCallExpression(path)) { + var callee = path.node.callee; + if (!t.isMemberExpression(callee)) { + var _callee$loc = callee.loc, + _start2 = _callee$loc.start, + _end2 = _callee$loc.end, + _identifierName = _callee$loc.identifierName; + + callExpressions.push({ + name: _identifierName, + location: { start: _start2, end: _end2 } + }); + } + } + + if (t.isIdentifier(path)) { + var _path$node$loc = path.node.loc, + _start3 = _path$node$loc.start, + _end3 = _path$node$loc.end; + + + identifiers.push({ + name: path.node.name, + expression: path.node.name, + location: { start: _start3, end: _end3 } + }); + } + + if (t.isThisExpression(path.node)) { + var _path$node$loc2 = path.node.loc, + _start4 = _path$node$loc2.start, + _end4 = _path$node$loc2.end; + + identifiers.push({ + name: "this", + location: { start: _start4, end: _end4 }, + expressionLocation: path.node.loc, + expression: "this" + }); + } + + if (t.isVariableDeclarator(path)) { + var node = path.node.id; + var _path$node$loc3 = path.node.loc, + _start5 = _path$node$loc3.start, + _end5 = _path$node$loc3.end; + + + identifiers.push({ + name: node.name, + expression: node.name, + location: { start: _start5, end: _end5 } + }); + } + } + }); + + // comments are extracted separately from the AST + var comments = getComments(ast); + + return { + functions, + variables, + callExpressions, + memberExpressions, + objectProperties, + comments, + identifiers + }; +} + +function getSymbols(source) { + if (symbolDeclarations.has(source.id)) { + var _symbols = symbolDeclarations.get(source.id); + if (_symbols) { + return _symbols; + } + } + + var symbols = extractSymbols(source); + symbolDeclarations.set(source.id, symbols); + return symbols; +} + +function extendSnippet(name, expression, path, prevPath) { + var computed = path && path.node.computed; + var prevComputed = prevPath && prevPath.node.computed; + var prevArray = t.isArrayExpression(prevPath); + var array = t.isArrayExpression(path); + + if (expression === "") { + if (computed) { + return `[${name}]`; + } + return name; + } + + if (computed || array) { + if (prevComputed || prevArray) { + return `[${name}]${expression}`; + } + return `[${name}].${expression}`; + } + + if (prevComputed || prevArray) { + return `${name}${expression}`; + } + + return `${name}.${expression}`; +} + +function getMemberSnippet(node) { + var expression = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; + + if (t.isMemberExpression(node)) { + var _name = node.property.name; + + return getMemberSnippet(node.object, extendSnippet(_name, expression)); + } + + if (t.isCallExpression(node)) { + return ""; + } + + if (t.isThisExpression(node)) { + return `this.${expression}`; + } + + if (t.isIdentifier(node)) { + return `${node.name}.${expression}`; + } + + return expression; +} + +function getObjectSnippet(path, prevPath) { + var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ""; + + if (!path) { + return expression; + } + + var name = path.node.key.name; + + var extendedExpression = extendSnippet(name, expression, path, prevPath); + + var nextPrevPath = path; + var nextPath = path.parentPath && path.parentPath.parentPath; + + return getSnippet(nextPath, nextPrevPath, extendedExpression); +} + +function getArraySnippet(path, prevPath, expression) { + var index = prevPath.parentPath.key; + var extendedExpression = extendSnippet(index, expression, path, prevPath); + + var nextPrevPath = path; + var nextPath = path.parentPath && path.parentPath.parentPath; + + return getSnippet(nextPath, nextPrevPath, extendedExpression); +} + +function getSnippet(path, prevPath) { + var expression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ""; + + if (t.isVariableDeclaration(path)) { + var node = path.node.declarations[0]; + var _name2 = node.id.name; + return extendSnippet(_name2, expression, path, prevPath); + } + + if (t.isVariableDeclarator(path)) { + var _node = path.node.id; + if (t.isObjectPattern(_node)) { + return expression; + } + + var _name3 = _node.name; + var prop = extendSnippet(_name3, expression, path, prevPath); + return prop; + } + + if (t.isAssignmentExpression(path)) { + var _node2 = path.node.left; + var _name4 = t.isMemberExpression(_node2) ? getMemberSnippet(_node2) : _node2.name; + + var _prop = extendSnippet(_name4, expression, path, prevPath); + return _prop; + } + + if ((0, _helpers.isFunction)(path)) { + return expression; + } + + if (t.isIdentifier(path)) { + var _node3 = path.node; + return `${_node3.name}.${expression}`; + } + + if (t.isObjectProperty(path)) { + return getObjectSnippet(path, prevPath, expression); + } + + if (t.isObjectExpression(path)) { + var parentPath = prevPath && prevPath.parentPath; + return getObjectSnippet(parentPath, prevPath, expression); + } + + if (t.isMemberExpression(path)) { + return getMemberSnippet(path.node, expression); + } + + if (t.isArrayExpression(path)) { + return getArraySnippet(path, prevPath, expression); + } +} + +function formatSymbols(source) { + var symbols = getSymbols(source); + + function formatLocation(loc) { + if (!loc) { + return ""; + } + var start = loc.start, + end = loc.end; + + + var startLoc = `(${start.line}, ${start.column})`; + var endLoc = `(${end.line}, ${end.column})`; + return `[${startLoc}, ${endLoc}]`; + } + + function summarize(symbol) { + var loc = formatLocation(symbol.location); + var exprLoc = formatLocation(symbol.expressionLocation); + var params = symbol.parameterNames ? symbol.parameterNames.join(", ") : ""; + var expression = symbol.expression || ""; + var klass = symbol.klass || ""; + return `${loc} ${exprLoc} ${expression} ${symbol.name} ${params} ${klass}`; + } + + return Object.keys(symbols).map(name => `${name}:\n ${symbols[name].map(summarize).join("\n")}`); +} + +function clearSymbols() { + symbolDeclarations = new Map(); +} + +/***/ }), +/* 1220 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.hasSource = hasSource; +exports.setSource = setSource; +exports.getSource = getSource; +exports.clearSources = clearSources; + + +var cachedSources = new Map(); + +function hasSource(sourceId) { + return cachedSources.has(sourceId); +} + +function setSource(source) { + cachedSources.set(source.id, source); +} + +function getSource(sourceId) { + if (!cachedSources.has(sourceId)) { + throw new Error(`${sourceId} was not provided.`); + } + return cachedSources.get(sourceId); +} + +function clearSources() { + cachedSources = new Map(); +} + +/***/ }), +/* 1221 */, +/* 1222 */, +/* 1223 */, +/* 1224 */, +/* 1225 */, +/* 1226 */, +/* 1227 */, +/* 1228 */, +/* 1229 */, +/* 1230 */, +/* 1231 */, +/* 1232 */, +/* 1233 */, +/* 1234 */, +/* 1235 */, +/* 1236 */, +/* 1237 */, +/* 1238 */, +/* 1239 */, +/* 1240 */, +/* 1241 */, +/* 1242 */, +/* 1243 */, +/* 1244 */, +/* 1245 */, +/* 1246 */, +/* 1247 */, +/* 1248 */, +/* 1249 */, +/* 1250 */, +/* 1251 */, +/* 1252 */, +/* 1253 */, +/* 1254 */, +/* 1255 */, +/* 1256 */, +/* 1257 */, +/* 1258 */, +/* 1259 */, +/* 1260 */, +/* 1261 */, +/* 1262 */, +/* 1263 */, +/* 1264 */, +/* 1265 */, +/* 1266 */, +/* 1267 */, +/* 1268 */, +/* 1269 */, +/* 1270 */, +/* 1271 */, +/* 1272 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(1273); + + +/***/ }), +/* 1273 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _closest = __webpack_require__(1217); + +var _scopes = __webpack_require__(1274); + +var _getSymbols = __webpack_require__(1219); + +var _getSymbols2 = _interopRequireDefault(_getSymbols); + +var _ast = __webpack_require__(1209); + +var _getScopes = __webpack_require__(1276); + +var _getScopes2 = _interopRequireDefault(_getScopes); + +var _sources = __webpack_require__(1220); + +var _getOutOfScopeLocations = __webpack_require__(1277); + +var _getOutOfScopeLocations2 = _interopRequireDefault(_getOutOfScopeLocations); + +var _steps = __webpack_require__(1278); + +var _getEmptyLines = __webpack_require__(1280); + +var _getEmptyLines2 = _interopRequireDefault(_getEmptyLines); + +var _validate = __webpack_require__(1281); + +var _devtoolsUtils = __webpack_require__(900); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var workerHandler = _devtoolsUtils.workerUtils.workerHandler; + + +self.onmessage = workerHandler({ + getClosestExpression: _closest.getClosestExpression, + getOutOfScopeLocations: _getOutOfScopeLocations2.default, + getSymbols: _getSymbols2.default, + getScopes: _getScopes2.default, + clearSymbols: _getSymbols.clearSymbols, + clearScopes: _getScopes.clearScopes, + clearASTs: _ast.clearASTs, + hasSource: _sources.hasSource, + setSource: _sources.setSource, + clearSources: _sources.clearSources, + getVariablesInScope: _scopes.getVariablesInScope, + getNextStep: _steps.getNextStep, + getEmptyLines: _getEmptyLines2.default, + hasSyntaxError: _validate.hasSyntaxError +}); + +/***/ }), +/* 1274 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +exports.getVariablesInLocalScope = getVariablesInLocalScope; +exports.getVariablesInScope = getVariablesInScope; +exports.isExpressionInScope = isExpressionInScope; + +var _toPairs = __webpack_require__(795); + +var _toPairs2 = _interopRequireDefault(_toPairs); + +var _uniq = __webpack_require__(561); + +var _uniq2 = _interopRequireDefault(_uniq); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +function getScopeVariables(scope) { + var bindings = scope.bindings; + + + return (0, _toPairs2.default)(bindings).map((_ref) => { + var _ref2 = _slicedToArray(_ref, 2), + name = _ref2[0], + binding = _ref2[1]; + + return { + name, + references: binding.referencePaths + }; + }); +} + +function getScopeChain(scope) { + var scopes = []; + + do { + scopes.push(scope); + } while (scope = scope.parent); + + return scopes; +} + +function getVariablesInLocalScope(scope) { + return getScopeVariables(scope); +} + +function getVariablesInScope(scope) { + var _ref3; + + var scopes = getScopeChain(scope); + var scopeVars = scopes.map(getScopeVariables); + var vars = (_ref3 = [{ name: "this" }, { name: "arguments" }]).concat.apply(_ref3, _toConsumableArray(scopeVars)).map(variable => variable.name); + return (0, _uniq2.default)(vars); +} + +function isExpressionInScope(expression, scope) { + if (!scope) { + return false; + } + + var variables = getVariablesInScope(scope); + var firstPart = expression.split(/\./)[0]; + return variables.includes(firstPart); +} + +/***/ }), +/* 1275 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getFunctionName; +function getFunctionName(path) { + if (path.node.id) { + return path.node.id.name; + } + + var parent = path.parent; + if (parent.type == "ObjectProperty") { + return parent.key.name; + } + + if (parent.type == "ObjectExpression" || path.node.type == "ClassMethod") { + return path.node.key.name; + } + + if (parent.type == "VariableDeclarator") { + return parent.id.name; + } + + if (parent.type == "AssignmentExpression") { + if (parent.left.type == "MemberExpression") { + return parent.left.property.name; + } + + return parent.left.name; + } + + return "anonymous"; +} + +/***/ }), +/* 1276 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getScopes; +exports.clearScopes = clearScopes; + +var _ast = __webpack_require__(1209); + +var _sources = __webpack_require__(1220); + +var _parser = __webpack_require__(1187); + +var parsedScopesCache = new Map(); + +function getScopes(location) { + var sourceId = location.sourceId; + + var parsedScopes = parsedScopesCache.get(sourceId); + if (!parsedScopes) { + var visitor = (0, _parser.createParseJSScopeVisitor)(sourceId); + (0, _ast.traverseAst)((0, _sources.getSource)(sourceId), visitor.traverseVisitor); + parsedScopes = visitor.toParsedScopes(); + parsedScopesCache.set(sourceId, parsedScopes); + } + return (0, _parser.findScopes)(parsedScopes, location); +} + +function clearScopes() { + parsedScopesCache = new Map(); +} + +/***/ }), +/* 1277 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _get = __webpack_require__(1073); + +var _get2 = _interopRequireDefault(_get); + +var _contains = __webpack_require__(1218); + +var _getSymbols2 = __webpack_require__(1219); + +var _getSymbols3 = _interopRequireDefault(_getSymbols2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function findSymbols(source) { + var _getSymbols = (0, _getSymbols3.default)(source), + functions = _getSymbols.functions, + comments = _getSymbols.comments; + + return { functions, comments }; +} + +/** + * Returns the location for a given function path. If the path represents a + * function declaration, the location will begin after the function identifier + * but before the function parameters. + */ + +function getLocation(func) { + var location = _extends({}, func.location); + + // if the function has an identifier, start the block after it so the + // identifier is included in the "scope" of its parent + var identifierEnd = (0, _get2.default)("identifier.loc.end", func); + if (identifierEnd) { + location.start = identifierEnd; + } + + return location; +} + +/** + * Reduces an array of locations to remove items that are completely enclosed + * by another location in the array. + */ +function removeOverlaps(locations, location) { + // support reducing without an initializing array + if (!Array.isArray(locations)) { + locations = [locations]; + } + + var contains = locations.filter(a => (0, _contains.containsLocation)(a, location)).length > 0; + + if (!contains) { + locations.push(location); + } + + return locations; +} + +/** + * Sorts an array of locations by start position + */ +function sortByStart(a, b) { + if (a.start.line < b.start.line) { + return -1; + } else if (a.start.line === b.start.line) { + return a.start.column - b.start.column; + } + + return 1; +} + +/** + * Returns an array of locations that are considered out of scope for the given + * location. + */ +function getOutOfScopeLocations(source, position) { + var _findSymbols = findSymbols(source), + functions = _findSymbols.functions, + comments = _findSymbols.comments; + + var commentLocations = comments.map(c => c.location); + + return functions.map(getLocation).concat(commentLocations).filter(loc => !(0, _contains.containsPosition)(loc, position)).reduce(removeOverlaps, []).sort(sortByStart); +} + +exports.default = getOutOfScopeLocations; + +/***/ }), +/* 1278 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +exports.getNextStep = getNextStep; + +var _debuggerHtml = __webpack_require__(843); + +var _types = __webpack_require__(1279); + +var _closest = __webpack_require__(1217); + +var _helpers = __webpack_require__(1212); + +function getNextStep(source, pausedPosition) { + var currentExpression = getSteppableExpression(source, pausedPosition); + if (!currentExpression) { + return null; + } + var currentStatement = currentExpression.getStatementParent(); + return _getNextStep(currentStatement, pausedPosition); +} + +function getSteppableExpression(source, pausedPosition) { + var closestPath = (0, _closest.getClosestPath)(source, pausedPosition); + + if (!closestPath) { + return null; + } + + if ((0, _helpers.isAwaitExpression)(closestPath) || (0, _helpers.isYieldExpression)(closestPath)) { + return closestPath; + } + + return closestPath.find(p => p.isAwaitExpression() || p.isYieldExpression()); +} + +function _getNextStep(statement, position) { + var nextStatement = statement.getSibling(statement.key + 1); + if (nextStatement.node) { + return _extends({}, nextStatement.node.loc.start, { + sourceId: position.sourceId + }); + } + + return null; +} + +/***/ }), +/* 1279 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/***/ }), +/* 1280 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getEmptyLines; + +var _uniq = __webpack_require__(561); + +var _uniq2 = _interopRequireDefault(_uniq); + +var _difference = __webpack_require__(1129); + +var _difference2 = _interopRequireDefault(_difference); + +var _ast = __webpack_require__(1209); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var commentTokens = ["CommentBlock", "CommentLine"]; + +function fillRange(start, end) { + return Array(end - start + 1).fill().map((item, index) => start + index); +} + +// Populates a pre-filled array of every line number, +// then removes lines which were found to be executable +function getLines(ast) { + return fillRange(0, ast.tokens[ast.tokens.length - 1].loc.end.line); +} + +// The following sequence stores lines which have executable code +// (contents other than comments or EOF, regardless of line position) +function getExecutableLines(ast) { + var lines = ast.tokens.filter(token => !commentTokens.includes(token.type) && (!token.type || token.type.label && token.type.label != "eof")).map(token => token.loc.start.line - 1); + + return (0, _uniq2.default)(lines); +} + +function getEmptyLines(sourceToJS) { + if (!sourceToJS) { + return null; + } + + var ast = (0, _ast.getAst)(sourceToJS); + if (!ast || !ast.comments) { + return []; + } + + var executableLines = getExecutableLines(ast); + var lines = getLines(ast); + return (0, _difference2.default)(lines, executableLines); +} + +/***/ }), +/* 1281 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -33402,7 +33483,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.hasSyntaxError = hasSyntaxError; -var _ast = __webpack_require__(1051); +var _ast = __webpack_require__(1209); function hasSyntaxError(input) { try { diff --git a/devtools/client/debugger/new/pretty-print-worker.js b/devtools/client/debugger/new/pretty-print-worker.js index dceeb9f3c06f..1774ce020007 100644 --- a/devtools/client/debugger/new/pretty-print-worker.js +++ b/devtools/client/debugger/new/pretty-print-worker.js @@ -70,17 +70,74 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 380); +/******/ return __webpack_require__(__webpack_require__.s = 1282); /******/ }) /************************************************************************/ /******/ ({ -/***/ 380: +/***/ 1282: /***/ (function(module, exports, __webpack_require__) { -module.exports = __webpack_require__(964); +module.exports = __webpack_require__(1283); +/***/ }), + +/***/ 1283: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _prettyFast = __webpack_require__(802); + +var _prettyFast2 = _interopRequireDefault(_prettyFast); + +var _devtoolsUtils = __webpack_require__(900); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var workerHandler = _devtoolsUtils.workerUtils.workerHandler; + + +function prettyPrint(_ref) { + var url = _ref.url, + indent = _ref.indent, + source = _ref.source; + + var prettified = (0, _prettyFast2.default)(source, { + url: url, + indent: " ".repeat(indent) + }); + + return { + code: prettified.code, + mappings: invertMappings(prettified.map._mappings) + }; +} + +function invertMappings(mappings) { + return mappings._array.map(m => { + var mapping = { + generated: { + line: m.originalLine, + column: m.originalColumn + } + }; + if (m.source) { + mapping.source = m.source; + mapping.original = { + line: m.generatedLine, + column: m.generatedColumn + }; + mapping.name = m.name; + } + return mapping; + }); +} + +self.onmessage = workerHandler({ prettyPrint }); + /***/ }), /***/ 381: @@ -7532,63 +7589,6 @@ module.exports = { streamingWorkerHandler }; -/***/ }), - -/***/ 964: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _prettyFast = __webpack_require__(802); - -var _prettyFast2 = _interopRequireDefault(_prettyFast); - -var _devtoolsUtils = __webpack_require__(900); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var workerHandler = _devtoolsUtils.workerUtils.workerHandler; - - -function prettyPrint(_ref) { - var url = _ref.url, - indent = _ref.indent, - source = _ref.source; - - var prettified = (0, _prettyFast2.default)(source, { - url: url, - indent: " ".repeat(indent) - }); - - return { - code: prettified.code, - mappings: invertMappings(prettified.map._mappings) - }; -} - -function invertMappings(mappings) { - return mappings._array.map(m => { - var mapping = { - generated: { - line: m.originalLine, - column: m.originalColumn - } - }; - if (m.source) { - mapping.source = m.source; - mapping.original = { - line: m.generatedLine, - column: m.generatedColumn - }; - mapping.name = m.name; - } - return mapping; - }); -} - -self.onmessage = workerHandler({ prettyPrint }); - /***/ }) /******/ }); diff --git a/devtools/client/debugger/new/search-worker.js b/devtools/client/debugger/new/search-worker.js index 21cf99a7fa9f..533bf6a756e1 100644 --- a/devtools/client/debugger/new/search-worker.js +++ b/devtools/client/debugger/new/search-worker.js @@ -70,7 +70,7 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.p = "/assets/build"; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 382); +/******/ return __webpack_require__(__webpack_require__.s = 1284); /******/ }) /************************************************************************/ /******/ ({ @@ -262,168 +262,6 @@ function arrayMap(array, iteratee) { module.exports = arrayMap; -/***/ }), - -/***/ 1123: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _getMatches = __webpack_require__(1173); - -var _getMatches2 = _interopRequireDefault(_getMatches); - -var _projectSearch = __webpack_require__(1140); - -var _devtoolsUtils = __webpack_require__(900); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var workerHandler = _devtoolsUtils.workerUtils.workerHandler; - - -self.onmessage = workerHandler({ getMatches: _getMatches2.default, findSourceMatches: _projectSearch.findSourceMatches }); - -/***/ }), - -/***/ 1138: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = buildQuery; - -var _escapeRegExp = __webpack_require__(259); - -var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Ignore doing outline matches for less than 3 whitespaces - * - * @memberof utils/source-search - * @static - */ -function ignoreWhiteSpace(str) { - return (/^\s{0,2}$/.test(str) ? "(?!\\s*.*)" : str - ); -} - - -function wholeMatch(query, wholeWord) { - if (query === "" || !wholeWord) { - return query; - } - - return `\\b${query}\\b`; -} - -function buildFlags(caseSensitive, isGlobal) { - if (caseSensitive && isGlobal) { - return "g"; - } - - if (!caseSensitive && isGlobal) { - return "gi"; - } - - if (!caseSensitive && !isGlobal) { - return "i"; - } - - return; -} - -function buildQuery(originalQuery, modifiers, _ref) { - var _ref$isGlobal = _ref.isGlobal, - isGlobal = _ref$isGlobal === undefined ? false : _ref$isGlobal, - _ref$ignoreSpaces = _ref.ignoreSpaces, - ignoreSpaces = _ref$ignoreSpaces === undefined ? false : _ref$ignoreSpaces; - var caseSensitive = modifiers.caseSensitive, - regexMatch = modifiers.regexMatch, - wholeWord = modifiers.wholeWord; - - - if (originalQuery === "") { - return new RegExp(originalQuery); - } - - var query = originalQuery; - if (ignoreSpaces) { - query = ignoreWhiteSpace(query); - } - - if (!regexMatch) { - query = (0, _escapeRegExp2.default)(query); - } - - query = wholeMatch(query, wholeWord); - var flags = buildFlags(caseSensitive, isGlobal); - - if (flags) { - return new RegExp(query, flags); - } - - return new RegExp(query); -} - -/***/ }), - -/***/ 1140: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.findSourceMatches = findSourceMatches; - -var _source = __webpack_require__(233); - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // Maybe reuse file search's functions? - - -function findSourceMatches(source, queryText) { - var _ref; - - var text = source.text; - - if (!(0, _source.isLoaded)(source) || !text || queryText == "") { - return []; - } - - var lines = text.split("\n"); - var result = undefined; - var query = new RegExp(queryText, "g"); - - var matches = lines.map((_text, line) => { - var indices = []; - - while (result = query.exec(_text)) { - indices.push({ - sourceId: source.id, - line: line + 1, - column: result.index, - match: result[0], - value: _text, - text: result.input - }); - } - return indices; - }).filter(_matches => _matches.length > 0); - - matches = (_ref = []).concat.apply(_ref, _toConsumableArray(matches)); - return matches; -} - /***/ }), /***/ 1165: @@ -681,44 +519,6 @@ module.exports = { /***/ }), -/***/ 1173: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = getMatches; - -var _buildQuery = __webpack_require__(1138); - -var _buildQuery2 = _interopRequireDefault(_buildQuery); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function getMatches(query, text, modifiers) { - if (!query || !text || !modifiers) { - return []; - } - var regexQuery = (0, _buildQuery2.default)(query, modifiers, { - isGlobal: true - }); - var matchedLocations = []; - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) { - var singleMatch = void 0; - var line = lines[i]; - while ((singleMatch = regexQuery.exec(line)) !== null) { - matchedLocations.push({ line: i, ch: singleMatch.index }); - } - } - return matchedLocations; -} - -/***/ }), - /***/ 121: /***/ (function(module, exports, __webpack_require__) { @@ -809,6 +609,94 @@ var isArray = Array.isArray || function (xs) { }; +/***/ }), + +/***/ 1211: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = buildQuery; + +var _escapeRegExp = __webpack_require__(259); + +var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Ignore doing outline matches for less than 3 whitespaces + * + * @memberof utils/source-search + * @static + */ +function ignoreWhiteSpace(str) { + return (/^\s{0,2}$/.test(str) ? "(?!\\s*.*)" : str + ); +} + + +function wholeMatch(query, wholeWord) { + if (query === "" || !wholeWord) { + return query; + } + + return `\\b${query}\\b`; +} + +function buildFlags(caseSensitive, isGlobal) { + if (caseSensitive && isGlobal) { + return "g"; + } + + if (!caseSensitive && isGlobal) { + return "gi"; + } + + if (!caseSensitive && !isGlobal) { + return "i"; + } + + return; +} + +function buildQuery(originalQuery, modifiers, _ref) { + var _ref$isGlobal = _ref.isGlobal, + isGlobal = _ref$isGlobal === undefined ? false : _ref$isGlobal, + _ref$ignoreSpaces = _ref.ignoreSpaces, + ignoreSpaces = _ref$ignoreSpaces === undefined ? false : _ref$ignoreSpaces; + var caseSensitive = modifiers.caseSensitive, + regexMatch = modifiers.regexMatch, + wholeWord = modifiers.wholeWord; + + + if (originalQuery === "") { + return new RegExp(originalQuery); + } + + var query = originalQuery; + if (ignoreSpaces) { + query = ignoreWhiteSpace(query); + } + + if (!regexMatch) { + query = (0, _escapeRegExp2.default)(query); + } + + query = wholeMatch(query, wholeWord); + var flags = buildFlags(caseSensitive, isGlobal); + + if (flags) { + return new RegExp(query, flags); + } + + return new RegExp(query); +} + /***/ }), /***/ 122: @@ -902,6 +790,126 @@ var objectKeys = Object.keys || function (obj) { }; +/***/ }), + +/***/ 1284: +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(1285); + + +/***/ }), + +/***/ 1285: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _getMatches = __webpack_require__(1286); + +var _getMatches2 = _interopRequireDefault(_getMatches); + +var _projectSearch = __webpack_require__(1287); + +var _devtoolsUtils = __webpack_require__(900); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var workerHandler = _devtoolsUtils.workerUtils.workerHandler; + + +self.onmessage = workerHandler({ getMatches: _getMatches2.default, findSourceMatches: _projectSearch.findSourceMatches }); + +/***/ }), + +/***/ 1286: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getMatches; + +var _buildQuery = __webpack_require__(1211); + +var _buildQuery2 = _interopRequireDefault(_buildQuery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function getMatches(query, text, modifiers) { + if (!query || !text || !modifiers) { + return []; + } + var regexQuery = (0, _buildQuery2.default)(query, modifiers, { + isGlobal: true + }); + var matchedLocations = []; + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + var singleMatch = void 0; + var line = lines[i]; + while ((singleMatch = regexQuery.exec(line)) !== null) { + matchedLocations.push({ line: i, ch: singleMatch.index }); + } + } + return matchedLocations; +} + +/***/ }), + +/***/ 1287: +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.findSourceMatches = findSourceMatches; + +var _source = __webpack_require__(233); + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // Maybe reuse file search's functions? + + +function findSourceMatches(source, queryText) { + var _ref; + + var text = source.text; + + if (!(0, _source.isLoaded)(source) || !text || queryText == "") { + return []; + } + + var lines = text.split("\n"); + var result = undefined; + var query = new RegExp(queryText, "g"); + + var matches = lines.map((_text, line) => { + var indices = []; + + while (result = query.exec(_text)) { + indices.push({ + sourceId: source.id, + line: line + 1, + column: result.index, + match: result[0], + value: _text, + text: result.input + }); + } + return indices; + }).filter(_matches => _matches.length > 0); + + matches = (_ref = []).concat.apply(_ref, _toConsumableArray(matches)); + return matches; +} + /***/ }), /***/ 14: @@ -949,7 +957,7 @@ module.exports = isObjectLike; Object.defineProperty(exports, "__esModule", { value: true }); -exports.isLoaded = exports.getMode = exports.getSourceLineCount = exports.getSourcePath = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.shouldPrettyPrint = exports.isThirdParty = exports.isPretty = exports.isJavaScript = undefined; +exports.isLoaded = exports.getMode = exports.getSourceLineCount = exports.getSourcePath = exports.getFileURL = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.shouldPrettyPrint = exports.isThirdParty = exports.isPretty = exports.isJavaScript = undefined; var _devtoolsSourceMap = __webpack_require__(898); @@ -1048,12 +1056,23 @@ function getRawSourceURL(url) { return url.replace(/:formatted$/, ""); } -function getFilenameFromURL(url) { +function resolveFileURL(url) { + var transformUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : initialUrl => initialUrl; + url = getRawSourceURL(url || ""); - var name = (0, _path.basename)(url) || "(index)"; + var name = transformUrl(url); return (0, _utils.endTruncateStr)(name, 50); } +function getFilenameFromURL(url) { + return resolveFileURL(url, initialUrl => (0, _path.basename)(initialUrl) || "(index)"); +} + +function getFormattedSourceId(id) { + var sourceId = id.split("/")[1]; + return `SOURCE${sourceId}`; +} + /** * Show a source url's filename. * If the source does not have a url, use the source id. @@ -1066,13 +1085,30 @@ function getFilename(source) { id = source.id; if (!url) { - var sourceId = id.split("/")[1]; - return `SOURCE${sourceId}`; + return getFormattedSourceId(id); } return getFilenameFromURL(url); } +/** + * Show a source url. + * If the source does not have a url, use the source id. + * + * @memberof utils/source + * @static + */ +function getFileURL(source) { + var url = source.url, + id = source.id; + + if (!url) { + return getFormattedSourceId(id); + } + + return resolveFileURL(url); +} + var contentTypeModeMap = { "text/javascript": { name: "javascript" }, "text/typescript": { name: "javascript", typescript: true }, @@ -1184,6 +1220,7 @@ exports.getPrettySourceURL = getPrettySourceURL; exports.getRawSourceURL = getRawSourceURL; exports.getFilename = getFilename; exports.getFilenameFromURL = getFilenameFromURL; +exports.getFileURL = getFileURL; exports.getSourcePath = getSourcePath; exports.getSourceLineCount = getSourceLineCount; exports.getMode = getMode; @@ -2463,14 +2500,6 @@ module.exports = { }; -/***/ }), - -/***/ 382: -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__(1123); - - /***/ }), /***/ 6: diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini index db48cccf063d..26ab596fb62e 100644 --- a/devtools/client/debugger/new/test/mochitest/browser.ini +++ b/devtools/client/debugger/new/test/mochitest/browser.ini @@ -19,6 +19,9 @@ support-files = examples/sum/sum.js examples/sum/sum.min.js examples/sum/sum.min.js.map + examples/reload/code_reload_1.js + examples/reload/code_reload_2.js + examples/reload/doc_reload.html examples/doc-async.html examples/doc-asm.html examples/doc-scripts.html @@ -53,6 +56,7 @@ support-files = examples/script-switching-02.js examples/script-switching-01.js examples/times2.js + examples/reload/sjs_code_reload.sjs [browser_dbg-asm.js] [browser_dbg-async-stepping.js] @@ -64,7 +68,6 @@ support-files = skip-if = true # Bug 1383576 [browser_dbg-breakpoints-cond.js] [browser_dbg-call-stack.js] -[browser_dbg-expressions.js] [browser_dbg-scopes.js] [browser_dbg-chrome-create.js] [browser_dbg-chrome-debugging.js] @@ -74,6 +77,8 @@ skip-if = debug # bug 1374187 [browser_dbg-editor-gutter.js] [browser_dbg-editor-select.js] [browser_dbg-editor-highlight.js] +[browser_dbg-expressions.js] +[browser_dbg-expressions-error.js] [browser_dbg-iframes.js] [browser_dbg_keyboard_navigation.js] [browser_dbg_keyboard-shortcuts.js] @@ -102,4 +107,4 @@ skip-if = true # Bug 1393121, 1393299 [browser_dbg-tabs.js] [browser_dbg-toggling-tools.js] [browser_dbg-wasm-sourcemaps.js] -skip-if = true +[browser_dbg-reload.js] diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js new file mode 100644 index 000000000000..3a8dee1a998f --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-error.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * test pausing on an errored watch expression + * assert that you can: + * 1. resume + * 2. still evalutate expressions + * 3. expand properties + */ + +const expressionSelectors = { + input: "input.input-expression" +}; + +function getLabel(dbg, index) { + return findElement(dbg, "expressionNode", index).innerText; +} + +function getValue(dbg, index) { + return findElement(dbg, "expressionValue", index).innerText; +} + +function assertEmptyValue(dbg, index) { + const value = findElement(dbg, "expressionValue", index); + if (value) { + is(value.innerText, ""); + return; + } + + is(value, null); +} + +function toggleExpression(dbg, index) { + findElement(dbg, "expressionNode", index).click(); +} + +async function addExpression(dbg, input) { + info("Adding an expression"); + findElementWithSelector(dbg, expressionSelectors.input).focus(); + type(dbg, input); + pressKey(dbg, "Enter"); + + await waitForDispatch(dbg, "EVALUATE_EXPRESSION"); +} + +async function editExpression(dbg, input) { + info("updating the expression"); + dblClickElement(dbg, "expressionNode", 1); + // Position cursor reliably at the end of the text. + pressKey(dbg, "End"); + type(dbg, input); + pressKey(dbg, "Enter"); + await waitForDispatch(dbg, "EVALUATE_EXPRESSION"); +} + +/* + * When we add a bad expression, we'll pause, + * resume, and wait for the expression to finish being evaluated. + */ +async function addBadExpression(dbg, input) { + const paused = waitForPaused(dbg); + const added = addExpression(dbg, input); + + await paused; + ok(dbg.selectors.isEvaluatingExpression(dbg.getState())); + await resume(dbg); + await added; +} + +add_task(async function() { + const dbg = await initDebugger("doc-script-switching.html"); + + await togglePauseOnExceptions(dbg, true, false); + + // add a good expression, 2 bad expressions, and another good one + await addExpression(dbg, "location"); + await addBadExpression(dbg, "foo.bar"); + await addBadExpression(dbg, "foo.batt"); + await addExpression(dbg, "2"); + + // check the value of + is(getValue(dbg, 2), "(unavailable)") + is(getValue(dbg, 3), "(unavailable)") + is(getValue(dbg, 4), 2); + + toggleExpression(dbg, 1); + await waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES"); + is(findAllElements(dbg, "expressionNodes").length, 20); +}); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js new file mode 100644 index 000000000000..7c4db1a5ded3 --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js @@ -0,0 +1,29 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Test reloading: + * 1. reload the source + * 2. re-sync breakpoints + */ + +add_task(async function() { + const dbg = await initDebugger("reload/doc_reload.html", "sjs_code_reload"); + + const sym = waitForDispatch(dbg, "SET_SYMBOLS"); + await selectSource(dbg, "sjs_code_reload"); + await sym; + + await addBreakpoint(dbg, "sjs_code_reload", 2); + + const sync = waitForDispatch(dbg, "SYNC_BREAKPOINT"); + await reload(dbg, "sjs_code_reload"); + await sync; + + const breakpoints = dbg.selectors.getBreakpoints(dbg.getState()); + const breakpointList = breakpoints.valueSeq().toJS(); + const breakpoint = breakpointList[0]; + + is(breakpointList.length, 1); + is(breakpoint.location.line, 6); +}); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js index 14eeb332b347..5604c3f45a03 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js @@ -11,6 +11,7 @@ add_task(async function() { await waitForPaused(dbg); assertPausedLocation(dbg); + await waitForSource(dbg, "wasm-sourcemaps/average.c"); await addBreakpoint(dbg, "wasm-sourcemaps/average.c", 12); clickElement(dbg, "resume"); diff --git a/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_1.js b/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_1.js new file mode 100644 index 000000000000..52e7f61a01fc --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_1.js @@ -0,0 +1,3 @@ +function foo(n) { + console.log("yo") +} diff --git a/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_2.js b/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_2.js new file mode 100644 index 000000000000..9d59fe7c8b52 --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/examples/reload/code_reload_2.js @@ -0,0 +1,7 @@ +/* + * comments + */ + +function foo() { + console.log("YO") +} diff --git a/devtools/client/debugger/new/test/mochitest/examples/reload/doc_reload.html b/devtools/client/debugger/new/test/mochitest/examples/reload/doc_reload.html new file mode 100644 index 000000000000..6894782cd313 --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/examples/reload/doc_reload.html @@ -0,0 +1,15 @@ + + + + + + + + Empty test page 1 + + + + + + diff --git a/devtools/client/debugger/new/test/mochitest/examples/reload/sjs_code_reload.sjs b/devtools/client/debugger/new/test/mochitest/examples/reload/sjs_code_reload.sjs new file mode 100644 index 000000000000..774d39090d31 --- /dev/null +++ b/devtools/client/debugger/new/test/mochitest/examples/reload/sjs_code_reload.sjs @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* globals getState, setState */ +/* exported handleRequest */ + +"use strict"; + +function _getUrl(request, counter) { + const { scheme, host, path } = request; + + const newPath = path.substr(0, path.lastIndexOf("/") + 1); + const index = counter < 3 ? 1 : 2; + return `${scheme}://${host}${newPath}/code_reload_${index}.js` +} + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "0"); + response.setHeader("Access-Control-Allow-Origin", "*", false); + response.setHeader("Content-Type", "text/javascript", false); + + // Redirect to a different file each time. + let counter = 1 + +getState("counter"); + + const newUrl = _getUrl(request, counter); + + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", newUrl); + setState("counter", "" + counter); +} diff --git a/devtools/client/debugger/new/test/mochitest/head.js b/devtools/client/debugger/new/test/mochitest/head.js index 71b4816bddfd..cda5800ec386 100644 --- a/devtools/client/debugger/new/test/mochitest/head.js +++ b/devtools/client/debugger/new/test/mochitest/head.js @@ -504,7 +504,7 @@ function stepOut(dbg) { function resume(dbg) { info("Resuming"); dbg.actions.resume(); - return waitForThreadEvents(dbg, "resumed"); + return waitForState(dbg, (state) => !dbg.selectors.isPaused(state)); } function deleteExpression(dbg, input) { diff --git a/devtools/client/locales/en-US/debugger.properties b/devtools/client/locales/en-US/debugger.properties index 970998bbebac..b6328e38a11d 100644 --- a/devtools/client/locales/en-US/debugger.properties +++ b/devtools/client/locales/en-US/debugger.properties @@ -790,3 +790,7 @@ shortcuts.projectSearch=Full Project Search # LOCALIZATION NOTE (shortcuts.functionSearch): text describing # keyboard shortcut action for function search shortcuts.functionSearch=Function Search + +# LOCALIZATION NOTE (shortcuts.buttonName): text describing +# keyboard shortcut button text +shortcuts.buttonName=Keyboard shortcuts diff --git a/devtools/client/preferences/debugger.js b/devtools/client/preferences/debugger.js index 1cfe2dacad7b..0286d8a4d180 100644 --- a/devtools/client/preferences/debugger.js +++ b/devtools/client/preferences/debugger.js @@ -31,7 +31,6 @@ pref("devtools.debugger.ui.variables-only-enum-visible", false); pref("devtools.debugger.ui.variables-searchbox-visible", false); pref("devtools.debugger.ui.framework-grouping-on", true); pref("devtools.debugger.call-stack-visible", false); -pref("devtools.debugger.scopes-visible", false); pref("devtools.debugger.start-panel-collapsed", false); pref("devtools.debugger.end-panel-collapsed", false); pref("devtools.debugger.tabs", "[]"); From 90add213edce2f59c55a0f18aa290ff69cf9fef9 Mon Sep 17 00:00:00 2001 From: Ya-Chieh Wu Date: Sun, 8 Oct 2017 20:06:00 -0400 Subject: [PATCH 28/55] Bug 1406265 - use Set* and Is* instead of changing/getting the member directly. r=dbaron MozReview-Commit-ID: 8l2MzjFGci4 --- layout/tables/celldata.h | 52 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h index e58a8c8823a7..992d85a3acfd 100644 --- a/layout/tables/celldata.h +++ b/layout/tables/celldata.h @@ -194,14 +194,25 @@ public: mozilla::LogicalSide aOwner, bool aBevel); - bool IsIStartStart() const; + inline bool IsIStartStart() const + { + return (bool)mIStartStart; + } - void SetIStartStart(bool aValue); + inline void SetIStartStart(bool aValue) + { + mIStartStart = aValue; + } - bool IsBStartStart() const; - - void SetBStartStart(bool aValue); + inline bool IsBStartStart() const + { + return (bool)mBStartStart; + } + inline void SetBStartStart(bool aValue) + { + mBStartStart = aValue; + } protected: BCPixelSize mIStartSize; // size in pixels of iStart border @@ -371,7 +382,8 @@ inline void CellData::SetOverlap(bool aOverlap) inline BCData::BCData() { mIStartOwner = mBStartOwner = eCellOwner; - mIStartStart = mBStartStart = 1; + SetBStartStart(true); + SetIStartStart(true); mIStartSize = mCornerSubSize = mBStartSize = 0; mCornerSide = mozilla::eLogicalSideBStart; mCornerBevel = false; @@ -385,7 +397,7 @@ inline nscoord BCData::GetIStartEdge(BCBorderOwner& aOwner, bool& aStart) const { aOwner = (BCBorderOwner)mIStartOwner; - aStart = (bool)mIStartStart; + aStart = IsIStartStart(); return (nscoord)mIStartSize; } @@ -396,14 +408,14 @@ inline void BCData::SetIStartEdge(BCBorderOwner aOwner, { mIStartOwner = aOwner; mIStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; - mIStartStart = aStart; + SetIStartStart(aStart); } inline nscoord BCData::GetBStartEdge(BCBorderOwner& aOwner, bool& aStart) const { aOwner = (BCBorderOwner)mBStartOwner; - aStart = (bool)mBStartStart; + aStart = IsBStartStart(); return (nscoord)mBStartSize; } @@ -414,7 +426,7 @@ inline void BCData::SetBStartEdge(BCBorderOwner aOwner, { mBStartOwner = aOwner; mBStartSize = (aSize > MAX_BORDER_WIDTH) ? MAX_BORDER_WIDTH : aSize; - mBStartStart = aStart; + SetBStartStart(aStart); } inline BCPixelSize BCData::GetCorner(mozilla::LogicalSide& aOwnerSide, @@ -434,24 +446,4 @@ inline void BCData::SetCorner(BCPixelSize aSubSize, mCornerBevel = aBevel; } -inline bool BCData::IsIStartStart() const -{ - return (bool)mIStartStart; -} - -inline void BCData::SetIStartStart(bool aValue) -{ - mIStartStart = aValue; -} - -inline bool BCData::IsBStartStart() const -{ - return (bool)mBStartStart; -} - -inline void BCData::SetBStartStart(bool aValue) -{ - mBStartStart = aValue; -} - #endif From ee6e7153ed6fa590084346deff655a48f64165d0 Mon Sep 17 00:00:00 2001 From: "Miran.Karic" Date: Wed, 4 Oct 2017 09:50:00 -0400 Subject: [PATCH 29/55] Bug 1403635 - MIPS: Add MIPS R1 support. r=bbouvier Many tests fail on MIPS R1 boards because R2 instructions are emitted. This patch adds architecture detection for R2, along existing one for Loongson. Instruction sequences that are emitted for R1 instead of R2 instructions are added to macro assembler. --- .../mips-shared/Architecture-mips-shared.cpp | 10 ++ .../mips-shared/Architecture-mips-shared.h | 2 + .../jit/mips-shared/Assembler-mips-shared.cpp | 21 +++- .../mips-shared/CodeGenerator-mips-shared.cpp | 4 +- .../MacroAssembler-mips-shared-inl.h | 4 +- .../MacroAssembler-mips-shared.cpp | 118 ++++++++++++++++-- .../mips-shared/MacroAssembler-mips-shared.h | 8 ++ js/src/jit/mips64/CodeGenerator-mips64.cpp | 6 +- js/src/jit/mips64/MacroAssembler-mips64.cpp | 4 +- 9 files changed, 154 insertions(+), 23 deletions(-) diff --git a/js/src/jit/mips-shared/Architecture-mips-shared.cpp b/js/src/jit/mips-shared/Architecture-mips-shared.cpp index 4fcf2c90e4ee..8a83398b6943 100644 --- a/js/src/jit/mips-shared/Architecture-mips-shared.cpp +++ b/js/src/jit/mips-shared/Architecture-mips-shared.cpp @@ -13,6 +13,7 @@ #define HWCAP_MIPS (1 << 28) #define HWCAP_LOONGSON (1 << 27) +#define HWCAP_R2 (1 << 26) #define HWCAP_FPU (1 << 0) namespace js { @@ -25,6 +26,7 @@ get_mips_flags() #if defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64) flags |= HWCAP_FPU; + flags |= HWCAP_R2; #else # ifdef __linux__ FILE* fp = fopen("/proc/cpuinfo", "r"); @@ -39,6 +41,8 @@ get_mips_flags() flags |= HWCAP_FPU; if (strstr(buf, "Loongson")) flags |= HWCAP_LOONGSON; + if (strstr(buf, "mips32r2") || strstr(buf, "mips64r2")) + flags |= HWCAP_R2; # endif #endif // JS_SIMULATOR_MIPS32 || JS_SIMULATOR_MIPS64 return flags; @@ -54,11 +58,17 @@ static bool check_loongson() return mips_private::Flags & HWCAP_LOONGSON; } +static bool check_r2() +{ + return mips_private::Flags & HWCAP_R2; +} + namespace mips_private { // Cache a local copy so we only have to read /proc/cpuinfo once. uint32_t Flags = get_mips_flags(); bool hasFPU = check_fpu();; bool isLoongson = check_loongson(); + bool hasR2 = check_r2(); } Registers::Code diff --git a/js/src/jit/mips-shared/Architecture-mips-shared.h b/js/src/jit/mips-shared/Architecture-mips-shared.h index 462e8b25105c..0d5f61e76428 100644 --- a/js/src/jit/mips-shared/Architecture-mips-shared.h +++ b/js/src/jit/mips-shared/Architecture-mips-shared.h @@ -314,11 +314,13 @@ namespace mips_private { extern uint32_t Flags; extern bool hasFPU; extern bool isLoongson; + extern bool hasR2; } inline uint32_t GetMIPSFlags() { return mips_private::Flags; } inline bool hasFPU() { return mips_private::hasFPU; } inline bool isLoongson() { return mips_private::isLoongson; } +inline bool hasR2() { return mips_private::hasR2; } // MIPS doesn't have double registers that can NOT be treated as float32. inline bool diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.cpp b/js/src/jit/mips-shared/Assembler-mips-shared.cpp index 46192dbd94f9..0f1f02b1bab1 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/Assembler-mips-shared.cpp @@ -714,6 +714,7 @@ AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); spew("rotr %3s,%3s, 0x%x", rd.name(), rt.name(), sa); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode()); } @@ -722,6 +723,7 @@ AssemblerMIPSShared::as_drotr(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(sa < 32); spew("drotr %3s,%3s, 0x%x", rd.name(), rt.name(), sa); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode()); } @@ -730,6 +732,7 @@ AssemblerMIPSShared::as_drotr32(Register rd, Register rt, uint16_t sa) { MOZ_ASSERT(31 < sa && sa < 64); spew("drotr32%3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode()); } @@ -737,6 +740,7 @@ BufferOffset AssemblerMIPSShared::as_rotrv(Register rd, Register rt, Register rs) { spew("rotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode()); } @@ -744,6 +748,7 @@ BufferOffset AssemblerMIPSShared::as_drotrv(Register rd, Register rt, Register rs) { spew("drotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode()); } @@ -1076,6 +1081,7 @@ AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t siz Register rd; rd = Register::FromCode(pos + size - 1); spew("ins %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode()); } @@ -1086,6 +1092,7 @@ AssemblerMIPSShared::as_dins(Register rt, Register rs, uint16_t pos, uint16_t si Register rd; rd = Register::FromCode(pos + size - 1); spew("dins %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode()); } @@ -1096,6 +1103,7 @@ AssemblerMIPSShared::as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t s Register rd; rd = Register::FromCode(pos + size - 1 - 32); spew("dinsm %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode()); } @@ -1106,6 +1114,7 @@ AssemblerMIPSShared::as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t s Register rd; rd = Register::FromCode(pos + size - 1 - 32); spew("dinsu %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode()); } @@ -1116,6 +1125,7 @@ AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t siz Register rd; rd = Register::FromCode(size - 1); spew("ext %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode()); } @@ -1124,6 +1134,7 @@ BufferOffset AssemblerMIPSShared::as_seb(Register rd, Register rt) { spew("seb %3s,%3s", rd.name(), rt.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode()); } @@ -1131,6 +1142,7 @@ BufferOffset AssemblerMIPSShared::as_seh(Register rd, Register rt) { spew("seh %3s,%3s", rd.name(), rt.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode()); } @@ -1141,6 +1153,7 @@ AssemblerMIPSShared::as_dext(Register rt, Register rs, uint16_t pos, uint16_t si Register rd; rd = Register::FromCode(size - 1); spew("dext %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode()); } @@ -1151,7 +1164,8 @@ AssemblerMIPSShared::as_dextm(Register rt, Register rs, uint16_t pos, uint16_t s Register rd; rd = Register::FromCode(size - 1 - 32); spew("dextm %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); - return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode()); + MOZ_ASSERT(hasR2()); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode()); } BufferOffset @@ -1161,6 +1175,7 @@ AssemblerMIPSShared::as_dextu(Register rt, Register rs, uint16_t pos, uint16_t s Register rd; rd = Register::FromCode(size - 1); spew("dextu %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode()); } @@ -1412,6 +1427,7 @@ BufferOffset AssemblerMIPSShared::as_truncls(FloatRegister fd, FloatRegister fs) { spew("trunc.l.s%3s,%3s", fd.name(), fs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_l_fmt).encode()); } @@ -1447,6 +1463,7 @@ BufferOffset AssemblerMIPSShared::as_truncld(FloatRegister fd, FloatRegister fs) { spew("trunc.l.d%3s,%3s", fd.name(), fs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_l_fmt).encode()); } @@ -1454,6 +1471,7 @@ BufferOffset AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs) { spew("cvt.d.l%3s,%3s", fd.name(), fs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode()); } @@ -1482,6 +1500,7 @@ BufferOffset AssemblerMIPSShared::as_cvtsl(FloatRegister fd, FloatRegister fs) { spew("cvt.s.l%3s,%3s", fd.name(), fs.name()); + MOZ_ASSERT(hasR2()); return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_s_fmt).encode()); } diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 61aa7c3388d8..7d168b7c2a8e 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -1580,7 +1580,7 @@ CodeGeneratorMIPSShared::visitCopySignF(LCopySignF* ins) masm.moveFromFloat32(rhs, rhsi); // Combine. - masm.as_ins(rhsi, lhsi, 0, 31); + masm.ma_ins(rhsi, lhsi, 0, 31); masm.moveToFloat32(rhsi, output); } @@ -1600,7 +1600,7 @@ CodeGeneratorMIPSShared::visitCopySignD(LCopySignD* ins) masm.moveFromDoubleHi(rhs, rhsi); // Combine. - masm.as_ins(rhsi, lhsi, 0, 31); + masm.ma_ins(rhsi, lhsi, 0, 31); masm.moveToDoubleHi(rhsi, output); } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index a8637793b162..75703666df48 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -29,13 +29,13 @@ MacroAssembler::moveGPRToFloat32(Register src, FloatRegister dest) void MacroAssembler::move8SignExtend(Register src, Register dest) { - as_seb(dest, src); + ma_seb(dest, src); } void MacroAssembler::move16SignExtend(Register src, Register dest) { - as_seh(dest, src); + ma_seh(dest, src); } // =============================================================== diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp index 92ee55ca6928..08e39f0f12e8 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp @@ -71,13 +71,27 @@ MacroAssemblerMIPSShared::ma_sra(Register rd, Register rt, Imm32 shift) void MacroAssemblerMIPSShared::ma_ror(Register rd, Register rt, Imm32 shift) { - as_rotr(rd, rt, shift.value % 32); + if (hasR2()) { + as_rotr(rd, rt, shift.value % 32); + } else { + ScratchRegisterScope scratch(asMasm()); + as_srl(scratch, rt, shift.value % 32); + as_sll(rd, rt, (32 - (shift.value % 32)) % 32); + as_or(rd, rd, scratch); + } } void MacroAssemblerMIPSShared::ma_rol(Register rd, Register rt, Imm32 shift) { - as_rotr(rd, rt, 32 - (shift.value % 32)); + if (hasR2()) { + as_rotr(rd, rt, (32 - (shift.value % 32)) % 32); + } else { + ScratchRegisterScope scratch(asMasm()); + as_srl(scratch, rt, (32 - (shift.value % 32)) % 32); + as_sll(rd, rt, shift.value % 32); + as_or(rd, rd, scratch); + } } void @@ -101,14 +115,29 @@ MacroAssemblerMIPSShared::ma_sra(Register rd, Register rt, Register shift) void MacroAssemblerMIPSShared::ma_ror(Register rd, Register rt, Register shift) { - as_rotrv(rd, rt, shift); + if (hasR2()) { + as_rotrv(rd, rt, shift); + } else { + ScratchRegisterScope scratch(asMasm()); + ma_negu(scratch, shift); + as_sllv(scratch, rt, scratch); + as_srlv(rd, rt, shift); + as_or(rd, rd, scratch); + } } void MacroAssemblerMIPSShared::ma_rol(Register rd, Register rt, Register shift) { - ma_negu(ScratchRegister, shift); - as_rotrv(rd, rt, ScratchRegister); + ScratchRegisterScope scratch(asMasm()); + ma_negu(scratch, shift); + if (hasR2()) { + as_rotrv(rd, rt, scratch); + } else { + as_srlv(rd, rt, scratch); + as_sllv(scratch, rt, shift); + as_or(rd, rd, scratch); + } } void @@ -123,6 +152,69 @@ MacroAssemblerMIPSShared::ma_not(Register rd, Register rs) as_nor(rd, rs, zero); } +// Bit extract/insert +void +MacroAssemblerMIPSShared::ma_ext(Register rt, Register rs, uint16_t pos, uint16_t size) { + MOZ_ASSERT(pos < 32); + MOZ_ASSERT(pos + size < 33); + + if (hasR2()) { + as_ext(rt, rs, pos, size); + } else { + int shift_left = 32 - (pos + size); + as_sll(rt, rs, shift_left); + int shift_right = 32 - size; + if (shift_right > 0) { + as_srl(rt, rt, shift_right); + } + } +} + +void +MacroAssemblerMIPSShared::ma_ins(Register rt, Register rs, uint16_t pos, uint16_t size) { + MOZ_ASSERT(pos < 32); + MOZ_ASSERT(pos + size <= 32); + MOZ_ASSERT(size != 0); + + if (hasR2()) { + as_ins(rt, rs, pos, size); + } else { + ScratchRegisterScope scratch(asMasm()); + SecondScratchRegisterScope scratch2(asMasm()); + ma_subu(scratch, zero, Imm32(1)); + as_srl(scratch, scratch, 32 - size); + as_and(scratch2, rs, scratch); + as_sll(scratch2, scratch2, pos); + as_sll(scratch, scratch, pos); + as_nor(scratch, scratch, zero); + as_and(scratch, rt, scratch); + as_or(rt, scratch2, scratch); + } +} + +// Sign extend +void +MacroAssemblerMIPSShared::ma_seb(Register rd, Register rt) +{ + if (hasR2()) { + as_seb(rd, rt); + } else { + as_sll(rd, rt, 24); + as_sra(rd, rd, 24); + } +} + +void +MacroAssemblerMIPSShared::ma_seh(Register rd, Register rt) +{ + if (hasR2()) { + as_seh(rd, rt); + } else { + as_sll(rd, rt, 16); + as_sra(rd, rd, 16); + } +} + // And. void MacroAssemblerMIPSShared::ma_and(Register rd, Register rs) @@ -484,7 +576,7 @@ MacroAssemblerMIPSShared::ma_load_unaligned(Register dest, const BaseIndex& src, as_lbu(temp, base, hiOffset); else as_lb(temp, base, hiOffset); - as_ins(dest, temp, 8, 24); + ma_ins(dest, temp, 8, 24); break; case SizeWord: as_lwl(dest, base, hiOffset); @@ -627,7 +719,7 @@ MacroAssemblerMIPSShared::ma_store_unaligned(Register data, const BaseIndex& des switch (size) { case SizeHalfWord: as_sb(data, base, lowOffset); - as_ext(temp, data, 8, 8); + ma_ext(temp, data, 8, 8); as_sb(temp, base, hiOffset); break; case SizeWord: @@ -1243,10 +1335,10 @@ MacroAssemblerMIPSShared::atomicFetchOpMIPSr2(int nbytes, bool signExtend, Atomi if (signExtend) { switch (nbytes) { case 1: - as_seb(output, output); + ma_seb(output, output); break; case 2: - as_seh(output, output); + ma_seh(output, output); break; case 4: break; @@ -1418,10 +1510,10 @@ MacroAssemblerMIPSShared::compareExchangeMIPSr2(int nbytes, bool signExtend, con if (signExtend) { switch (nbytes) { case 1: - as_seb(output, output); + ma_seb(output, output); break; case 2: - as_seh(output, output); + ma_seh(output, output); break; case 4: break; @@ -1769,7 +1861,7 @@ MacroAssembler::wasmTruncateDoubleToInt32(FloatRegister input, Register output, as_truncwd(ScratchFloat32Reg, input); as_cfc1(ScratchRegister, Assembler::FCSR); moveFromFloat32(ScratchFloat32Reg, output); - as_ext(ScratchRegister, ScratchRegister, 6, 1); + ma_ext(ScratchRegister, ScratchRegister, 6, 1); ma_b(ScratchRegister, Imm32(0), oolEntry, Assembler::NotEqual); } @@ -1780,7 +1872,7 @@ MacroAssembler::wasmTruncateFloat32ToInt32(FloatRegister input, Register output, as_truncws(ScratchFloat32Reg, input); as_cfc1(ScratchRegister, Assembler::FCSR); moveFromFloat32(ScratchFloat32Reg, output); - as_ext(ScratchRegister, ScratchRegister, 6, 1); + ma_ext(ScratchRegister, ScratchRegister, 6, 1); ma_b(ScratchRegister, Imm32(0), oolEntry, Assembler::NotEqual); } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h index 60e945753c4b..615d80e614ca 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.h @@ -85,6 +85,14 @@ class MacroAssemblerMIPSShared : public Assembler void ma_not(Register rd, Register rs); + // Bit extract/insert + void ma_ext(Register rt, Register rs, uint16_t pos, uint16_t size); + void ma_ins(Register rt, Register rs, uint16_t pos, uint16_t size); + + // Sign extend + void ma_seb(Register rd, Register rt); + void ma_seh(Register rd, Register rt); + // and void ma_and(Register rd, Register rs); void ma_and(Register rd, Imm32 imm); diff --git a/js/src/jit/mips64/CodeGenerator-mips64.cpp b/js/src/jit/mips64/CodeGenerator-mips64.cpp index a9254a58eaae..5d99683cafd8 100644 --- a/js/src/jit/mips64/CodeGenerator-mips64.cpp +++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp @@ -683,7 +683,7 @@ CodeGeneratorMIPS64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) masm.moveFromDouble(ScratchDoubleReg, output); masm.as_cfc1(ScratchRegister, Assembler::FCSR); // extract invalid operation flag (bit 6) from FCSR - masm.as_ext(ScratchRegister, ScratchRegister, 6, 1); + masm.ma_ext(ScratchRegister, ScratchRegister, 6, 1); masm.ma_dsrl(SecondScratchReg, output, Imm32(63)); masm.ma_or(SecondScratchReg, ScratchRegister); masm.ma_b(SecondScratchReg, Imm32(0), ool->entry(), Assembler::NotEqual); @@ -703,7 +703,7 @@ CodeGeneratorMIPS64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) // Check that the result is in the uint64_t range. masm.moveFromDouble(ScratchDoubleReg, output); masm.as_cfc1(ScratchRegister, Assembler::FCSR); - masm.as_ext(ScratchRegister, ScratchRegister, 6, 1); + masm.ma_ext(ScratchRegister, ScratchRegister, 6, 1); masm.ma_dsrl(SecondScratchReg, output, Imm32(63)); masm.ma_or(SecondScratchReg, ScratchRegister); masm.ma_b(SecondScratchReg, Imm32(0), ool->entry(), Assembler::NotEqual); @@ -724,7 +724,7 @@ CodeGeneratorMIPS64::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir) // Check that the result is in the int64_t range. masm.as_cfc1(output, Assembler::FCSR); - masm.as_ext(output, output, 6, 1); + masm.ma_ext(output, output, 6, 1); masm.ma_b(output, Imm32(0), ool->entry(), Assembler::NotEqual); masm.bind(ool->rejoin()); diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 5d0ecc68a6f3..12ed13c9857f 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -2578,7 +2578,7 @@ MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, as_truncld(ScratchDoubleReg, input); moveFromDoubleHi(ScratchDoubleReg, output); as_cfc1(ScratchRegister, Assembler::FCSR); - as_ext(ScratchRegister, ScratchRegister, 6, 1); + ma_ext(ScratchRegister, ScratchRegister, 6, 1); ma_or(ScratchRegister, output); moveFromFloat32(ScratchDoubleReg, output); ma_b(ScratchRegister, Imm32(0), oolEntry, Assembler::NotEqual); @@ -2592,7 +2592,7 @@ MacroAssembler::wasmTruncateFloat32ToUInt32(FloatRegister input, Register output as_truncls(ScratchDoubleReg, input); moveFromDoubleHi(ScratchDoubleReg, output); as_cfc1(ScratchRegister, Assembler::FCSR); - as_ext(ScratchRegister, ScratchRegister, 6, 1); + ma_ext(ScratchRegister, ScratchRegister, 6, 1); ma_or(ScratchRegister, output); moveFromFloat32(ScratchDoubleReg, output); ma_b(ScratchRegister, Imm32(0), oolEntry, Assembler::NotEqual); From 3113c320330d1787525d9ec2d6fe343bb7145220 Mon Sep 17 00:00:00 2001 From: Andreas Farre Date: Mon, 9 Oct 2017 05:16:00 -0400 Subject: [PATCH 30/55] Bug 1377766 - Enable budget throttling by default. r=bkelly --- modules/libpref/init/all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5c12b9cb7789..b7011e0c2512 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1312,8 +1312,8 @@ pref("dom.timeout.foreground_budget_regeneration_rate", 1); pref("dom.timeout.foreground_throttling_max_budget", -1); // The maximum amount a timeout can be delayed by budget throttling pref("dom.timeout.budget_throttling_max_delay", 15000); -// Turn off budget throttling by default -pref("dom.timeout.enable_budget_timer_throttling", false); +// Turn on budget throttling by default +pref("dom.timeout.enable_budget_timer_throttling", true); // Don't use new input types pref("dom.experimental_forms", false); From 2115adfe5cda4175c44661257c038a129346a89e Mon Sep 17 00:00:00 2001 From: Georg Fritzsche Date: Fri, 6 Oct 2017 05:04:00 -0400 Subject: [PATCH 31/55] Bug 1402609 - Part 1: Fix missing rejection handling in Troubleshoot.jsm. r=felipe --- toolkit/modules/Troubleshoot.jsm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index ad87485cc3cf..3a68f83914f3 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -318,7 +318,8 @@ var dataProviders = { // getExperiments promises experiment history Experiments.instance().getExperiments().then( - experiments => done(experiments) + experiments => done(experiments), + () => done([]) ); }, From fceee5b7a0b890eb393a6f1c0590411fe6a2bf54 Mon Sep 17 00:00:00 2001 From: Georg Fritzsche Date: Fri, 6 Oct 2017 05:05:00 -0400 Subject: [PATCH 32/55] Bug 1402609 - Part 2: Make Experiments.jsm recover from unloadable manifest cache. r=Dexter --- browser/experiments/Experiments.jsm | 5 +++-- browser/experiments/test/xpcshell/test_cache.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm index 00df9c10b546..b7c8d7d6be9b 100644 --- a/browser/experiments/Experiments.jsm +++ b/browser/experiments/Experiments.jsm @@ -1040,11 +1040,12 @@ Experiments.Experiments.prototype = { let result = await loadJSONAsync(path, { compression: "lz4" }); this._populateFromCache(result); } catch (e) { + this._experiments = new Map(); if (e instanceof OS.File.Error && e.becauseNoSuchFile) { // No cached manifest yet. - this._experiments = new Map(); + this._log.trace("_loadFromCache - no cached manifest yet"); } else { - throw e; + this._log.error("_loadFromCache - caught error", e); } } }, diff --git a/browser/experiments/test/xpcshell/test_cache.js b/browser/experiments/test/xpcshell/test_cache.js index dccb35443d53..c2e7475fbf2f 100644 --- a/browser/experiments/test/xpcshell/test_cache.js +++ b/browser/experiments/test/xpcshell/test_cache.js @@ -393,3 +393,19 @@ add_task(async function test_expiration() { await promiseRestartManager(); await removeCacheFile(); }); + +add_task(async function test_invalid_cache() { + // Save uncompressed data to the cache file to trigger a loading error. + let encoder = new TextEncoder(); + let data = encoder.encode("foo"); + + let path = OS.Path.join(OS.Constants.Path.profileDir, "experiments.json"); + let options = { tmpPath: path + ".tmp" }; + await OS.File.writeAtomic(path, data, options); + + // Trigger loading from the cache. This should not throw and gracefully recover. + let experiments = new Experiments.Experiments(gPolicy); + let list = await experiments.getExperiments(); + + Assert.deepEqual(list, [], "The experiments cache should be empty."); +}); From d7b893d711c82ca7411b866058e89d9835e27241 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Mon, 9 Oct 2017 17:44:25 +0200 Subject: [PATCH 33/55] Backed out changeset 1779da025280 (bug 1406474) for crashing in reftest and web-platform-tests, e.g. layout/reftests/font-face/download-2-big.html. r=backout on a CLOSED TREE --- gfx/thebes/gfxUserFontSet.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 85ca0f3b392e..1c84ceb128d5 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -403,12 +403,11 @@ public: mPrivate(aKey->mPrivate) { } - Entry(Entry&& aOther) - : mAllowedFontSets(mozilla::Move(mAllowedFontSets)), - mURI(mozilla::Move(aOther.mURI)), - mPrincipal(mozilla::Move(aOther.mPrincipal)), - mFontEntry(mozilla::Move(aOther.mFontEntry)), - mPrivate(mozilla::Move(aOther.mPrivate)) + Entry(const Entry& aOther) + : mURI(aOther.mURI), + mPrincipal(aOther.mPrincipal), + mFontEntry(aOther.mFontEntry), + mPrivate(aOther.mPrivate) { } ~Entry() { } From 3a7ab1ab7851c3d8fe4ea1cf4f72855f1e9072c8 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Mon, 9 Oct 2017 07:50:00 -0400 Subject: [PATCH 34/55] Bug 1405199 - Update result principal URI on the new channel when nsBaseChannel redirects. r=bz --- netwerk/base/nsBaseChannel.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/netwerk/base/nsBaseChannel.cpp b/netwerk/base/nsBaseChannel.cpp index cf17c341dc08..9cdffc81bfb2 100644 --- a/netwerk/base/nsBaseChannel.cpp +++ b/netwerk/base/nsBaseChannel.cpp @@ -106,6 +106,28 @@ nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags, new nsRedirectHistoryEntry(uriPrincipal, nullptr, EmptyCString()); newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect); + + // Ensure the channel's loadInfo's result principal URI so that it's + // either non-null or updated to the redirect target URI. + // We must do this because in case the loadInfo's result principal URI + // is null, it would be taken from OriginalURI of the channel. But we + // overwrite it with the whole redirect chain first URI before opening + // the target channel, hence the information would be lost. + // If the protocol handler that created the channel wants to use + // the originalURI of the channel as the principal URI, it has left + // the result principal URI on the load info null. + nsCOMPtr resultPrincipalURI; + + nsCOMPtr existingLoadInfo = newChannel->GetLoadInfo(); + if (existingLoadInfo) { + existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI)); + } + if (!resultPrincipalURI) { + newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI)); + } + + newLoadInfo->SetResultPrincipalURI(resultPrincipalURI); + newChannel->SetLoadInfo(newLoadInfo); } else { From 49156443d9ae7b174398ba2e0fdb7a4c81a31e6c Mon Sep 17 00:00:00 2001 From: Jorg K Date: Mon, 9 Oct 2017 07:19:00 -0400 Subject: [PATCH 35/55] Bug 1403658 - Add nsString overload for HTMLAnchorElement::GetName() and HTMLBodyElement::GetBackground(), add HTMLBodyElement::FromContentOrNull(). r=bz --- dom/html/HTMLAnchorElement.h | 4 ++++ dom/html/HTMLBodyElement.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/dom/html/HTMLAnchorElement.h b/dom/html/HTMLAnchorElement.h index 2c5d9127dab5..72b2e40015dd 100644 --- a/dom/html/HTMLAnchorElement.h +++ b/dom/html/HTMLAnchorElement.h @@ -201,6 +201,10 @@ public: { GetHTMLAttr(nsGkAtoms::name, aValue); } + void GetName(nsAString& aValue) + { + GetHTMLAttr(nsGkAtoms::name, aValue); + } void SetName(const nsAString& aValue, mozilla::ErrorResult& rv) { SetHTMLAttr(nsGkAtoms::name, aValue, rv); diff --git a/dom/html/HTMLBodyElement.h b/dom/html/HTMLBodyElement.h index df4b67b67e93..d824530d4dbf 100644 --- a/dom/html/HTMLBodyElement.h +++ b/dom/html/HTMLBodyElement.h @@ -32,6 +32,8 @@ public: // nsISupports NS_DECL_ISUPPORTS_INHERITED + NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLBodyElement, body); + // Event listener stuff; we need to declare only the ones we need to // forward to window that don't come from nsIDOMHTMLBodyElement. #define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */ @@ -112,6 +114,10 @@ public: { GetHTMLAttr(nsGkAtoms::background, aBackground); } + void GetBackground(nsAString& aBackground) + { + GetHTMLAttr(nsGkAtoms::background, aBackground); + } void SetBackground(const nsAString& aBackground, ErrorResult& aError) { SetHTMLAttr(nsGkAtoms::background, aBackground, aError); From 2a15781174c3c6ec550c35657ac074daf39addca Mon Sep 17 00:00:00 2001 From: David Keeler Date: Fri, 15 Sep 2017 14:47:54 -0700 Subject: [PATCH 36/55] Bug 1369561 - Address misc. SnprintfLiteral correctness nits. r=jld, r=froydnj --- security/sandbox/linux/SandboxUtil.cpp | 17 ++++++++++------- xpcom/base/nsSystemInfo.cpp | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/security/sandbox/linux/SandboxUtil.cpp b/security/sandbox/linux/SandboxUtil.cpp index ad6003ecaad5..999329882364 100644 --- a/security/sandbox/linux/SandboxUtil.cpp +++ b/security/sandbox/linux/SandboxUtil.cpp @@ -62,7 +62,6 @@ UnshareUserNamespace() uid_t uid = getuid(); gid_t gid = getgid(); char buf[80]; - size_t len; if (syscall(__NR_unshare, CLONE_NEWUSER) != 0) { return false; @@ -84,17 +83,21 @@ UnshareUserNamespace() // current thread. However, CLONE_NEWUSER can be unshared only in a // single-threaded process, so those are equivalent if we reach this // point. - len = size_t(SprintfLiteral(buf, "%u %u 1\n", uid, uid)); - MOZ_ASSERT(len < sizeof(buf)); - if (!WriteStringToFile("/proc/self/uid_map", buf, len)) { + int len = SprintfLiteral(buf, "%u %u 1\n", uid, uid); + if (len >= int(sizeof(buf)) || len < 0) { + return false; + } + if (!WriteStringToFile("/proc/self/uid_map", buf, size_t(len))) { MOZ_CRASH("Failed to write /proc/self/uid_map"); } Unused << WriteStringToFile("/proc/self/setgroups", "deny", 4); - len = size_t(SprintfLiteral(buf, "%u %u 1\n", gid, gid)); - MOZ_ASSERT(len < sizeof(buf)); - if (!WriteStringToFile("/proc/self/gid_map", buf, len)) { + len = SprintfLiteral(buf, "%u %u 1\n", gid, gid); + if (len >= int(sizeof(buf)) || len < 0) { + return false; + } + if (!WriteStringToFile("/proc/self/gid_map", buf, size_t(len))) { MOZ_CRASH("Failed to write /proc/self/gid_map"); } return true; diff --git a/xpcom/base/nsSystemInfo.cpp b/xpcom/base/nsSystemInfo.cpp index e5a7fe97be03..782dc9abf37d 100644 --- a/xpcom/base/nsSystemInfo.cpp +++ b/xpcom/base/nsSystemInfo.cpp @@ -706,7 +706,7 @@ nsSystemInfo::Init() } nsAutoCString secondaryLibrary; - if (gtkver_len > 0) { + if (gtkver_len > 0 && gtkver_len < int(sizeof(gtkver))) { secondaryLibrary.Append(nsDependentCSubstring(gtkver, gtkver_len)); } From 20f23200cd52e484b6762d71ac89372327709cc7 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:40 -0700 Subject: [PATCH 37/55] Bug 1391693 P1 Rename nsIInterceptedChannel.cancel() to cancelInterception() r=jdm --- docshell/base/nsDocShell.cpp | 2 +- dom/workers/ServiceWorkerEvents.cpp | 10 +++++----- netwerk/base/nsINetworkInterceptController.idl | 2 +- netwerk/protocol/http/HttpChannelParentListener.cpp | 2 +- netwerk/protocol/http/InterceptedChannel.cpp | 4 ++-- netwerk/protocol/http/InterceptedChannel.h | 4 ++-- netwerk/test/unit/test_synthesized_response.js | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index c7ba6e0fdb2b..c396c820251b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -15066,7 +15066,7 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel) { RefPtr swm = ServiceWorkerManager::GetInstance(); if (!swm) { - aChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED); + aChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); return NS_OK; } diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index cef2933b0d77..a5f3e35deade 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -115,7 +115,7 @@ CancelChannelRunnable::Run() mChannel->SetHandleFetchEventEnd(TimeStamp::Now()); mChannel->SaveTimeStamps(); - mChannel->Cancel(mStatus); + mChannel->CancelInterception(mStatus); mRegistration->MaybeScheduleUpdate(); return NS_OK; } @@ -199,7 +199,7 @@ public: nsCOMPtr loadInfo = underlyingChannel->GetLoadInfo(); if (!loadInfo || !CSPPermitsResponse(loadInfo)) { - mChannel->Cancel(NS_ERROR_CONTENT_BLOCKED); + mChannel->CancelInterception(NS_ERROR_CONTENT_BLOCKED); return NS_OK; } @@ -213,14 +213,14 @@ public: } rv = mChannel->SetChannelInfo(&channelInfo); if (NS_WARN_IF(NS_FAILED(rv))) { - mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED); + mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); return NS_OK; } rv = mChannel->SynthesizeStatus(mInternalResponse->GetUnfilteredStatus(), mInternalResponse->GetUnfilteredStatusText()); if (NS_WARN_IF(NS_FAILED(rv))) { - mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED); + mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); return NS_OK; } @@ -235,7 +235,7 @@ public: rv = mChannel->FinishSynthesizedResponse(mResponseURLSpec); if (NS_WARN_IF(NS_FAILED(rv))) { - mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED); + mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); return NS_OK; } diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl index b3cdc3aed680..f56313a118ed 100644 --- a/netwerk/base/nsINetworkInterceptController.idl +++ b/netwerk/base/nsINetworkInterceptController.idl @@ -68,7 +68,7 @@ interface nsIInterceptedChannel : nsISupports * @return NS_ERROR_FAILURE if the response has already been synthesized or * the original request has been instructed to continue. */ - void cancel(in nsresult status); + void cancelInterception(in nsresult status); /** * The synthesized response body to be produced. diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp index 2066f162a0cc..bff502ae9282 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -408,7 +408,7 @@ void HttpChannelParentListener::ClearInterceptedChannel() { if (mInterceptedChannel) { - mInterceptedChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED); + mInterceptedChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); mInterceptedChannel = nullptr; } } diff --git a/netwerk/protocol/http/InterceptedChannel.cpp b/netwerk/protocol/http/InterceptedChannel.cpp index 2edccb90127e..4f98e2bb0e48 100644 --- a/netwerk/protocol/http/InterceptedChannel.cpp +++ b/netwerk/protocol/http/InterceptedChannel.cpp @@ -373,7 +373,7 @@ InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLS } NS_IMETHODIMP -InterceptedChannelChrome::Cancel(nsresult aStatus) +InterceptedChannelChrome::CancelInterception(nsresult aStatus) { MOZ_ASSERT(NS_FAILED(aStatus)); @@ -541,7 +541,7 @@ InterceptedChannelContent::FinishSynthesizedResponse(const nsACString& aFinalURL } NS_IMETHODIMP -InterceptedChannelContent::Cancel(nsresult aStatus) +InterceptedChannelContent::CancelInterception(nsresult aStatus) { MOZ_ASSERT(NS_FAILED(aStatus)); diff --git a/netwerk/protocol/http/InterceptedChannel.h b/netwerk/protocol/http/InterceptedChannel.h index 16c256ea44a3..dd5550c70842 100644 --- a/netwerk/protocol/http/InterceptedChannel.h +++ b/netwerk/protocol/http/InterceptedChannel.h @@ -190,7 +190,7 @@ public: NS_IMETHOD GetSecureUpgradedChannelURI(nsIURI** aURI) override; NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override; NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override; - NS_IMETHOD Cancel(nsresult aStatus) override; + NS_IMETHOD CancelInterception(nsresult aStatus) override; NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override; NS_IMETHOD GetInternalContentPolicyType(nsContentPolicyType *aInternalContentPolicyType) override; @@ -223,7 +223,7 @@ public: NS_IMETHOD GetSecureUpgradedChannelURI(nsIURI** aURI) override; NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override; NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override; - NS_IMETHOD Cancel(nsresult aStatus) override; + NS_IMETHOD CancelInterception(nsresult aStatus) override; NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override; NS_IMETHOD GetInternalContentPolicyType(nsContentPolicyType *aInternalContentPolicyType) override; diff --git a/netwerk/test/unit/test_synthesized_response.js b/netwerk/test/unit/test_synthesized_response.js index b7a1b72fec1a..5668ba5020b1 100644 --- a/netwerk/test/unit/test_synthesized_response.js +++ b/netwerk/test/unit/test_synthesized_response.js @@ -183,7 +183,7 @@ add_test(function() { // ensure that the intercepted channel can be cancelled add_test(function() { var chan = make_channel(URL + '/body', null, function(intercepted) { - intercepted.cancel(Cr.NS_BINDING_ABORTED); + intercepted.cancelInterception(Cr.NS_BINDING_ABORTED); }); chan.asyncOpen2(new ChannelListener(run_next_test, null, CL_EXPECT_FAILURE)); }); @@ -195,7 +195,7 @@ add_test(function() { do_timeout(0, function() { var gotexception = false; try { - chan.cancel(); + chan.cancelInterception(); } catch (x) { gotexception = true; } From 9ed7291825223cdcf0704b88b1daf62ea2bfb096 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:40 -0700 Subject: [PATCH 38/55] Bug 1391693 P2 Only validate docloader channel on redirect if its been set. r=smaug --- uriloader/base/nsDocLoader.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp index 7d345fa71f91..81224954ed75 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp @@ -1450,8 +1450,12 @@ NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel, stateFlags |= nsIWebProgressListener::STATE_IS_DOCUMENT; #if defined(DEBUG) - nsCOMPtr request(do_QueryInterface(aOldChannel)); - NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel"); + // We only set mDocumentRequest in OnStartRequest(), but its possible + // to get a redirect before that for service worker interception. + if (mDocumentRequest) { + nsCOMPtr request(do_QueryInterface(aOldChannel)); + NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel"); + } #endif /* DEBUG */ } From eec881a235fa0d1ea5677c8d98681ad9920e6d68 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:40 -0700 Subject: [PATCH 39/55] Bug 1391693 P3 Allow CSP report channels to be internally redirected. r=ckerschb --- dom/security/nsCSPContext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp index b56384f8ec7f..04fcae847878 100644 --- a/dom/security/nsCSPContext.cpp +++ b/dom/security/nsCSPContext.cpp @@ -1528,6 +1528,11 @@ CSPReportRedirectSink::AsyncOnChannelRedirect(nsIChannel* aOldChannel, uint32_t aRedirFlags, nsIAsyncVerifyRedirectCallback* aCallback) { + if (aRedirFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { + aCallback->OnRedirectVerifyCallback(NS_OK); + return NS_OK; + } + // cancel the old channel so XHR failure callback happens nsresult rv = aOldChannel->Cancel(NS_ERROR_ABORT); NS_ENSURE_SUCCESS(rv, rv); From 47571637f3c51b0333a1966ad376b930f7d3a4c6 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:40 -0700 Subject: [PATCH 40/55] Bug 1391693 P4 Don't count internal redirects towards Response.redirected r=tt --- dom/fetch/FetchDriver.cpp | 48 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index f3d021c9c23b..c69a41e3951a 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -872,26 +872,32 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, } // "HTTP-redirect fetch": step 14 "Append locationURL to request's URL list." - nsCOMPtr uri; - MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri))); + // However, ignore internal redirects here. We don't want to flip + // Response.redirected to true if an internal redirect occurs. These + // should be transparent to script. + if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) { + nsCOMPtr uri; + MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri))); - nsCOMPtr uriClone; - nsresult rv = uri->CloneIgnoringRef(getter_AddRefs(uriClone)); - if(NS_WARN_IF(NS_FAILED(rv))){ - return rv; - } - nsCString spec; - rv = uriClone->GetSpec(spec); - if(NS_WARN_IF(NS_FAILED(rv))){ - return rv; - } - nsCString fragment; - rv = uri->GetRef(fragment); - if(NS_WARN_IF(NS_FAILED(rv))){ - return rv; + nsCOMPtr uriClone; + nsresult rv = uri->CloneIgnoringRef(getter_AddRefs(uriClone)); + if(NS_WARN_IF(NS_FAILED(rv))){ + return rv; + } + nsCString spec; + rv = uriClone->GetSpec(spec); + if(NS_WARN_IF(NS_FAILED(rv))){ + return rv; + } + nsCString fragment; + rv = uri->GetRef(fragment); + if(NS_WARN_IF(NS_FAILED(rv))){ + return rv; + } + + mRequest->AddURL(spec, fragment); } - mRequest->AddURL(spec, fragment); NS_ConvertUTF8toUTF16 tRPHeaderValue(tRPHeaderCValue); // updates request’s associated referrer policy according to the // Referrer-Policy header (if any). @@ -902,10 +908,10 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel, mRequest->SetReferrerPolicy(net_referrerPolicy); // Should update channel's referrer policy if (httpChannel) { - rv = FetchUtil::SetRequestReferrer(mPrincipal, - mDocument, - httpChannel, - mRequest); + nsresult rv = FetchUtil::SetRequestReferrer(mPrincipal, + mDocument, + httpChannel, + mRequest); NS_ENSURE_SUCCESS(rv, rv); } } From b4550ab09acaaba84ac0148cc51513e21e62c02b Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:40 -0700 Subject: [PATCH 41/55] Bug 1391693 P5 Move some helper methods from nsHttpChannel to HttpBaseChannel. r=valentin --- netwerk/protocol/http/HttpBaseChannel.h | 30 +++++++++++++++++++++++++ netwerk/protocol/http/nsHttpChannel.h | 21 ----------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 08aacff1eb5e..26a716bb93c3 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -371,6 +371,36 @@ public: /* Necko internal use only... */ return mChannelId; } + void InternalSetUploadStream(nsIInputStream *uploadStream) + { + mUploadStream = uploadStream; + } + + void SetUploadStreamHasHeaders(bool hasHeaders) + { + mUploadStreamHasHeaders = hasHeaders; + } + + MOZ_MUST_USE nsresult + SetReferrerWithPolicyInternal(nsIURI *referrer, uint32_t referrerPolicy) + { + nsAutoCString spec; + nsresult rv = referrer->GetAsciiSpec(spec); + if (NS_FAILED(rv)) { + return rv; + } + mReferrer = referrer; + mReferrerPolicy = referrerPolicy; + rv = mRequestHead.SetHeader(nsHttp::Referer, spec); + return rv; + } + + MOZ_MUST_USE nsresult SetTopWindowURI(nsIURI* aTopWindowURI) + { + mTopWindowURI = aTopWindowURI; + return NS_OK; + } + protected: // Handle notifying listener, removing from loadgroup if request failed. void DoNotifyListener(); diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index d0209fde42eb..0d9672140efe 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -203,27 +203,6 @@ public: /* internal necko use only */ using InitLocalBlockListCallback = std::function; - void InternalSetUploadStream(nsIInputStream *uploadStream) - { mUploadStream = uploadStream; } - void SetUploadStreamHasHeaders(bool hasHeaders) - { mUploadStreamHasHeaders = hasHeaders; } - - MOZ_MUST_USE nsresult - SetReferrerWithPolicyInternal(nsIURI *referrer, uint32_t referrerPolicy) { - nsAutoCString spec; - nsresult rv = referrer->GetAsciiSpec(spec); - if (NS_FAILED(rv)) return rv; - mReferrer = referrer; - mReferrerPolicy = referrerPolicy; - rv = mRequestHead.SetHeader(nsHttp::Referer, spec); - return rv; - } - - MOZ_MUST_USE nsresult SetTopWindowURI(nsIURI* aTopWindowURI) { - mTopWindowURI = aTopWindowURI; - return NS_OK; - } - uint32_t GetRequestTime() const { return mRequestTime; From 91eddc52d475b0d9fc23c2cdf1cbf1aa7f7ac4c3 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:41 -0700 Subject: [PATCH 42/55] Bug 1391693 P6 Make HttpChannelParent operate on HttpBaseChannel objects instead of nsHttpChannel directly. r=valentin --- netwerk/protocol/http/HttpChannelParent.cpp | 166 ++++++++++++-------- netwerk/protocol/http/HttpChannelParent.h | 2 +- 2 files changed, 101 insertions(+), 67 deletions(-) diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 34679442c784..d5c3a7666467 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -235,8 +235,9 @@ HttpChannelParent::CleanupBackgroundChannel() // The nsHttpChannel may have a reference to this parent, release it // to avoid circular references. - if (mChannel) { - mChannel->SetWarningReporter(nullptr); + RefPtr httpChannelImpl = do_QueryObject(mChannel); + if (httpChannelImpl) { + httpChannelImpl->SetWarningReporter(nullptr); } if (!mPromise.IsEmpty()) { @@ -521,7 +522,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, return SendFailedAsyncOpen(rv); } - RefPtr httpChannel = do_QueryObject(channel, &rv); + RefPtr httpChannel = do_QueryObject(channel, &rv); if (NS_FAILED(rv)) { return SendFailedAsyncOpen(rv); } @@ -531,7 +532,10 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, httpChannel->SetTopLevelContentWindowId(aContentWindowId); httpChannel->SetTopLevelOuterContentWindowId(aTopLevelOuterContentWindowId); - httpChannel->SetWarningReporter(this); + RefPtr httpChannelImpl = do_QueryObject(httpChannel); + if (httpChannelImpl) { + httpChannelImpl->SetWarningReporter(this); + } httpChannel->SetTimingEnabled(true); if (mPBOverride != kPBOverride_Unset) { httpChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); @@ -566,8 +570,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader); } else { httpChannel->SetRequestHeader(requestHeaders[i].mHeader, - requestHeaders[i].mValue, - requestHeaders[i].mMerge); + requestHeaders[i].mValue, + requestHeaders[i].mMerge); } } @@ -645,7 +649,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) { parentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead()); mWillSynthesizeResponse = true; - httpChannel->SetCouldBeSynthesized(); + httpChannelImpl->SetCouldBeSynthesized(); if (!aSecurityInfoSerialization.IsEmpty()) { nsCOMPtr secInfo; @@ -671,10 +675,14 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, return SendFailedAsyncOpen(rv); } - httpChannel->SetCacheKey(cacheKey); - httpChannel->PreferAlternativeDataType(aPreferredAlternativeType); + nsCOMPtr cacheChannel = + do_QueryInterface(static_cast(httpChannel.get())); + if (cacheChannel) { + cacheChannel->SetCacheKey(cacheKey); + cacheChannel->PreferAlternativeDataType(aPreferredAlternativeType); - httpChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent); + cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent); + } httpChannel->SetContentType(aContentTypeHint); @@ -814,14 +822,17 @@ HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shoul LOG((" found channel %p, rv=%08" PRIx32, channel.get(), static_cast(rv))); mChannel = do_QueryObject(channel); if (!mChannel) { - LOG((" but it's not nsHttpChannel")); + LOG((" but it's not HttpBaseChannel")); Delete(); return true; } - LOG((" and it is nsHttpChannel %p", mChannel.get())); + LOG((" and it is HttpBaseChannel %p", mChannel.get())); - mChannel->SetWarningReporter(this); + RefPtr httpChannelImpl = do_QueryObject(mChannel); + if (httpChannelImpl) { + httpChannelImpl->SetWarningReporter(this); + } nsCOMPtr controller; NS_QueryNotificationCallbacks(channel, controller); @@ -1409,15 +1420,15 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) MOZ_RELEASE_ASSERT(!mDivertingFromChild, "Cannot call OnStartRequest if diverting is set!"); - RefPtr chan = do_QueryObject(aRequest); + RefPtr chan = do_QueryObject(aRequest); if (!chan) { - LOG((" aRequest is not nsHttpChannel")); - NS_ERROR("Expecting only nsHttpChannel as aRequest in HttpChannelParent::OnStartRequest"); + LOG((" aRequest is not HttpBaseChannel")); + NS_ERROR("Expecting only HttpBaseChannel as aRequest in HttpChannelParent::OnStartRequest"); return NS_ERROR_UNEXPECTED; } MOZ_ASSERT(mChannel == chan, - "HttpChannelParent getting OnStartRequest from a different nsHttpChannel instance"); + "HttpChannelParent getting OnStartRequest from a different HttpBaseChannel instance"); // Send down any permissions which are relevant to this URL if we are // performing a document load. We can't do that is mIPCClosed is set. @@ -1432,28 +1443,36 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) nsHttpResponseHead *responseHead = chan->GetResponseHead(); nsHttpRequestHead *requestHead = chan->GetRequestHead(); bool isFromCache = false; - chan->IsFromCache(&isFromCache); int32_t fetchCount = 0; - chan->GetCacheTokenFetchCount(&fetchCount); uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME; - chan->GetCacheTokenExpirationTime(&expirationTime); nsCString cachedCharset; - chan->GetCacheTokenCachedCharset(cachedCharset); - bool loadedFromApplicationCache; - chan->GetLoadedFromApplicationCache(&loadedFromApplicationCache); - if (loadedFromApplicationCache) { - mOfflineForeignMarker = chan->GetOfflineCacheEntryAsForeignMarker(); - nsCOMPtr appCache; - chan->GetApplicationCache(getter_AddRefs(appCache)); - nsCString appCacheGroupId; - nsCString appCacheClientId; - appCache->GetGroupID(appCacheGroupId); - appCache->GetClientID(appCacheClientId); - if (mIPCClosed || - !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId)) - { - return NS_ERROR_UNEXPECTED; + RefPtr httpChannelImpl = do_QueryObject(chan); + + if (httpChannelImpl) { + httpChannelImpl->IsFromCache(&isFromCache); + httpChannelImpl->GetCacheTokenFetchCount(&fetchCount); + httpChannelImpl->GetCacheTokenExpirationTime(&expirationTime); + httpChannelImpl->GetCacheTokenCachedCharset(cachedCharset); + } + + bool loadedFromApplicationCache = false; + + if (httpChannelImpl) { + httpChannelImpl->GetLoadedFromApplicationCache(&loadedFromApplicationCache); + if (loadedFromApplicationCache) { + mOfflineForeignMarker = httpChannelImpl->GetOfflineCacheEntryAsForeignMarker(); + nsCOMPtr appCache; + httpChannelImpl->GetApplicationCache(getter_AddRefs(appCache)); + nsCString appCacheGroupId; + nsCString appCacheClientId; + appCache->GetGroupID(appCacheGroupId); + appCache->GetClientID(appCacheClientId); + if (mIPCClosed || + !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId)) + { + return NS_ERROR_UNEXPECTED; + } } } @@ -1464,11 +1483,32 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset(). // It could be already released by nsHttpChannel at that time. nsCOMPtr cacheEntry; - chan->GetCacheToken(getter_AddRefs(cacheEntry)); - mCacheEntry = do_QueryInterface(cacheEntry); - nsresult channelStatus = NS_OK; - chan->GetStatus(&channelStatus); + uint32_t cacheKeyValue = 0; + nsAutoCString altDataType; + + if (httpChannelImpl) { + httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry)); + mCacheEntry = do_QueryInterface(cacheEntry); + + httpChannelImpl->GetStatus(&channelStatus); + + nsCOMPtr cacheKey; + httpChannelImpl->GetCacheKey(getter_AddRefs(cacheKey)); + if (cacheKey) { + nsCOMPtr container = do_QueryInterface(cacheKey); + if (!container) { + return NS_ERROR_ILLEGAL_VALUE; + } + + nsresult rv = container->GetData(&cacheKeyValue); + if (NS_FAILED(rv)) { + return rv; + } + } + + httpChannelImpl->GetAlternativeDataType(altDataType); + } nsCString secInfoSerialization; UpdateAndSerializeSecurityInfo(secInfoSerialization); @@ -1476,23 +1516,6 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) uint8_t redirectCount = 0; chan->GetRedirectCount(&redirectCount); - nsCOMPtr cacheKey; - chan->GetCacheKey(getter_AddRefs(cacheKey)); - uint32_t cacheKeyValue = 0; - if (cacheKey) { - nsCOMPtr container = do_QueryInterface(cacheKey); - if (!container) { - return NS_ERROR_ILLEGAL_VALUE; - } - - nsresult rv = container->GetData(&cacheKeyValue); - if (NS_FAILED(rv)) { - return rv; - } - } - - nsAutoCString altDataType; - chan->GetAlternativeDataType(altDataType); int64_t altDataLen = chan->GetAltDataLength(); // !!! We need to lock headers and please don't forget to unlock them !!! @@ -1562,7 +1585,10 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest, mChannel->GetCacheReadStart(&timing.cacheReadStart); mChannel->GetCacheReadEnd(&timing.cacheReadEnd); - mChannel->SetWarningReporter(nullptr); + RefPtr httpChannelImpl = do_QueryObject(mChannel); + if (httpChannelImpl) { + httpChannelImpl->SetWarningReporter(nullptr); + } // Either IPC channel is closed or background channel // is ready to send OnStopRequest. @@ -1597,9 +1623,11 @@ HttpChannelParent::OnDataAvailable(nsIRequest *aRequest, nsresult channelStatus = NS_OK; mChannel->GetStatus(&channelStatus); - nsresult transportStatus = - (mChannel->IsReadingFromCache()) ? NS_NET_STATUS_READING - : NS_NET_STATUS_RECEIVING_FROM; + nsresult transportStatus = NS_NET_STATUS_RECEIVING_FROM; + RefPtr httpChannelImpl = do_QueryObject(mChannel); + if (httpChannelImpl && httpChannelImpl->IsReadingFromCache()) { + transportStatus = NS_NET_STATUS_READING; + } static uint32_t const kCopyChunkSize = 128 * 1024; uint32_t toRead = std::min(aCount, kCopyChunkSize); @@ -1798,7 +1826,7 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, // If the channel is a HTTP channel, we also want to inform the child // about the parent's channelId attribute, so that both parent and child // share the same ID. Useful for monitoring channel activity in devtools. - uint64_t channelId; + uint64_t channelId = 0; nsCOMPtr httpChannel = do_QueryInterface(newChannel); if (httpChannel) { rv = httpChannel->GetChannelId(&channelId); @@ -1873,7 +1901,9 @@ HttpChannelParent::SuspendForDiversion() // MessageDiversionStarted call will suspend mEventQ as many times as the // channel has been suspended, so that channel and this queue are in sync. - mChannel->MessageDiversionStarted(this); + nsCOMPtr divertChannel = + do_QueryInterface(static_cast(mChannel.get())); + divertChannel->MessageDiversionStarted(this); nsresult rv = NS_OK; @@ -1889,7 +1919,7 @@ HttpChannelParent::SuspendForDiversion() // OnDataAvailable until diversion is over. At the same time we should // send the diverted OnDataAvailable-s to the listeners and not queue them // in mEventQ. - rv = mChannel->SuspendInternal(); + rv = divertChannel->SuspendInternal(); MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE); mSuspendedForDiversion = NS_SUCCEEDED(rv); } else { @@ -1944,11 +1974,13 @@ HttpChannelParent::ResumeForDiversion() return NS_ERROR_UNEXPECTED; } - mChannel->MessageDiversionStop(); + nsCOMPtr divertChannel = + do_QueryInterface(static_cast(mChannel.get())); + divertChannel->MessageDiversionStop(); if (mSuspendedForDiversion) { // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer. - nsresult rv = mChannel->ResumeInternal(); + nsresult rv = divertChannel->ResumeInternal(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -2104,7 +2136,9 @@ HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode) // Resume only if we suspended earlier. if (mSuspendedForDiversion) { - mChannel->ResumeInternal(); + nsCOMPtr divertChannel = + do_QueryInterface(static_cast(mChannel.get())); + divertChannel->ResumeInternal(); } // Channel has already sent OnStartRequest to the child, so ensure that we // call it here if it hasn't already been called. diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 2d1d15ff110f..3e2a5d842d43 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -260,7 +260,7 @@ private: friend class DivertStopRequestEvent; friend class DivertCompleteEvent; - RefPtr mChannel; + RefPtr mChannel; nsCOMPtr mCacheEntry; nsCOMPtr mAssociatedContentSecurity; bool mIPCClosed; // PHttpChannel actor has been Closed() From df180af556092e11973cade6b322d12cd0011443 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:41 -0700 Subject: [PATCH 43/55] Bug 1391693 P7 Make HttpChannelParent and HttpChannelParentListener allow an internal redirect during service worker interception. r=jdm --- netwerk/protocol/http/HttpChannelParent.cpp | 43 ++++++++++++++- .../http/HttpChannelParentListener.cpp | 55 ++++++++++++++++--- .../protocol/http/HttpChannelParentListener.h | 6 +- 3 files changed, 92 insertions(+), 12 deletions(-) diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index d5c3a7666467..8639435a1b5a 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -113,7 +113,7 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why) // If this is an intercepted channel, we need to make sure that any resources are // cleaned up to avoid leaks. if (mParentListener) { - mParentListener->ClearInterceptedChannel(); + mParentListener->ClearInterceptedChannel(this); } CleanupBackgroundChannel(); @@ -1806,8 +1806,40 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, "newChannel=%p callback=%p]\n", this, registrarId, newChannel, callback)); - if (mIPCClosed) + if (mIPCClosed) { return NS_BINDING_ABORTED; + } + + // If this is an internal redirect for service worker interception, then + // hide it from the child process. The original e10s interception code + // was not designed with this in mind and its not necessary to replace + // the HttpChannelChild/Parent objects in this case. + if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { + nsCOMPtr newIntercepted = do_QueryInterface(newChannel); + if (newIntercepted) { +#ifdef DEBUG + // Note, InterceptedHttpChannel can also do an internal redirect + // for opaque response interception. This should not actually + // happen here in e10s mode. + nsCOMPtr oldIntercepted = + do_QueryInterface(static_cast(mChannel.get())); + MOZ_ASSERT(!oldIntercepted); +#endif + + // Re-link the HttpChannelParent to the new InterceptedHttpChannel. + nsCOMPtr linkedChannel; + rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(linkedChannel)); + NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(linkedChannel == newChannel); + + // We immediately store the InterceptedHttpChannel as our nested + // mChannel. None of the redirect IPC messaging takes place. + mChannel = do_QueryObject(newChannel); + + callback->OnRedirectVerifyCallback(NS_OK); + return NS_OK; + } + } // Sending down the original URI, because that is the URI we have // to construct the channel from - this is the URI we've been actually @@ -1867,6 +1899,13 @@ HttpChannelParent::CompleteRedirect(bool succeeded) LOG(("HttpChannelParent::CompleteRedirect [this=%p succeeded=%d]\n", this, succeeded)); + // If this was an internal redirect for a service worker interception then + // we will not have a redirecting channel here. Hide this redirect from + // the child. + if (!mRedirectChannel) { + return NS_OK; + } + if (succeeded && !mIPCClosed) { // TODO: check return value: assume child dead if failed Unused << SendRedirect3Complete(); diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp index bff502ae9282..69bc6f82942c 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -29,6 +29,7 @@ HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitial , mSuspendedForDiversion(false) , mShouldIntercept(false) , mShouldSuspendIntercept(false) + , mInterceptCanceled(false) { LOG(("HttpChannelParentListener::HttpChannelParentListener [this=%p, next=%p]", this, aInitialChannel)); @@ -247,14 +248,19 @@ HttpChannelParentListener::OnRedirectResult(bool succeeded) } if (succeeded) { - // Switch to redirect channel and delete the old one. - nsCOMPtr parent; - parent = do_QueryInterface(mNextListener); - MOZ_ASSERT(parent); - parent->Delete(); - mNextListener = do_QueryInterface(redirectChannel); - MOZ_ASSERT(mNextListener); - redirectChannel->SetParentListener(this); + // Switch to redirect channel and delete the old one. Only do this + // if we are actually changing channels. During a service worker + // interception internal redirect we preserve the same HttpChannelParent. + if (!SameCOMIdentity(redirectChannel, mNextListener)) { + nsCOMPtr parent; + parent = do_QueryInterface(mNextListener); + MOZ_ASSERT(parent); + parent->Delete(); + mInterceptCanceled = false; + mNextListener = do_QueryInterface(redirectChannel); + MOZ_ASSERT(mNextListener); + redirectChannel->SetParentListener(this); + } } else if (redirectChannel) { // Delete the redirect target channel: continue using old channel redirectChannel->Delete(); @@ -320,6 +326,23 @@ public: NS_IMETHODIMP HttpChannelParentListener::ChannelIntercepted(nsIInterceptedChannel* aChannel) { + // Its possible for the child-side interception to complete and tear down + // the actor before we even get this parent-side interception notification. + // In this case we want to let the interception succeed, but then immediately + // cancel it. If we return an error code from here then it might get + // propagated back to the child process where the interception did not encounter + // an error. Therefore cancel the new channel asynchronously from a runnable. + if (mInterceptCanceled) { + nsCOMPtr r = + NewRunnableMethod("HttpChannelParentListener::CancelInterception", + aChannel, + &nsIInterceptedChannel::CancelInterception, + NS_BINDING_ABORTED); + MOZ_ALWAYS_SUCCEEDS( + SystemGroup::Dispatch(TaskCategory::Other, r.forget())); + return NS_OK; + } + if (mShouldSuspendIntercept) { mInterceptedChannel = aChannel; return NS_OK; @@ -381,6 +404,11 @@ HttpChannelParentListener::DivertTo(nsIStreamListener* aListener) MOZ_ASSERT(aListener); MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); + // Reset mInterceptCanceled back to false every time a new listener is set. + // We only want to cancel the interception if our current listener has + // signaled its cleaning up. + mInterceptCanceled = false; + mNextListener = aListener; return ResumeForDiversion(); @@ -405,12 +433,21 @@ HttpChannelParentListener::SetupInterceptionAfterRedirect(bool aShouldIntercept) } void -HttpChannelParentListener::ClearInterceptedChannel() +HttpChannelParentListener::ClearInterceptedChannel(nsIStreamListener* aListener) { + // Only cancel the interception if this is from our current listener. We + // can get spurious calls here from other HttpChannelParent instances being + // destroyed asynchronously. + if (!SameCOMIdentity(mNextListener, aListener)) { + return; + } if (mInterceptedChannel) { mInterceptedChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); mInterceptedChannel = nullptr; } + // Note that channel interception has been canceled. If we got this before + // the interception even occured we will trigger the cancel later. + mInterceptCanceled = true; } } // namespace net diff --git a/netwerk/protocol/http/HttpChannelParentListener.h b/netwerk/protocol/http/HttpChannelParentListener.h index 227c9e22e923..2be605c1c439 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.h +++ b/netwerk/protocol/http/HttpChannelParentListener.h @@ -52,7 +52,7 @@ public: void SetupInterception(const nsHttpResponseHead& aResponseHead); void SetupInterceptionAfterRedirect(bool aShouldIntercept); - void ClearInterceptedChannel(); + void ClearInterceptedChannel(nsIStreamListener* aListener); private: virtual ~HttpChannelParentListener(); @@ -73,6 +73,10 @@ private: bool mShouldIntercept; // Set if this channel should suspend on interception. bool mShouldSuspendIntercept; + // Set if the channel interception has been canceled. Can be set before + // interception first occurs. In this case cancelation is deferred until + // the interception takes place. + bool mInterceptCanceled; nsAutoPtr mSynthesizedResponseHead; From b27e98a26d6cf6385e37d1ec36e87b69054d501c Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:41 -0700 Subject: [PATCH 44/55] Bug 1391693 P8 Add new InterceptedHttpChannel class to represent parent-side channel with a ServiceWorker FetchEvent. r=asuth r=valentin --- .../protocol/http/InterceptedHttpChannel.cpp | 1038 +++++++++++++++++ .../protocol/http/InterceptedHttpChannel.h | 182 +++ netwerk/protocol/http/moz.build | 1 + 3 files changed, 1221 insertions(+) create mode 100644 netwerk/protocol/http/InterceptedHttpChannel.cpp create mode 100644 netwerk/protocol/http/InterceptedHttpChannel.h diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp new file mode 100644 index 000000000000..7a865f36d6d2 --- /dev/null +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp @@ -0,0 +1,1038 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InterceptedHttpChannel.h" +#include "nsContentSecurityManager.h" +#include "nsEscape.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS_INHERITED(InterceptedHttpChannel, + HttpBaseChannel, + nsIInterceptedChannel, + nsIAsyncVerifyRedirectCallback, + nsIRequestObserver, + nsIStreamListener, + nsIChannelWithDivertableParentListener, + nsIThreadRetargetableRequest, + nsIThreadRetargetableStreamListener) + +InterceptedHttpChannel::InterceptedHttpChannel() + : HttpAsyncAborter(this) + , mProgress(0) + , mProgressReported(0) + , mSynthesizedStreamLength(-1) + , mResumeStartPos(0) + , mSynthesizedOrReset(Invalid) + , mCallingStatusAndProgress(false) +{ + mChannelCreationTime = PR_Now(); + mChannelCreationTimestamp = TimeStamp::Now(); +} + +void +InterceptedHttpChannel::ReleaseListeners() +{ + if (mLoadGroup) { + mLoadGroup->RemoveRequest(this, nullptr, mStatus); + } + HttpBaseChannel::ReleaseListeners(); + mSynthesizedResponseHead.reset(); + mRedirectChannel = nullptr; + mBodyReader = nullptr; + mBodyWriter = nullptr; + mReleaseHandle = nullptr; + mProgressSink = nullptr; + mPump = nullptr; + mParentChannel = nullptr; + + MOZ_DIAGNOSTIC_ASSERT(!mIsPending); +} + +nsresult +InterceptedHttpChannel::SetupReplacementChannel(nsIURI *aURI, + nsIChannel *aChannel, + bool aPreserveMethod, + uint32_t aRedirectFlags) +{ + nsresult rv = HttpBaseChannel::SetupReplacementChannel(aURI, aChannel, + aPreserveMethod, + aRedirectFlags); + if (NS_FAILED(rv)) { + return rv; + } + + // While we can't resume an synthetic response, we can still propagate + // the resume params across redirects for other channels to handle. + if (mResumeStartPos > 0) { + nsCOMPtr resumable = do_QueryInterface(aChannel); + if (!resumable) { + return NS_ERROR_NOT_RESUMABLE; + } + + resumable->ResumeAt(mResumeStartPos, mResumeEntityId); + } + + return NS_OK; +} + +bool +InterceptedHttpChannel::ShouldRedirect() const +{ + // Determine if the synthetic response requires us to perform a real redirect. + return nsHttpChannel::WillRedirect(mResponseHead) && + !mLoadInfo->GetDontFollowRedirects(); +} + +nsresult +InterceptedHttpChannel::FollowSyntheticRedirect() +{ + // Perform a real redirect based on the synthetic response. + + nsCOMPtr ioService; + nsresult rv = gHttpHandler->GetIOService(getter_AddRefs(ioService)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString location; + rv = mResponseHead->GetHeader(nsHttp::Location, location); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + // make sure non-ASCII characters in the location header are escaped. + nsAutoCString locationBuf; + if (NS_EscapeURL(location.get(), -1, esc_OnlyNonASCII, locationBuf)) { + location = locationBuf; + } + + if (NS_WARN_IF(mRedirectionLimit == 0)) { + return NS_ERROR_REDIRECT_LOOP; + } + + nsCOMPtr redirectURI; + rv = ioService->NewURI(nsDependentCString(location.get()), + nullptr, + mURI, + getter_AddRefs(redirectURI)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_CORRUPTED_CONTENT); + + uint32_t redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY; + if (nsHttp::IsPermanentRedirect(mResponseHead->Status())) { + redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT; + } + + bool rewriteToGET = ShouldRewriteRedirectToGET(mResponseHead->Status(), + mRequestHead.ParsedMethod()); + + nsCOMPtr newChannel; + nsCOMPtr redirectLoadInfo = + CloneLoadInfoForRedirect(redirectURI, redirectFlags); + rv = NS_NewChannelInternal(getter_AddRefs(newChannel), + redirectURI, + redirectLoadInfo, + nullptr, // aLoadGroup + nullptr, // aCallbacks + mLoadFlags, + ioService); + NS_ENSURE_SUCCESS(rv, rv); + + rv = SetupReplacementChannel(redirectURI, newChannel, !rewriteToGET, + redirectFlags); + NS_ENSURE_SUCCESS(rv, rv); + + mRedirectChannel = newChannel.forget(); + + rv = gHttpHandler->AsyncOnChannelRedirect(this, mRedirectChannel, redirectFlags); + + if (NS_WARN_IF(NS_FAILED(rv))) { + OnRedirectVerifyCallback(rv); + } + + return rv; +} + +nsresult +InterceptedHttpChannel::RedirectForOpaqueResponse(nsIURI* aResponseURI) +{ + // Perform an internal redirect to another InterceptedHttpChannel using + // the given cross-origin response URL. The resulting channel will then + // process the synthetic response as normal. This extra redirect is + // performed so that listeners treat the result as unsafe cross-origin + // data. + + nsresult rv = NS_OK; + + RefPtr newChannel = + CreateForSynthesis(mResponseHead, mBodyReader); + + rv = newChannel->Init(aResponseURI, mCaps, + static_cast(mProxyInfo.get()), + mProxyResolveFlags, mProxyURI, mChannelId); + + uint32_t flags = nsIChannelEventSink::REDIRECT_INTERNAL; + + nsCOMPtr redirectLoadInfo = + CloneLoadInfoForRedirect(aResponseURI, flags); + newChannel->SetLoadInfo(redirectLoadInfo); + NS_ENSURE_SUCCESS(rv, rv); + + rv = SetupReplacementChannel(aResponseURI, newChannel, true, flags); + NS_ENSURE_SUCCESS(rv, rv); + + mRedirectChannel = newChannel; + + rv = gHttpHandler->AsyncOnChannelRedirect(this, mRedirectChannel, flags); + + if (NS_FAILED(rv)) { + OnRedirectVerifyCallback(rv); + } + + return rv; +} + +nsresult +InterceptedHttpChannel::StartPump() +{ + MOZ_DIAGNOSTIC_ASSERT(!mPump); + MOZ_DIAGNOSTIC_ASSERT(mBodyReader); + + // We don't support resuming an intercepted channel. We can't guarantee the + // ServiceWorker will always return the same data and we can't rely on the + // http cache code to detect changes. For now, just force the channel to + // NS_ERROR_NOT_RESUMABLE which should cause the front-end to recreate the + // channel without calling ResumeAt(). + // + // It would also be possible to convert this information to a range request, + // but its unclear if we should do that for ServiceWorker FetchEvents. See: + // + // https://github.com/w3c/ServiceWorker/issues/1201 + if (mResumeStartPos > 0) { + return NS_ERROR_NOT_RESUMABLE; + } + + // For progress we trust the content-length for the "maximum" size. + // We can't determine the full size from the stream itself since + // we may only receive the data incrementally. We can't trust + // Available() here. + // TODO: We could implement an nsIFixedLengthInputStream interface and + // QI to it here. This would let us determine the total length + // for streams that support it. See bug 1388774. + Unused << GetContentLength(&mSynthesizedStreamLength); + + nsresult rv = nsInputStreamPump::Create(getter_AddRefs(mPump), + mBodyReader, + 0, 0, true); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mPump->AsyncRead(this, mListenerContext); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t suspendCount = mSuspendCount; + while (suspendCount--) { + mPump->Suspend(); + } + + return rv; +} + +nsresult +InterceptedHttpChannel::OpenRedirectChannel() +{ + nsresult rv = NS_OK; + + // Make sure to do this after we received redirect veto answer, + // i.e. after all sinks had been notified + mRedirectChannel->SetOriginalURI(mOriginalURI); + + // open new channel + if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) { + MOZ_ASSERT(!mListenerContext, "mListenerContext should be null!"); + rv = mRedirectChannel->AsyncOpen2(mListener); + } + else { + rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext); + } + NS_ENSURE_SUCCESS(rv, rv); + + mStatus = NS_BINDING_REDIRECTED; + + return rv; +} + +void +InterceptedHttpChannel::MaybeCallStatusAndProgress() +{ + // OnStatus() and OnProgress() must only be called on the main thread. If + // we are on a separate thread, then we maybe need to schedule a runnable + // to call them asynchronousnly. + if (!NS_IsMainThread()) { + // Check to see if we are already trying to call OnStatus/OnProgress + // asynchronously. If we are, then don't queue up another runnable. + // We don't want to flood the main thread. + if (mCallingStatusAndProgress) { + return; + } + mCallingStatusAndProgress = true; + + nsCOMPtr r = + NewRunnableMethod("InterceptedHttpChannel::MaybeCallStatusAndProgress", + this, + &InterceptedHttpChannel::MaybeCallStatusAndProgress); + MOZ_ALWAYS_SUCCEEDS( + SystemGroup::Dispatch(TaskCategory::Other, r.forget())); + + return; + } + + MOZ_ASSERT(NS_IsMainThread()); + + // We are about to capture out progress position. Clear the flag we use + // to de-duplicate progress report runnables. We want any further progress + // updates to trigger another runnable. We do this before capture the + // progress value since we're using atomics and not a mutex lock. + mCallingStatusAndProgress = false; + + // Capture the current status from our atomic count. + int64_t progress = mProgress; + + MOZ_DIAGNOSTIC_ASSERT(progress >= mProgressReported); + + // Do nothing if we've already made the calls for this amount of progress + // or if the channel is not configured for these calls. Note, the check + // for mProgressSink here means we will not fire any spurious late calls + // after ReleaseListeners() is executed. + if (progress <= mProgressReported || + mCanceled || + !mProgressSink || + (mLoadFlags & HttpBaseChannel::LOAD_BACKGROUND)) { + return; + } + + // Capture the host name on the first set of calls to avoid doing this + // string processing repeatedly. + if (mProgressReported == 0) { + nsAutoCString host; + MOZ_ALWAYS_SUCCEEDS(mURI->GetHost(host)); + CopyUTF8toUTF16(host, mStatusHost); + } + + mProgressSink->OnStatus(this, mListenerContext, NS_NET_STATUS_READING, + mStatusHost.get()); + + mProgressSink->OnProgress(this, mListenerContext, progress, + mSynthesizedStreamLength); + + mProgressReported = progress; +} + +// static +already_AddRefed +InterceptedHttpChannel::CreateForInterception() +{ + // Create an InterceptedHttpChannel that will trigger a FetchEvent + // in a ServiceWorker when opened. + RefPtr ref = new InterceptedHttpChannel(); + return ref.forget(); +} + +// static +already_AddRefed +InterceptedHttpChannel::CreateForSynthesis(const nsHttpResponseHead* aHead, + nsIInputStream* aBody) +{ + MOZ_DIAGNOSTIC_ASSERT(aHead); + MOZ_DIAGNOSTIC_ASSERT(aBody); + + // Create an InterceptedHttpChannel that already has a synthesized response. + // The synthetic response will be processed when opened. A FetchEvent + // will not be triggered. + RefPtr ref = new InterceptedHttpChannel(); + ref->mBodyReader = aBody; + ref->mResponseHead = new nsHttpResponseHead(*aHead); + + return ref.forget(); +} + +NS_IMETHODIMP +InterceptedHttpChannel::Cancel(nsresult aStatus) +{ + return CancelInterception(aStatus); +} + +NS_IMETHODIMP +InterceptedHttpChannel::Suspend(void) +{ + nsresult rv = SuspendInternal(); + + nsresult rvParentChannel = NS_OK; + if (mParentChannel) { + rvParentChannel = mParentChannel->SuspendMessageDiversion(); + } + + return NS_FAILED(rv) ? rv : rvParentChannel; +} + +NS_IMETHODIMP +InterceptedHttpChannel::Resume(void) +{ + nsresult rv = ResumeInternal(); + + nsresult rvParentChannel = NS_OK; + if (mParentChannel) { + rvParentChannel = mParentChannel->ResumeMessageDiversion(); + } + + return NS_FAILED(rv) ? rv : rvParentChannel; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetSecurityInfo(nsISupports** aSecurityInfo) +{ + nsCOMPtr ref(mSecurityInfo); + ref.forget(aSecurityInfo); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::AsyncOpen(nsIStreamListener* aListener, nsISupports* aContext) +{ + if (mCanceled) { + return mStatus; + } + + mAsyncOpenTime = TimeStamp::Now(); + mIsPending = true; + mListener = aListener; + + mResponseCouldBeSynthesized = true; + + if (mLoadGroup) { + mLoadGroup->AddRequest(this, nullptr); + } + + // If we already have a synthesized body then we are pre-synthesized. + // This can happen for two reasons: + // 1. We have a pre-synthesized redirect in e10s mode. In this case + // we should follow the redirect. + // 2. We are handling a "fake" redirect for an opaque response. Here + // we should just process the synthetic body. + if (mBodyReader) { + if (ShouldRedirect()) { + return FollowSyntheticRedirect(); + } + + return StartPump(); + } + + // Otherwise we need to trigger a FetchEvent in a ServiceWorker. + nsCOMPtr controller; + GetCallback(controller); + + if (NS_WARN_IF(!controller)) { + Cancel(NS_ERROR_FAILURE); + DoNotifyListener(); + return NS_ERROR_FAILURE; + } + + nsresult rv = controller->ChannelIntercepted(this); + if (NS_WARN_IF(NS_FAILED(rv))) { + Cancel(rv); + DoNotifyListener(); + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::AsyncOpen2(nsIStreamListener* aListener) +{ + nsCOMPtr listener(aListener); + nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener); + if (NS_WARN_IF(NS_FAILED(rv))) { + mStatus = rv; + DoNotifyListener(); + return rv; + } + return AsyncOpen(listener, nullptr); +} + +NS_IMETHODIMP +InterceptedHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage) +{ + // Synthetic responses should not trigger CORS blocking. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetupFallbackChannel(const char* aFallbackKey) +{ + // AppCache should not be used with service worker intercepted channels. + // This should never be called. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +InterceptedHttpChannel::ForceIntercepted(uint64_t aInterceptionID) +{ + // This is a stale API call used in the old nsHttpChannel interception + // code when e10s is enabled. It will be removed in the future. + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetResponseSynthesized(bool* aResponseSynthesized) +{ + *aResponseSynthesized = mResponseHead || mBodyReader; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetPriority(int32_t aPriority) +{ + mPriority = clamped(aPriority, INT16_MIN, INT16_MAX); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetClassFlags(uint32_t aClassFlags) +{ + mClassOfService = aClassFlags; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::ClearClassFlags(uint32_t aClassFlags) +{ + mClassOfService &= ~aClassFlags; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::AddClassFlags(uint32_t aClassFlags) +{ + mClassOfService |= aClassFlags; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::ResumeAt(uint64_t aStartPos, + const nsACString & aEntityId) +{ + // We don't support resuming synthesized responses, but we do track this + // information so it can be passed on to the resulting nsHttpChannel if + // ResetInterception is called. + mResumeStartPos = aStartPos; + mResumeEntityId = aEntityId; + return NS_OK; +} + +void +InterceptedHttpChannel::DoNotifyListenerCleanup() +{ + // Prefer to cleanup in ReleaseListeners() as it seems to be called + // more consistently in necko. +} + + +NS_IMETHODIMP +InterceptedHttpChannel::ResetInterception(void) +{ + if (mCanceled) { + return mStatus; + } + + uint32_t flags = nsIChannelEventSink::REDIRECT_INTERNAL; + + nsCOMPtr newChannel; + nsCOMPtr redirectLoadInfo = + CloneLoadInfoForRedirect(mURI, flags); + nsresult rv = NS_NewChannelInternal(getter_AddRefs(newChannel), + mURI, + redirectLoadInfo, + nullptr, // aLoadGroup + nullptr, // aCallbacks + mLoadFlags); + NS_ENSURE_SUCCESS(rv, rv); + + rv = SetupReplacementChannel(mURI, newChannel, true, flags); + NS_ENSURE_SUCCESS(rv, rv); + + if (mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) { + nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; + rv = newChannel->GetLoadFlags(&loadFlags); + NS_ENSURE_SUCCESS(rv, rv); + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + rv = newChannel->SetLoadFlags(loadFlags); + NS_ENSURE_SUCCESS(rv, rv); + } + + mRedirectChannel = newChannel.forget(); + + rv = gHttpHandler->AsyncOnChannelRedirect(this, mRedirectChannel, flags); + + if (NS_FAILED(rv)) { + OnRedirectVerifyCallback(rv); + } + + return rv; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SynthesizeStatus(uint16_t aStatus, + const nsACString& aReason) +{ + if (mCanceled) { + return mStatus; + } + + if (!mSynthesizedResponseHead) { + mSynthesizedResponseHead.reset(new nsHttpResponseHead()); + } + + nsAutoCString statusLine; + statusLine.AppendLiteral("HTTP/1.1 "); + statusLine.AppendInt(aStatus); + statusLine.AppendLiteral(" "); + statusLine.Append(aReason); + + mSynthesizedResponseHead->ParseStatusLine(statusLine); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SynthesizeHeader(const nsACString& aName, + const nsACString& aValue) +{ + if (mCanceled) { + return mStatus; + } + + if (!mSynthesizedResponseHead) { + mSynthesizedResponseHead.reset(new nsHttpResponseHead()); + } + + nsAutoCString header = aName + NS_LITERAL_CSTRING(": ") + aValue; + // Overwrite any existing header. + nsresult rv = mSynthesizedResponseHead->ParseHeaderLine(header); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::FinishSynthesizedResponse(const nsACString& aFinalURLSpec) +{ + if (mCanceled) { + return mStatus; + } + + if (mBodyWriter) { + mBodyWriter->Close(); + } + + if (!mSynthesizedResponseHead) { + mSynthesizedResponseHead.reset(new nsHttpResponseHead()); + } + + mResponseHead = mSynthesizedResponseHead.release(); + + if (ShouldRedirect()) { + return FollowSyntheticRedirect(); + } + + // Intercepted responses should already be decoded. + SetApplyConversion(false); + + // Errors and redirects may not have a body. Synthesize an empty string stream + // here so later code can be simpler. + if (!mBodyReader) { + nsresult rv = NS_NewCStringInputStream(getter_AddRefs(mBodyReader), + EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr responseURI; + if (!aFinalURLSpec.IsEmpty()) { + nsresult rv = NS_NewURI(getter_AddRefs(responseURI), aFinalURLSpec); + NS_ENSURE_SUCCESS(rv, rv); + } else { + responseURI = mURI; + } + + bool equal = false; + Unused << mURI->Equals(responseURI, &equal); + if (!equal) { + return RedirectForOpaqueResponse(responseURI); + } + + return StartPump(); +} + +NS_IMETHODIMP +InterceptedHttpChannel::CancelInterception(nsresult aStatus) +{ + if (mCanceled) { + return NS_OK; + } + mCanceled = true; + + MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(aStatus)); + if (NS_SUCCEEDED(mStatus)) { + mStatus = aStatus; + } + + if (mPump) { + return mPump->Cancel(mStatus); + } + + return AsyncAbort(mStatus); +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetResponseBody(nsIOutputStream** aResponseBody) +{ + if (!mBodyWriter) { + nsresult rv = NS_NewPipe(getter_AddRefs(mBodyReader), + getter_AddRefs(mBodyWriter), + 0, // default segment size + UINT32_MAX, // infinite pipe length + true, // non-blocking reader + true); // non-blocking writer + NS_ENSURE_SUCCESS(rv, rv); + } + nsCOMPtr ref(mBodyWriter); + ref.forget(aResponseBody); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetChannel(nsIChannel** aChannel) +{ + nsCOMPtr ref(this); + ref.forget(aChannel); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetSecureUpgradedChannelURI(nsIURI** aSecureUpgradedChannelURI) +{ + nsCOMPtr ref(mURI); + ref.forget(aSecureUpgradedChannelURI); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) +{ + return aChannelInfo->ResurrectInfoOnChannel(this); +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetInternalContentPolicyType(nsContentPolicyType* aPolicyType) +{ + if (mLoadInfo) { + *aPolicyType = mLoadInfo->InternalContentPolicyType(); + } + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetConsoleReportCollector(nsIConsoleReportCollector** aConsoleReportCollector) +{ + nsCOMPtr ref(this); + ref.forget(aConsoleReportCollector); + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetLaunchServiceWorkerStart(mozilla::TimeStamp* aTimeStamp) +{ + return HttpBaseChannel::GetLaunchServiceWorkerStart(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetLaunchServiceWorkerStart(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetLaunchServiceWorkerStart(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::GetLaunchServiceWorkerEnd(mozilla::TimeStamp* aTimeStamp) +{ + return HttpBaseChannel::GetLaunchServiceWorkerEnd(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetLaunchServiceWorkerEnd(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetLaunchServiceWorkerEnd(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetDispatchFetchEventStart(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetDispatchFetchEventStart(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetDispatchFetchEventEnd(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetDispatchFetchEventEnd(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetHandleFetchEventStart(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetHandleFetchEventStart(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetHandleFetchEventEnd(mozilla::TimeStamp aTimeStamp) +{ + return HttpBaseChannel::SetHandleFetchEventEnd(aTimeStamp); +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetFinishResponseStart(mozilla::TimeStamp aTimeStamp) +{ + mFinishResponseStart = aTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetFinishSynthesizedResponseEnd(mozilla::TimeStamp aTimeStamp) +{ + MOZ_ASSERT(mSynthesizedOrReset == Invalid); + mSynthesizedOrReset = Synthesized; + mFinishResponseEnd = aTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetChannelResetEnd(mozilla::TimeStamp aTimeStamp) +{ + MOZ_ASSERT(mSynthesizedOrReset == Invalid); + mSynthesizedOrReset = Reset; + mFinishResponseEnd = aTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SaveTimeStamps(void) +{ + nsCString navigationOrSubresource = nsContentUtils::IsNonSubresourceRequest(this) ? + NS_LITERAL_CSTRING("navigation") : NS_LITERAL_CSTRING("subresource"); + + // We may have null timestamps if the fetch dispatch runnable was cancelled + // and we defaulted to resuming the request. + if (!mFinishResponseStart.IsNull() && !mFinishResponseEnd.IsNull()) { + Telemetry::HistogramID id = (mSynthesizedOrReset == Synthesized) ? + Telemetry::SERVICE_WORKER_FETCH_EVENT_FINISH_SYNTHESIZED_RESPONSE_MS : + Telemetry::SERVICE_WORKER_FETCH_EVENT_CHANNEL_RESET_MS; + Telemetry::Accumulate(id, navigationOrSubresource, + static_cast((mFinishResponseEnd - mFinishResponseStart).ToMilliseconds())); + } + + Telemetry::Accumulate(Telemetry::SERVICE_WORKER_FETCH_EVENT_DISPATCH_MS, + navigationOrSubresource, + static_cast((mHandleFetchEventStart - mDispatchFetchEventStart).ToMilliseconds())); + + if (!mFinishResponseEnd.IsNull()) { + Telemetry::Accumulate(Telemetry::SERVICE_WORKER_FETCH_INTERCEPTION_DURATION_MS, + navigationOrSubresource, + static_cast((mFinishResponseEnd - mDispatchFetchEventStart).ToMilliseconds())); + } + + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SetReleaseHandle(nsISupports* aHandle) +{ + mReleaseHandle = aHandle; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::OnRedirectVerifyCallback(nsresult rv) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_SUCCEEDED(rv)) { + rv = OpenRedirectChannel(); + } + + nsCOMPtr hook; + GetCallback(hook); + if (hook) { + hook->OnRedirectResult(NS_SUCCEEDED(rv)); + } + + if (NS_FAILED(rv)) { + Cancel(rv); + } + + mIsPending = false; + ReleaseListeners(); + + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest, + nsISupports* aContext) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mProgressSink) { + GetCallback(mProgressSink); + } + mTransactionTimings.responseStart = TimeStamp::Now(); + if (mListener) { + mListener->OnStartRequest(this, mListenerContext); + } + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::OnStopRequest(nsIRequest* aRequest, + nsISupports* aContext, + nsresult aStatus) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_SUCCEEDED(mStatus)) { + mStatus = aStatus; + } + + // Its possible that we have any async runnable queued to report some + // progress when OnStopRequest() is triggered. Report any left over + // progress immediately. The extra runnable will then do nothing thanks + // to the ReleaseListeners() call below. + MaybeCallStatusAndProgress(); + + mTransactionTimings.responseEnd = TimeStamp::Now(); + + mIsPending = false; + + // Register entry to the Performance resource timing + mozilla::dom::Performance* documentPerformance = GetPerformance(); + if (documentPerformance) { + documentPerformance->AddEntry(this, this); + } + + if (mListener) { + mListener->OnStopRequest(this, mListenerContext, mStatus); + } + + gHttpHandler->OnStopRequest(this); + + ReleaseListeners(); + + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::OnDataAvailable(nsIRequest* aRequest, + nsISupports* aContext, + nsIInputStream* aInputStream, + uint64_t aOffset, + uint32_t aCount) +{ + // Any thread if the channel has been retargeted. + + if (mCanceled || !mListener) { + // If there is no listener, we still need to drain the stream in order + // maintain necko invariants. + uint32_t unused = 0; + aInputStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &unused); + return mStatus; + } + if (mProgressSink) { + if (!(mLoadFlags & HttpBaseChannel::LOAD_BACKGROUND)) { + mProgress = aOffset + aCount; + MaybeCallStatusAndProgress(); + } + } + + return mListener->OnDataAvailable(this, mListenerContext, aInputStream, + aOffset, aCount); +} + +NS_IMETHODIMP +InterceptedHttpChannel::MessageDiversionStarted(ADivertableParentChannel* aParentChannel) +{ + MOZ_ASSERT(!mParentChannel); + mParentChannel = aParentChannel; + uint32_t suspendCount = mSuspendCount; + while(suspendCount--) { + mParentChannel->SuspendMessageDiversion(); + } + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::MessageDiversionStop() +{ + MOZ_ASSERT(mParentChannel); + mParentChannel = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::SuspendInternal() +{ + ++mSuspendCount; + if (mPump) { + return mPump->Suspend(); + } + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::ResumeInternal() +{ + --mSuspendCount; + if (mPump) { + return mPump->Resume(); + } + return NS_OK; +} + +NS_IMETHODIMP +InterceptedHttpChannel::RetargetDeliveryTo(nsIEventTarget* aNewTarget) +{ + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_ARG(aNewTarget); + + // If retargeting to the main thread, do nothing. + if (aNewTarget->IsOnCurrentThread()) { + return NS_OK; + } + + // Retargeting is only valid during OnStartRequest for nsIChannels. So + // we should only be called if we have a pump. + if (!mPump) { + return NS_ERROR_NOT_AVAILABLE; + } + + return mPump->RetargetDeliveryTo(aNewTarget); +} + +NS_IMETHODIMP +InterceptedHttpChannel::CheckListenerChain() +{ + MOZ_ASSERT(NS_IsMainThread()); + nsresult rv = NS_OK; + nsCOMPtr retargetableListener = + do_QueryInterface(mListener, &rv); + if (retargetableListener) { + rv = retargetableListener->CheckListenerChain(); + } + return rv; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h new file mode 100644 index 000000000000..f975ddf7dd13 --- /dev/null +++ b/netwerk/protocol/http/InterceptedHttpChannel.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_net_InterceptedHttpChannel_h +#define mozilla_net_InterceptedHttpChannel_h + +#include "HttpBaseChannel.h" +#include "nsINetworkInterceptController.h" +#include "nsIInputStream.h" +#include "nsIChannelWithDivertableParentListener.h" +#include "nsIThreadRetargetableRequest.h" + +namespace mozilla { +namespace net { + +// This class represents an http channel that is being intercepted by a +// ServiceWorker. This means that when the channel is opened a FetchEvent +// will be fired on the ServiceWorker thread. The channel will complete +// depending on what the worker does. The options are: +// +// 1. If the ServiceWorker does not handle the FetchEvent or does not call +// FetchEvent.respondWith(), then the channel needs to fall back to a +// normal request. When this happens ResetInterception() is called and +// the channel will perform an internal redirect back to an nsHttpChannel. +// +// 2. If the ServiceWorker provides a Response to FetchEvent.respondWith() +// then the status, headers, and body must be synthesized. When +// FinishSynthesizedResponse() is called the synthesized data must be +// reported back to the channel listener. This is handled in a few +// different ways: +// a. If a redirect was synthesized, then we perform the redirect to +// a new nsHttpChannel. This new channel might trigger yet another +// interception. +// b. If a same-origin or CORS Response was synthesized, then we simply +// crate an nsInputStreamPump to process it and call back to the +// listener. +// c. If an opaque Response was synthesized, then we perform an internal +// redirect to a new InterceptedHttpChannel using the cross-origin URL. +// When this new channel is opened, it then creates a pump as in case +// (b). The extra redirect here is to make sure the various listeners +// treat the result as unsafe cross-origin data. +// +// 3. If an error occurs, such as the ServiceWorker passing garbage to +// FetchEvent.respondWith(), then CancelInterception() is called. This is +// handled the same as a normal nsIChannel::Cancel() call. We abort the +// channel and end up calling OnStopRequest() with an error code. +class InterceptedHttpChannel final : public HttpBaseChannel + , public HttpAsyncAborter + , public nsIInterceptedChannel + , public nsIAsyncVerifyRedirectCallback + , public nsIStreamListener + , public nsIChannelWithDivertableParentListener + , public nsIThreadRetargetableRequest + , public nsIThreadRetargetableStreamListener +{ + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIINTERCEPTEDCHANNEL + NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSICHANNELWITHDIVERTABLEPARENTLISTENER + NS_DECL_NSITHREADRETARGETABLEREQUEST + NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER + +private: + friend class HttpAsyncAborter; + + UniquePtr mSynthesizedResponseHead; + nsCOMPtr mRedirectChannel; + nsCOMPtr mBodyReader; + nsCOMPtr mBodyWriter; + nsCOMPtr mReleaseHandle; + nsCOMPtr mProgressSink; + RefPtr mPump; + RefPtr mParentChannel; + TimeStamp mFinishResponseStart; + TimeStamp mFinishResponseEnd; + Atomic mProgress; + int64_t mProgressReported; + int64_t mSynthesizedStreamLength; + uint64_t mResumeStartPos; + nsCString mResumeEntityId; + nsString mStatusHost; + enum { + Invalid = 0, + Synthesized, + Reset + } mSynthesizedOrReset; + Atomic mCallingStatusAndProgress; + + InterceptedHttpChannel(); + ~InterceptedHttpChannel() = default; + + virtual void + ReleaseListeners() override; + + virtual MOZ_MUST_USE nsresult + SetupReplacementChannel(nsIURI *aURI, nsIChannel *aChannel, + bool aPreserveMethod, + uint32_t aRedirectFlags) override; + + bool + ShouldRedirect() const; + + nsresult + FollowSyntheticRedirect(); + + nsresult + RedirectForOpaqueResponse(nsIURI* aResponseURI); + + nsresult + StartPump(); + + nsresult + OpenRedirectChannel(); + + void + MaybeCallStatusAndProgress(); + +public: + static already_AddRefed + CreateForInterception(); + + static already_AddRefed + CreateForSynthesis(const nsHttpResponseHead* aHead, nsIInputStream* aBody); + + NS_IMETHOD + Cancel(nsresult aStatus) override; + + NS_IMETHOD + Suspend(void) override; + + NS_IMETHOD + Resume(void) override; + + NS_IMETHOD + GetSecurityInfo(nsISupports * *aSecurityInfo) override; + + NS_IMETHOD + AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) override; + + NS_IMETHOD + AsyncOpen2(nsIStreamListener *aListener) override; + + NS_IMETHOD + LogBlockedCORSRequest(const nsAString & aMessage) override; + + NS_IMETHOD + SetupFallbackChannel(const char * aFallbackKey) override; + + NS_IMETHOD + ForceIntercepted(uint64_t aInterceptionID) override; + + NS_IMETHOD + GetResponseSynthesized(bool *aResponseSynthesized) override; + + NS_IMETHOD + SetPriority(int32_t aPriority) override; + + NS_IMETHOD + SetClassFlags(uint32_t aClassFlags) override; + + NS_IMETHOD + ClearClassFlags(uint32_t flags) override; + + NS_IMETHOD + AddClassFlags(uint32_t flags) override; + + NS_IMETHOD + ResumeAt(uint64_t startPos, const nsACString & entityID) override; + + void + DoNotifyListenerCleanup() override; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_InterceptedHttpChannel_h diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index c272b645de52..324b7e6fe7d6 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -77,6 +77,7 @@ UNIFIED_SOURCES += [ 'HttpChannelParentListener.cpp', 'HttpInfo.cpp', 'InterceptedChannel.cpp', + 'InterceptedHttpChannel.cpp', 'nsCORSListenerProxy.cpp', 'nsHttp.cpp', 'nsHttpActivityDistributor.cpp', From f3f0b978e07c5bda1fd52a6d2869c85527d8b062 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:41 -0700 Subject: [PATCH 45/55] Bug 1391693 P9 Make nsHttpChannel redirect to InterceptedHttpChannel to fire a ServiceWorker FetchEvent. r=asuth r=valentin --- devtools/shared/webconsole/network-monitor.js | 6 +-- netwerk/protocol/http/nsHttpChannel.cpp | 50 +++++++++++++++++++ netwerk/protocol/http/nsHttpChannel.h | 4 ++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/devtools/shared/webconsole/network-monitor.js b/devtools/shared/webconsole/network-monitor.js index 541e5f8ffb6c..467941592a4a 100644 --- a/devtools/shared/webconsole/network-monitor.js +++ b/devtools/shared/webconsole/network-monitor.js @@ -814,10 +814,8 @@ NetworkMonitor.prototype = { this.interceptedChannels.add(subject); - // On e10s, we never receive http-on-examine-cached-response, so fake one. - if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) { - this._httpResponseExaminer(channel, "http-on-examine-cached-response"); - } + // Service workers never fire http-on-examine-cached-response, so fake one. + this._httpResponseExaminer(channel, "http-on-examine-cached-response"); }, /** diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index e5c915b38271..6e52c9f276e6 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -107,6 +107,7 @@ #include "HSTSPrimerListener.h" #include "CacheStorageService.h" #include "HttpChannelParent.h" +#include "InterceptedHttpChannel.h" #include "nsIBufferedStreams.h" #include "nsIFileStreams.h" #include "nsIMIMEInputStream.h" @@ -545,6 +546,10 @@ nsHttpChannel::Connect() return NS_ERROR_DOCUMENT_NOT_CACHED; } + if (ShouldIntercept()) { + return RedirectToInterceptedChannel(); + } + bool isTrackingResource = mIsTrackingResource; // is atomic LOG(("nsHttpChannel %p tracking resource=%d, local blocklist=%d, cos=%u", this, isTrackingResource, mLocalBlocklist, mClassOfService)); @@ -9577,5 +9582,50 @@ nsHttpChannel::GetWarningReporter() return mWarningReporter.get(); } +nsresult +nsHttpChannel::RedirectToInterceptedChannel() +{ + mInterceptCache = INTERCEPTED; + + nsCOMPtr controller; + GetCallback(controller); + + RefPtr intercepted = + InterceptedHttpChannel::CreateForInterception(); + + nsresult rv = + intercepted->Init(mURI, mCaps, static_cast(mProxyInfo.get()), + mProxyResolveFlags, mProxyURI, mChannelId); + + nsCOMPtr redirectLoadInfo = + CloneLoadInfoForRedirect(mURI, nsIChannelEventSink::REDIRECT_INTERNAL); + intercepted->SetLoadInfo(redirectLoadInfo); + + rv = SetupReplacementChannel(mURI, intercepted, true, + nsIChannelEventSink::REDIRECT_INTERNAL); + NS_ENSURE_SUCCESS(rv, rv); + + mRedirectChannel = intercepted; + + PushRedirectAsyncFunc( + &nsHttpChannel::ContinueAsyncRedirectChannelToURI); + + rv = gHttpHandler->AsyncOnChannelRedirect(this, intercepted, + nsIChannelEventSink::REDIRECT_INTERNAL); + + if (NS_SUCCEEDED(rv)) { + rv = WaitForRedirectCallback(); + } + + if (NS_FAILED(rv)) { + AutoRedirectVetoNotifier notifier(this); + + PopRedirectAsyncFunc( + &nsHttpChannel::ContinueAsyncRedirectChannelToURI); + } + + return rv; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 0d9672140efe..ed81bc0be198 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -499,6 +499,10 @@ private: already_AddRefed GetOrCreateChannelClassifier(); + // Start an internal redirect to a new InterceptedHttpChannel which will + // resolve in firing a ServiceWorker FetchEvent. + MOZ_MUST_USE nsresult RedirectToInterceptedChannel(); + private: // this section is for main-thread-only object // all the references need to be proxy released on main thread. From caf912a42ac6440537d2c48079303a910f175473 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:41 -0700 Subject: [PATCH 46/55] Bug 1391693 P10 Don't expect extraneous console message from service worker any more. r=bgrins --- .../webconsole/test/test_console_serviceworker.html | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/devtools/shared/webconsole/test/test_console_serviceworker.html b/devtools/shared/webconsole/test/test_console_serviceworker.html index 8d9965cf2857..011f7a111e75 100644 --- a/devtools/shared/webconsole/test/test_console_serviceworker.html +++ b/devtools/shared/webconsole/test/test_console_serviceworker.html @@ -97,11 +97,6 @@ let expectedConsoleCalls = [ filename: /helper_serviceworker/, arguments: ['fetch event: ' + SCOPE_FRAME_URL2], }, - { - level: "log", - filename: /helper_serviceworker/, - arguments: ['message event: ' + MESSAGE], - }, ]; let consoleCalls = []; @@ -169,10 +164,9 @@ let onAttach = Task.async(function*(state, response) { // Now postMessage() the service worker to trigger its message event // handler. This will generate 1 or 2 to console.log() statements - // depending on if the worker thread needs to spin up again. Although we - // don't have a controlled or registering document in both cases, we still - // could get console calls since we only flush reports when the channel is - // finally destroyed. + // depending on if the worker thread needs to spin up again. In either + // case, though, we should not get any console calls because we don't + // have a controlled or registering document. info("Completed force refresh. Messaging service worker."); yield messageServiceWorker(currentFrame.contentWindow, SCOPE, MESSAGE); From 4d2d40a639ac841f140421992415728e5a6b2fd2 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:42 -0700 Subject: [PATCH 47/55] Bug 1391693 P11 Remove old nsHttpChannel interception bits. r=valentin --- netwerk/protocol/http/HttpChannelChild.cpp | 6 - netwerk/protocol/http/HttpChannelChild.h | 1 - netwerk/protocol/http/InterceptedChannel.cpp | 209 ----------------- netwerk/protocol/http/InterceptedChannel.h | 31 --- .../protocol/http/InterceptedHttpChannel.cpp | 8 - .../protocol/http/InterceptedHttpChannel.h | 3 - netwerk/protocol/http/nsHttpChannel.cpp | 212 +++++------------- netwerk/protocol/http/nsHttpChannel.h | 16 -- .../protocol/http/nsIHttpChannelInternal.idl | 7 - 9 files changed, 50 insertions(+), 443 deletions(-) diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index c790d5fd2151..95433a28ebe0 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -3570,12 +3570,6 @@ HttpChannelChild::ForceIntercepted(bool aPostRedirectChannelShouldIntercept, return NS_OK; } -NS_IMETHODIMP -HttpChannelChild::ForceIntercepted(uint64_t aInterceptionID) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - void HttpChannelChild::ForceIntercepted(nsIInputStream* aSynthesizedInput) { diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index d21514371ec9..28a4095bfff7 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -98,7 +98,6 @@ public: NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override; // nsIHttpChannelInternal NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override; - NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override; // nsISupportsPriority NS_IMETHOD SetPriority(int32_t value) override; // nsIClassOfService diff --git a/netwerk/protocol/http/InterceptedChannel.cpp b/netwerk/protocol/http/InterceptedChannel.cpp index 4f98e2bb0e48..dd16185d9845 100644 --- a/netwerk/protocol/http/InterceptedChannel.cpp +++ b/netwerk/protocol/http/InterceptedChannel.cpp @@ -213,215 +213,6 @@ InterceptedChannelBase::SecureUpgradeChannelURI(nsIChannel* aChannel) return upgradedURI.forget(); } -InterceptedChannelChrome::InterceptedChannelChrome(nsHttpChannel* aChannel, - nsINetworkInterceptController* aController, - nsICacheEntry* aEntry) -: InterceptedChannelBase(aController) -, mChannel(aChannel) -, mSynthesizedCacheEntry(aEntry) -{ - nsresult rv = mChannel->GetApplyConversion(&mOldApplyConversion); - if (NS_WARN_IF(NS_FAILED(rv))) { - mOldApplyConversion = false; - } -} - -void -InterceptedChannelChrome::NotifyController() -{ - // Intercepted responses should already be decoded. - mChannel->SetApplyConversion(false); - - nsresult rv = mSynthesizedCacheEntry->OpenOutputStream(0, getter_AddRefs(mResponseBody)); - NS_ENSURE_SUCCESS_VOID(rv); - - DoNotifyController(); -} - -NS_IMETHODIMP -InterceptedChannelChrome::GetChannel(nsIChannel** aChannel) -{ - NS_IF_ADDREF(*aChannel = mChannel); - return NS_OK; -} - -NS_IMETHODIMP -InterceptedChannelChrome::ResetInterception() -{ - if (mClosed) { - return NS_ERROR_NOT_AVAILABLE; - } - - mReportCollector->FlushConsoleReports(mChannel); - - mSynthesizedCacheEntry->AsyncDoom(nullptr); - mSynthesizedCacheEntry = nullptr; - - mChannel->SetApplyConversion(mOldApplyConversion); - - nsCOMPtr uri; - mChannel->GetURI(getter_AddRefs(uri)); - - nsresult rv = mChannel->StartRedirectChannelToURI(uri, nsIChannelEventSink::REDIRECT_INTERNAL); - NS_ENSURE_SUCCESS(rv, rv); - - mResponseBody->Close(); - mResponseBody = nullptr; - mClosed = true; - - return NS_OK; -} - -NS_IMETHODIMP -InterceptedChannelChrome::SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) -{ - if (!mSynthesizedCacheEntry) { - return NS_ERROR_NOT_AVAILABLE; - } - - return DoSynthesizeStatus(aStatus, aReason); -} - -NS_IMETHODIMP -InterceptedChannelChrome::SynthesizeHeader(const nsACString& aName, const nsACString& aValue) -{ - if (!mSynthesizedCacheEntry) { - return NS_ERROR_NOT_AVAILABLE; - } - - return DoSynthesizeHeader(aName, aValue); -} - -NS_IMETHODIMP -InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLSpec) -{ - if (mClosed) { - return NS_ERROR_NOT_AVAILABLE; - } - - // Make sure the cache entry's output stream is always closed. If the - // channel was intercepted with a null-body response then its possible - // the synthesis completed without a stream copy operation. - mResponseBody->Close(); - - mReportCollector->FlushConsoleReports(mChannel); - - EnsureSynthesizedResponse(); - - // If the synthesized response is a redirect, then we want to respect - // the encoding of whatever is loaded as a result. - if (nsHttpChannel::WillRedirect(mSynthesizedResponseHead.ref())) { - nsresult rv = mChannel->SetApplyConversion(mOldApplyConversion); - NS_ENSURE_SUCCESS(rv, rv); - } - - mChannel->MarkIntercepted(); - - // First we ensure the appropriate metadata is set on the synthesized cache entry - // (i.e. the flattened response head) - - nsCOMPtr securityInfo; - nsresult rv = mChannel->GetSecurityInfo(getter_AddRefs(securityInfo)); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t expirationTime = 0; - rv = DoUpdateExpirationTime(mChannel, mSynthesizedCacheEntry, - mSynthesizedResponseHead.ref(), - expirationTime); - - rv = DoAddCacheEntryHeaders(mChannel, mSynthesizedCacheEntry, - mChannel->GetRequestHead(), - mSynthesizedResponseHead.ref(), securityInfo); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr originalURI; - mChannel->GetURI(getter_AddRefs(originalURI)); - - nsCOMPtr responseURI; - if (!aFinalURLSpec.IsEmpty()) { - rv = NS_NewURI(getter_AddRefs(responseURI), aFinalURLSpec); - NS_ENSURE_SUCCESS(rv, rv); - } else { - responseURI = originalURI; - } - - bool equal = false; - originalURI->Equals(responseURI, &equal); - if (!equal) { - rv = - mChannel->StartRedirectChannelToURI(responseURI, nsIChannelEventSink::REDIRECT_INTERNAL); - NS_ENSURE_SUCCESS(rv, rv); - } else { - bool usingSSL = false; - responseURI->SchemeIs("https", &usingSSL); - - // Then we open a real cache entry to read the synthesized response from. - rv = mChannel->OpenCacheEntry(usingSSL); - NS_ENSURE_SUCCESS(rv, rv); - - mSynthesizedCacheEntry = nullptr; - - if (!mChannel->AwaitingCacheCallbacks()) { - rv = mChannel->ContinueConnect(); - NS_ENSURE_SUCCESS(rv, rv); - } - } - - mClosed = true; - - return NS_OK; -} - -NS_IMETHODIMP -InterceptedChannelChrome::CancelInterception(nsresult aStatus) -{ - MOZ_ASSERT(NS_FAILED(aStatus)); - - if (mClosed) { - return NS_ERROR_FAILURE; - } - - mReportCollector->FlushConsoleReports(mChannel); - - // we need to use AsyncAbort instead of Cancel since there's no active pump - // to cancel which will provide OnStart/OnStopRequest to the channel. - nsresult rv = mChannel->AsyncAbort(aStatus); - NS_ENSURE_SUCCESS(rv, rv); - - mClosed = true; - - return NS_OK; -} - -NS_IMETHODIMP -InterceptedChannelChrome::SetChannelInfo(dom::ChannelInfo* aChannelInfo) -{ - if (mClosed) { - return NS_ERROR_FAILURE; - } - - return aChannelInfo->ResurrectInfoOnChannel(mChannel); -} - -NS_IMETHODIMP -InterceptedChannelChrome::GetInternalContentPolicyType(nsContentPolicyType* aPolicyType) -{ - NS_ENSURE_ARG(aPolicyType); - nsCOMPtr loadInfo; - nsresult rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo)); - NS_ENSURE_SUCCESS(rv, rv); - if (loadInfo) { - *aPolicyType = loadInfo->InternalContentPolicyType(); - } - return NS_OK; -} - -NS_IMETHODIMP -InterceptedChannelChrome::GetSecureUpgradedChannelURI(nsIURI** aURI) -{ - return mChannel->GetURI(aURI); -} - InterceptedChannelContent::InterceptedChannelContent(HttpChannelChild* aChannel, nsINetworkInterceptController* aController, InterceptStreamListener* aListener, diff --git a/netwerk/protocol/http/InterceptedChannel.h b/netwerk/protocol/http/InterceptedChannel.h index dd5550c70842..b0f914635774 100644 --- a/netwerk/protocol/http/InterceptedChannel.h +++ b/netwerk/protocol/http/InterceptedChannel.h @@ -166,37 +166,6 @@ public: SecureUpgradeChannelURI(nsIChannel* aChannel); }; -class InterceptedChannelChrome : public InterceptedChannelBase -{ - // The actual channel being intercepted. - RefPtr mChannel; - - // Writeable cache entry for use when synthesizing a response in a parent process - nsCOMPtr mSynthesizedCacheEntry; - - // When a channel is intercepted, content decoding is disabled since the - // ServiceWorker will have already extracted the decoded data. For parent - // process channels we need to preserve the earlier value in case - // ResetInterception is called. - bool mOldApplyConversion; -public: - InterceptedChannelChrome(nsHttpChannel* aChannel, - nsINetworkInterceptController* aController, - nsICacheEntry* aEntry); - - NS_IMETHOD ResetInterception() override; - NS_IMETHOD FinishSynthesizedResponse(const nsACString& aFinalURLSpec) override; - NS_IMETHOD GetChannel(nsIChannel** aChannel) override; - NS_IMETHOD GetSecureUpgradedChannelURI(nsIURI** aURI) override; - NS_IMETHOD SynthesizeStatus(uint16_t aStatus, const nsACString& aReason) override; - NS_IMETHOD SynthesizeHeader(const nsACString& aName, const nsACString& aValue) override; - NS_IMETHOD CancelInterception(nsresult aStatus) override; - NS_IMETHOD SetChannelInfo(mozilla::dom::ChannelInfo* aChannelInfo) override; - NS_IMETHOD GetInternalContentPolicyType(nsContentPolicyType *aInternalContentPolicyType) override; - - virtual void NotifyController() override; -}; - class InterceptedChannelContent : public InterceptedChannelBase { // The actual channel being intercepted. diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp index 7a865f36d6d2..4018a0f47624 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp @@ -474,14 +474,6 @@ InterceptedHttpChannel::SetupFallbackChannel(const char* aFallbackKey) return NS_ERROR_NOT_IMPLEMENTED; } -NS_IMETHODIMP -InterceptedHttpChannel::ForceIntercepted(uint64_t aInterceptionID) -{ - // This is a stale API call used in the old nsHttpChannel interception - // code when e10s is enabled. It will be removed in the future. - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP InterceptedHttpChannel::GetResponseSynthesized(bool* aResponseSynthesized) { diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h index f975ddf7dd13..1f4101493e60 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.h +++ b/netwerk/protocol/http/InterceptedHttpChannel.h @@ -151,9 +151,6 @@ public: NS_IMETHOD SetupFallbackChannel(const char * aFallbackKey) override; - NS_IMETHOD - ForceIntercepted(uint64_t aInterceptionID) override; - NS_IMETHOD GetResponseSynthesized(bool *aResponseSynthesized) override; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 6e52c9f276e6..3adb8436d8bc 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -122,9 +122,6 @@ namespace mozilla { namespace net { namespace { -// Monotonically increasing ID for generating unique cache entries per -// intercepted channel. -static uint64_t gNumIntercepted = 0; static bool sRCWNEnabled = false; static uint32_t sRCWNQueueSizeNormal = 50; static uint32_t sRCWNQueueSizePriority = 10; @@ -309,8 +306,6 @@ nsHttpChannel::nsHttpChannel() , mRequestTime(0) , mOfflineCacheLastModifiedTime(0) , mSuspendTotalTime(0) - , mInterceptCache(DO_NOT_INTERCEPT) - , mInterceptionID(gNumIntercepted++) , mCacheOpenWithPriority(false) , mCacheQueueSizeWhenOpen(0) , mCachedContentIsValid(false) @@ -653,8 +648,7 @@ nsHttpChannel::TryHSTSPriming() mLoadInfo->GetForceHSTSPriming(); if (requireHSTSPriming && - nsMixedContentBlocker::sSendHSTSPriming && - mInterceptCache == DO_NOT_INTERCEPT) { + nsMixedContentBlocker::sSendHSTSPriming) { if (!isHttpsScheme) { rv = HSTSPrimingListener::StartHSTSPriming(this, this); @@ -813,8 +807,7 @@ nsHttpChannel::ContinueConnect() // a CORS preflight. Bug: 1272440 // If we need to start a CORS preflight, do it now! // Note that it is important to do this before the early returns below. - if (!mIsCorsPreflightDone && mRequireCORSPreflight && - mInterceptCache != INTERCEPTED) { + if (!mIsCorsPreflightDone && mRequireCORSPreflight) { MOZ_ASSERT(!mPreflightChannel); nsresult rv = nsCORSListenerProxy::StartCORSPreflight(this, this, @@ -823,9 +816,7 @@ nsHttpChannel::ContinueConnect() return rv; } - MOZ_RELEASE_ASSERT(!(mRequireCORSPreflight && - mInterceptCache != INTERCEPTED) || - mIsCorsPreflightDone, + MOZ_RELEASE_ASSERT(!mRequireCORSPreflight || mIsCorsPreflightDone, "CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"); @@ -848,10 +839,7 @@ nsHttpChannel::ContinueConnect() event->Revoke(); } - // Don't accumulate the cache hit telemetry for intercepted channels. - if (mInterceptCache != INTERCEPTED) { - AccumulateCacheHitTelemetry(kCacheHit); - } + AccumulateCacheHitTelemetry(kCacheHit); return rv; } @@ -1578,9 +1566,7 @@ nsHttpChannel::CallOnStartRequest() { LOG(("nsHttpChannel::CallOnStartRequest [this=%p]", this)); - MOZ_RELEASE_ASSERT(!(mRequireCORSPreflight && - mInterceptCache != INTERCEPTED) || - mIsCorsPreflightDone, + MOZ_RELEASE_ASSERT(!mRequireCORSPreflight || mIsCorsPreflightDone, "CORS preflight must have been finished by the time we " "call OnStartRequest"); @@ -2996,16 +2982,6 @@ nsHttpChannel::StartRedirectChannelToURI(nsIURI *upgradedURI, uint32_t flags) // Inform consumers about this fake redirect mRedirectChannel = newChannel; - if (!(flags & nsIChannelEventSink::REDIRECT_STS_UPGRADE) && - mInterceptCache == INTERCEPTED) { - // Mark the channel as intercepted in order to propagate the response URL. - nsCOMPtr httpRedirect = do_QueryInterface(mRedirectChannel); - if (httpRedirect) { - rv = httpRedirect->ForceIntercepted(mInterceptionID); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - } - } - PushRedirectAsyncFunc( &nsHttpChannel::ContinueAsyncRedirectChannelToURI); rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags); @@ -3801,7 +3777,7 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) if (mPostID == 0) mPostID = gHttpHandler->GenerateUniqueID(); } - else if (!PossiblyIntercepted() && !mRequestHead.IsGet() && !mRequestHead.IsHead()) { + else if (!mRequestHead.IsGet() && !mRequestHead.IsHead()) { // don't use the cache for other types of requests return NS_OK; } @@ -3819,7 +3795,7 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) // Pick up an application cache from the notification // callbacks if available and if we are not an intercepted channel. - if (!PossiblyIntercepted() && !mApplicationCache && + if (!mApplicationCache && mInheritApplicationCache) { nsCOMPtr appCacheContainer; GetCallback(appCacheContainer); @@ -3842,15 +3818,7 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) NS_ENSURE_SUCCESS(rv, rv); } else { - // In the case of intercepted channels, we need to construct the cache - // entry key based on the original URI, so that in case the intercepted - // channel is redirected, the cache entry key before and after the - // redirect is the same. - if (PossiblyIntercepted()) { - openURI = mOriginalURI; - } else { - openURI = mURI; - } + openURI = mURI; } RefPtr info = GetLoadContextInfo(this); @@ -3866,12 +3834,12 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) nsAutoCString cacheControlRequestHeader; Unused << mRequestHead.GetHeader(nsHttp::Cache_Control, cacheControlRequestHeader); CacheControlParser cacheControlRequest(cacheControlRequestHeader); - if (cacheControlRequest.NoStore() && !PossiblyIntercepted()) { + if (cacheControlRequest.NoStore()) { goto bypassCacheEntryOpen; } if (offline || (mLoadFlags & INHIBIT_CACHING)) { - if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline && !PossiblyIntercepted()) { + if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline) { goto bypassCacheEntryOpen; } cacheEntryOpenFlags = nsICacheStorage::OPEN_READONLY; @@ -3898,10 +3866,6 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) rv = cacheStorageService->AppCacheStorage(info, mApplicationCache, getter_AddRefs(cacheStorage)); - } else if (PossiblyIntercepted()) { - // The synthesized cache has less restrictions on file size and so on. - rv = cacheStorageService->SynthesizedCacheStorage(info, - getter_AddRefs(cacheStorage)); } else if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) { rv = cacheStorageService->MemoryCacheStorage(info, // ? choose app cache as well... getter_AddRefs(cacheStorage)); @@ -3930,85 +3894,52 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY; - if (PossiblyIntercepted()) { - extension.Append(nsPrintfCString("u%" PRIu64, mInterceptionID)); - } else if (mPostID) { + if (mPostID) { extension.Append(nsPrintfCString("%d", mPostID)); } - // If this channel should be intercepted, we do not open a cache entry for this channel - // until the interception process is complete and the consumer decides what to do with it. - if (mInterceptCache == MAYBE_INTERCEPT) { - DebugOnly exists; - MOZ_ASSERT(NS_FAILED(cacheStorage->Exists(openURI, extension, &exists)) || !exists, - "The entry must not exist in the cache before we create it here"); + mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY; + mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority); - nsCOMPtr entry; - rv = cacheStorage->OpenTruncate(openURI, extension, getter_AddRefs(entry)); - NS_ENSURE_SUCCESS(rv, rv); + if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite) { + bool hasAltData = false; + uint32_t sizeInKb = 0; + rv = cacheStorage->GetCacheIndexEntryAttrs(openURI, extension, + &hasAltData, &sizeInKb); - nsCOMPtr controller; - GetCallback(controller); - - RefPtr intercepted = - new InterceptedChannelChrome(this, controller, entry); - intercepted->NotifyController(); - } else { - if (mInterceptCache == INTERCEPTED) { - cacheEntryOpenFlags |= nsICacheStorage::OPEN_INTERCEPTED; - // Clear OPEN_TRUNCATE for the fake cache entry, since otherwise - // cache storage will close the current entry which breaks the - // response synthesis. - cacheEntryOpenFlags &= ~nsICacheStorage::OPEN_TRUNCATE; - DebugOnly exists; - MOZ_ASSERT(NS_SUCCEEDED(cacheStorage->Exists(openURI, extension, &exists)) && exists, - "The entry must exist in the cache after we create it here"); + // We will attempt to race the network vs the cache if we've found + // this entry in the cache index, and it has appropriate attributes + // (doesn't have alt-data, and has a small size) + if (NS_SUCCEEDED(rv) && !hasAltData && + sizeInKb < sRCWNSmallResourceSizeKB) { + MaybeRaceCacheWithNetwork(); } - - mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY; - mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority); - - if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite && - mInterceptCache != INTERCEPTED) { - bool hasAltData = false; - uint32_t sizeInKb = 0; - rv = cacheStorage->GetCacheIndexEntryAttrs(openURI, extension, - &hasAltData, &sizeInKb); - - // We will attempt to race the network vs the cache if we've found - // this entry in the cache index, and it has appropriate attributes - // (doesn't have alt-data, and has a small size) - if (NS_SUCCEEDED(rv) && !hasAltData && - sizeInKb < sRCWNSmallResourceSizeKB) { - MaybeRaceCacheWithNetwork(); - } - } - - if (!mCacheOpenDelay) { - MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread"); - if (mNetworkTriggered) { - mRaceCacheWithNetwork = sRCWNEnabled; - } - rv = cacheStorage->AsyncOpenURI(openURI, extension, cacheEntryOpenFlags, this); - } else { - // We pass `this` explicitly as a parameter due to the raw pointer - // to refcounted object in lambda analysis. - mCacheOpenFunc = [openURI, extension, cacheEntryOpenFlags, cacheStorage] (nsHttpChannel* self) -> void { - MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread"); - if (self->mNetworkTriggered) { - self->mRaceCacheWithNetwork = true; - } - cacheStorage->AsyncOpenURI(openURI, extension, cacheEntryOpenFlags, self); - }; - - mCacheOpenTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - // calls nsHttpChannel::Notify after `mCacheOpenDelay` milliseconds - mCacheOpenTimer->InitWithCallback(this, mCacheOpenDelay, nsITimer::TYPE_ONE_SHOT); - - } - NS_ENSURE_SUCCESS(rv, rv); } + if (!mCacheOpenDelay) { + MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread"); + if (mNetworkTriggered) { + mRaceCacheWithNetwork = sRCWNEnabled; + } + rv = cacheStorage->AsyncOpenURI(openURI, extension, cacheEntryOpenFlags, this); + } else { + // We pass `this` explicitly as a parameter due to the raw pointer + // to refcounted object in lambda analysis. + mCacheOpenFunc = [openURI, extension, cacheEntryOpenFlags, cacheStorage] (nsHttpChannel* self) -> void { + MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread"); + if (self->mNetworkTriggered) { + self->mRaceCacheWithNetwork = true; + } + cacheStorage->AsyncOpenURI(openURI, extension, cacheEntryOpenFlags, self); + }; + + mCacheOpenTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + // calls nsHttpChannel::Notify after `mCacheOpenDelay` milliseconds + mCacheOpenTimer->InitWithCallback(this, mCacheOpenDelay, nsITimer::TYPE_ONE_SHOT); + + } + NS_ENSURE_SUCCESS(rv, rv); + waitFlags.Keep(WAIT_FOR_CACHE_ENTRY); bypassCacheEntryOpen: @@ -4229,7 +4160,7 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appC // want to proceed since the LOAD_ONLY_IF_MODIFIED flag is // also set. MOZ_ASSERT(mLoadFlags & LOAD_ONLY_IF_MODIFIED); - } else if (mInterceptCache != INTERCEPTED) { + } else { return rv; } } @@ -4330,10 +4261,6 @@ nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appC mRedirectedCachekeys->AppendElement(cacheKey); } - if (doValidation && mInterceptCache == INTERCEPTED) { - doValidation = false; - } - mCachedContentIsValid = !doValidation; if (doValidation) { @@ -5657,17 +5584,6 @@ nsHttpChannel::SetupReplacementChannel(nsIURI *newURI, resumableChannel->ResumeAt(mStartPos, mEntityID); } - if (!(redirectFlags & nsIChannelEventSink::REDIRECT_STS_UPGRADE) && - mInterceptCache != INTERCEPTED && - mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) { - nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; - rv = newChannel->GetLoadFlags(&loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; - rv = newChannel->SetLoadFlags(loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; } @@ -6169,11 +6085,6 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context) return NS_OK; } - if (mInterceptCache != INTERCEPTED && ShouldIntercept()) { - mInterceptCache = MAYBE_INTERCEPT; - SetCouldBeSynthesized(); - } - // Remember the cookie header that was set, if any nsAutoCString cookieHeader; if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookieHeader))) { @@ -6697,21 +6608,6 @@ nsHttpChannel::SetupFallbackChannel(const char *aFallbackKey) return NS_OK; } -NS_IMETHODIMP -nsHttpChannel::ForceIntercepted(uint64_t aInterceptionID) -{ - ENSURE_CALLED_BEFORE_ASYNC_OPEN(); - - if (NS_WARN_IF(mLoadFlags & LOAD_BYPASS_SERVICE_WORKER)) { - return NS_ERROR_NOT_AVAILABLE; - } - - MarkIntercepted(); - mResponseCouldBeSynthesized = true; - mInterceptionID = aInterceptionID; - return NS_OK; -} - NS_IMETHODIMP nsHttpChannel::SetChannelIsForDownload(bool aChannelIsForDownload) { @@ -8685,17 +8581,11 @@ nsHttpChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) return rv; } -void -nsHttpChannel::MarkIntercepted() -{ - mInterceptCache = INTERCEPTED; -} - NS_IMETHODIMP nsHttpChannel::GetResponseSynthesized(bool* aSynthesized) { NS_ENSURE_ARG_POINTER(aSynthesized); - *aSynthesized = (mInterceptCache == INTERCEPTED); + *aSynthesized = false; return NS_OK; } @@ -9585,8 +9475,6 @@ nsHttpChannel::GetWarningReporter() nsresult nsHttpChannel::RedirectToInterceptedChannel() { - mInterceptCache = INTERCEPTED; - nsCOMPtr controller; GetCallback(controller); diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index ed81bc0be198..572067ab5b37 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -165,7 +165,6 @@ public: NS_IMETHOD GetEncodedBodySize(uint64_t *aEncodedBodySize) override; // nsIHttpChannelInternal NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override; - NS_IMETHOD ForceIntercepted(uint64_t aInterceptionID) override; NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload) override; // nsISupportsPriority NS_IMETHOD SetPriority(int32_t value) override; @@ -264,7 +263,6 @@ public: /* internal necko use only */ uint32_t mKeep : 2; }; - void MarkIntercepted(); NS_IMETHOD GetResponseSynthesized(bool* aSynthesized) override; bool AwaitingCacheCallbacks(); void SetCouldBeSynthesized(); @@ -558,20 +556,6 @@ private: // telemetry in nsHttpChannel::OnStartRequest(). uint32_t mSuspendTotalTime; - // States of channel interception - enum { - DO_NOT_INTERCEPT, // no interception will occur - MAYBE_INTERCEPT, // interception in progress, but can be cancelled - INTERCEPTED, // a synthesized response has been provided - } mInterceptCache; - // ID of this channel for the interception purposes. Unique unless this - // channel is replacing an intercepted one via an redirection. - uint64_t mInterceptionID; - - bool PossiblyIntercepted() { - return mInterceptCache != DO_NOT_INTERCEPT; - } - // If the channel is associated with a cache, and the URI matched // a fallback namespace, this will hold the key for the fallback // cache entry. diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index 26e6da9e3842..4a7aa7df2476 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -225,13 +225,6 @@ interface nsIHttpChannelInternal : nsISupports [must_use] readonly attribute PRTime lastModifiedTime; - /** - * Force a channel that has not been AsyncOpen'ed to skip any check for possible - * interception and proceed immediately to open a previously-synthesized cache - * entry using the provided ID. - */ - [must_use] void forceIntercepted(in uint64_t aInterceptionID); - [must_use] readonly attribute boolean responseSynthesized; /** From 6097f72d6aca3aff25de13bb487cb4cb8c1ad5c4 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Mon, 9 Oct 2017 10:03:42 -0700 Subject: [PATCH 48/55] Bug 1391693 P12 Propagate creation and start times to InterceptedHttpChannel from original channel. r=valentin --- .../protocol/http/InterceptedHttpChannel.cpp | 42 +++++++++++++++---- .../protocol/http/InterceptedHttpChannel.h | 12 ++++-- netwerk/protocol/http/nsHttpChannel.cpp | 4 +- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp index 4018a0f47624..3179a3aa936d 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp @@ -21,7 +21,9 @@ NS_IMPL_ISUPPORTS_INHERITED(InterceptedHttpChannel, nsIThreadRetargetableRequest, nsIThreadRetargetableStreamListener) -InterceptedHttpChannel::InterceptedHttpChannel() +InterceptedHttpChannel::InterceptedHttpChannel(PRTime aCreationTime, + const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp) : HttpAsyncAborter(this) , mProgress(0) , mProgressReported(0) @@ -30,8 +32,12 @@ InterceptedHttpChannel::InterceptedHttpChannel() , mSynthesizedOrReset(Invalid) , mCallingStatusAndProgress(false) { - mChannelCreationTime = PR_Now(); - mChannelCreationTimestamp = TimeStamp::Now(); + // Pre-set the creation and AsyncOpen times based on the original channel + // we are intercepting. We don't want our extra internal redirect to mask + // any time spent processing the channel. + mChannelCreationTime = aCreationTime; + mChannelCreationTimestamp = aCreationTimestamp; + mAsyncOpenTime = aAsyncOpenTimestamp; } void @@ -165,7 +171,9 @@ InterceptedHttpChannel::RedirectForOpaqueResponse(nsIURI* aResponseURI) nsresult rv = NS_OK; RefPtr newChannel = - CreateForSynthesis(mResponseHead, mBodyReader); + CreateForSynthesis(mResponseHead, mBodyReader, + mChannelCreationTime, mChannelCreationTimestamp, + mAsyncOpenTime); rv = newChannel->Init(aResponseURI, mCaps, static_cast(mProxyInfo.get()), @@ -329,18 +337,26 @@ InterceptedHttpChannel::MaybeCallStatusAndProgress() // static already_AddRefed -InterceptedHttpChannel::CreateForInterception() +InterceptedHttpChannel::CreateForInterception(PRTime aCreationTime, + const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp) { // Create an InterceptedHttpChannel that will trigger a FetchEvent // in a ServiceWorker when opened. - RefPtr ref = new InterceptedHttpChannel(); + RefPtr ref = + new InterceptedHttpChannel(aCreationTime, aCreationTimestamp, + aAsyncOpenTimestamp); + return ref.forget(); } // static already_AddRefed InterceptedHttpChannel::CreateForSynthesis(const nsHttpResponseHead* aHead, - nsIInputStream* aBody) + nsIInputStream* aBody, + PRTime aCreationTime, + const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp) { MOZ_DIAGNOSTIC_ASSERT(aHead); MOZ_DIAGNOSTIC_ASSERT(aBody); @@ -348,7 +364,10 @@ InterceptedHttpChannel::CreateForSynthesis(const nsHttpResponseHead* aHead, // Create an InterceptedHttpChannel that already has a synthesized response. // The synthetic response will be processed when opened. A FetchEvent // will not be triggered. - RefPtr ref = new InterceptedHttpChannel(); + RefPtr ref = + new InterceptedHttpChannel(aCreationTime, aCreationTimestamp, + aAsyncOpenTimestamp); + ref->mBodyReader = aBody; ref->mResponseHead = new nsHttpResponseHead(*aHead); @@ -402,7 +421,12 @@ InterceptedHttpChannel::AsyncOpen(nsIStreamListener* aListener, nsISupports* aCo return mStatus; } - mAsyncOpenTime = TimeStamp::Now(); + // We should have pre-set the AsyncOpen time based on the original channel if + // timings are enabled. + if (mTimingEnabled) { + MOZ_DIAGNOSTIC_ASSERT(!mAsyncOpenTime.IsNull()); + } + mIsPending = true; mListener = aListener; diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h index 1f4101493e60..944dda8f83fb 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.h +++ b/netwerk/protocol/http/InterceptedHttpChannel.h @@ -91,7 +91,9 @@ private: } mSynthesizedOrReset; Atomic mCallingStatusAndProgress; - InterceptedHttpChannel(); + InterceptedHttpChannel(PRTime aCreationTime, + const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp); ~InterceptedHttpChannel() = default; virtual void @@ -122,10 +124,14 @@ private: public: static already_AddRefed - CreateForInterception(); + CreateForInterception(PRTime aCreationTime, const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp); static already_AddRefed - CreateForSynthesis(const nsHttpResponseHead* aHead, nsIInputStream* aBody); + CreateForSynthesis(const nsHttpResponseHead* aHead, nsIInputStream* aBody, + PRTime aCreationTime, + const TimeStamp& aCreationTimestamp, + const TimeStamp& aAsyncOpenTimestamp); NS_IMETHOD Cancel(nsresult aStatus) override; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 3adb8436d8bc..fd34bca095d0 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -9479,7 +9479,9 @@ nsHttpChannel::RedirectToInterceptedChannel() GetCallback(controller); RefPtr intercepted = - InterceptedHttpChannel::CreateForInterception(); + InterceptedHttpChannel::CreateForInterception(mChannelCreationTime, + mChannelCreationTimestamp, + mAsyncOpenTime); nsresult rv = intercepted->Init(mURI, mCaps, static_cast(mProxyInfo.get()), From 30d9a9082f56f253ef0609436cfd56ae77b923a4 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Mon, 9 Oct 2017 18:29:37 +0200 Subject: [PATCH 49/55] Bug 1402555 - followup to close the urlbar popup, since some tests are unhappy with the status quo. r=post-facto MozReview-Commit-ID: It8GhKfWj3n --HG-- extra : rebase_source : 5c1218eac9eaa04aa75b7640513867c938ca0d2b --- .../base/content/test/urlbar/browser_urlbar_remove_match.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/browser/base/content/test/urlbar/browser_urlbar_remove_match.js b/browser/base/content/test/urlbar/browser_urlbar_remove_match.js index ad75022075bf..e7a89e09feb1 100644 --- a/browser/base/content/test/urlbar/browser_urlbar_remove_match.js +++ b/browser/base/content/test/urlbar/browser_urlbar_remove_match.js @@ -25,4 +25,7 @@ add_task(async function test_remove_history() { await BrowserTestUtils.waitForCondition( () => !gURLBar.popup.richlistbox.children.some(c => !c.collapsed && c.getAttribute("ac-value") == TEST_URL), "Waiting for the result to disappear"); + + gURLBar.popup.hidePopup(); + await promisePopupHidden(gURLBar.popup); }); From 8cd834cd623133767979f3ff1b9c25c3af52d93f Mon Sep 17 00:00:00 2001 From: James Cheng Date: Mon, 9 Oct 2017 13:40:12 -0400 Subject: [PATCH 50/55] Bug 1365894 - Make SystemGroupImpl be a normal ref-counted object. r=ehsan MozReview-Commit-ID: LUcoBhNx2M5 --HG-- extra : rebase_source : 10010b8cc206c16980c9e1601445f262104f1dd2 --- xpcom/threads/SystemGroup.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/xpcom/threads/SystemGroup.cpp b/xpcom/threads/SystemGroup.cpp index fb649f6f00ae..4b3c67e5d4d8 100644 --- a/xpcom/threads/SystemGroup.cpp +++ b/xpcom/threads/SystemGroup.cpp @@ -17,7 +17,7 @@ class SystemGroupImpl final : public SchedulerGroup { public: SystemGroupImpl(); - ~SystemGroupImpl() {} + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SystemGroupImpl) static void InitStatic(); static void ShutdownStatic(); @@ -25,20 +25,12 @@ public: static bool Initialized() { return !!sSingleton; } - NS_METHOD_(MozExternalRefCountType) AddRef(void) - { - return 2; - } - NS_METHOD_(MozExternalRefCountType) Release(void) - { - return 1; - } - private: - static UniquePtr sSingleton; + ~SystemGroupImpl() = default; + static StaticRefPtr sSingleton; }; -UniquePtr SystemGroupImpl::sSingleton; +StaticRefPtr SystemGroupImpl::sSingleton; SystemGroupImpl::SystemGroupImpl() { @@ -50,7 +42,7 @@ SystemGroupImpl::InitStatic() { MOZ_ASSERT(!sSingleton); MOZ_ASSERT(NS_IsMainThread()); - sSingleton = MakeUnique(); + sSingleton = new SystemGroupImpl(); } /* static */ void From d49d38778b642708578797f52e677b0d26827e2a Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 9 Oct 2017 13:50:02 -0400 Subject: [PATCH 51/55] Bug 1371891 - Use CheckedInt to compute guess for the location of -> in FTP parser. r=michal --- netwerk/streamconv/converters/ParseFTPList.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/netwerk/streamconv/converters/ParseFTPList.cpp b/netwerk/streamconv/converters/ParseFTPList.cpp index b8826049cad8..07de5f5ba15d 100644 --- a/netwerk/streamconv/converters/ParseFTPList.cpp +++ b/netwerk/streamconv/converters/ParseFTPList.cpp @@ -10,11 +10,14 @@ #include "plstr.h" #include "nsDebug.h" #include "prprf.h" +#include "mozilla/CheckedInt.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Sprintf.h" /* ==================================================================== */ +using mozilla::CheckedInt; + static inline int ParsingFailed(struct list_state *state) { if (state->parsed_one || state->lstyle) /* junk if we fail to parse */ @@ -1192,14 +1195,17 @@ int ParseFTPList(const char *line, struct list_state *state, { /* First try to use result->fe_size to find " -> " sequence. This can give proper result for cases like "aaa -> bbb -> ccc". */ - uint32_t fe_size = atoi(result->fe_size); + uintptr_t fe_size = atoi(result->fe_size); + CheckedInt arrow_start(result->fe_fnlen); + arrow_start -= fe_size; + arrow_start -= 4; - if (result->fe_fnlen > (fe_size + 4) && - PL_strncmp(result->fe_fname + result->fe_fnlen - fe_size - 4 , " -> ", 4) == 0) + if (arrow_start.isValid() && + PL_strncmp(result->fe_fname + arrow_start.value(), " -> ", 4) == 0) { result->fe_lname = result->fe_fname + (result->fe_fnlen - fe_size); result->fe_lnlen = (&(line[linelen])) - (result->fe_lname); - result->fe_fnlen -= fe_size + 4; + result->fe_fnlen = arrow_start.value(); } else { From c93aae82acca31cd3dfb5d795796ccf0b421a61d Mon Sep 17 00:00:00 2001 From: Stone Shih Date: Tue, 19 Sep 2017 15:41:52 +0800 Subject: [PATCH 52/55] Bug 1375146 - Revise sending drag event. r=smaug --- dom/events/EventStateManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 1b72b51a7964..b341bbfc6dad 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -1295,8 +1295,9 @@ EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent, return; } case eDragEventClass: { - if (remote->Manager()->IsContentParent()) { - remote->Manager()->AsContentParent()->MaybeInvokeDragSession(remote); + RefPtr tabParent = remote; + if (tabParent->Manager()->IsContentParent()) { + tabParent->Manager()->AsContentParent()->MaybeInvokeDragSession(tabParent); } nsCOMPtr dragSession = nsContentUtils::GetDragSession(); @@ -1312,7 +1313,7 @@ EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent, } } - remote->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect); + tabParent->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect); return; } case ePluginEventClass: { From 373aeee3ba419cad1bc938db57017916d1adb0b5 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 17 Sep 2017 19:52:04 +0900 Subject: [PATCH 53/55] Bug 1394530 - Stop using optimized path for non PromiseObject. r=till --- js/src/builtin/Promise.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index b1dbf047fb22..0f314720624b 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -2406,6 +2406,15 @@ NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfi HandleValue onRejected, HandleObject resolve, HandleObject reject, HandleObject incumbentGlobalObject) { + // Either of the following conditions must be met: + // * resultPromise is a PromiseObject + // * resolve and reject are callable + // except for Async Generator, there resultPromise can be nullptr. + MOZ_ASSERT_IF(resultPromise && !resultPromise->is(), resolve); + MOZ_ASSERT_IF(resultPromise && !resultPromise->is(), IsCallable(resolve)); + MOZ_ASSERT_IF(resultPromise && !resultPromise->is(), reject); + MOZ_ASSERT_IF(resultPromise && !resultPromise->is(), IsCallable(reject)); + Rooted reaction(cx, NewObjectWithClassProto(cx)); if (!reaction) return nullptr; @@ -3113,7 +3122,7 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis // rejected promises list. bool addToDependent = true; - if (C == PromiseCtor) { + if (C == PromiseCtor && resultPromise->is()) { addToDependent = false; } else { // 25.4.5.3., step 4. @@ -3172,12 +3181,14 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis return false; } - // If the object to depend on isn't a, maybe-wrapped, Promise instance, - // we ignore it. All this does is lose some small amount of debug - // information in scenarios that are highly unlikely to occur in useful - // code. + // If either the object to depend on or the object that gets blocked isn't + // a, maybe-wrapped, Promise instance, we ignore it. All this does is lose + // some small amount of debug information in scenarios that are highly + // unlikely to occur in useful code. if (!unwrappedPromiseObj->is()) return true; + if (!blockedPromise_->is()) + return true; Rooted promise(cx, &unwrappedPromiseObj->as()); return AddPromiseReaction(cx, promise, UndefinedHandleValue, UndefinedHandleValue, From da2ce929eaafa0b7e7f3b643e70b30c81ee502e2 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Mon, 9 Oct 2017 14:28:39 -0400 Subject: [PATCH 54/55] Bug 1394265 - Set MAX_COMBINED_TEXTURE_IMAGE_UNITS to 0 if GetIntegeriv fails. r=daoshengmu MozReview-Commit-ID: 6VDKmtVPrVO --- dom/canvas/WebGLContextValidate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/canvas/WebGLContextValidate.cpp b/dom/canvas/WebGLContextValidate.cpp index 54eee217dfd9..9013c3d4a05b 100644 --- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -513,10 +513,10 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware, // even though the hardware supports much more. The // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value. - gl->GetUIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits); - mGLMaxCombinedTextureImageUnits = mGLMaxTextureUnits; + mGLMaxCombinedTextureImageUnits = gl->GetIntAs(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); + mGLMaxTextureUnits = mGLMaxCombinedTextureImageUnits; - if (mGLMaxTextureUnits < 8) { + if (mGLMaxCombinedTextureImageUnits < 8) { const nsPrintfCString reason("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!", mGLMaxTextureUnits); *out_failReason = { "FEATURE_FAILURE_WEBGL_T_UNIT", reason }; From 591c9f864b251ebaab06d33e878397ef5549d155 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 9 Oct 2017 14:49:19 -0400 Subject: [PATCH 55/55] Bug 1405878. Make sure to notify for our kids, if needed, before calling DoneAddingChildren in the XML content sink. r=hsivonen Once we call DoneAddingChildren, random code of various sorts will run, which can flush our notification state. If that happens before we've notified on our kids, but after we've popped the element we're closing off the element stack, we will fail to ever notify on the kids. MozReview-Commit-ID: Ei7v5OobX8R --- dom/xml/crashtests/1405878.xml | 11 +++++++++++ dom/xml/crashtests/crashtests.list | 1 + dom/xml/nsXMLContentSink.cpp | 18 +++++++++++------- layout/reftests/bugs/1405878-1-ref.xml | 7 +++++++ layout/reftests/bugs/1405878-1.xml | 6 ++++++ layout/reftests/bugs/reftest.list | 1 + 6 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 dom/xml/crashtests/1405878.xml create mode 100644 layout/reftests/bugs/1405878-1-ref.xml create mode 100644 layout/reftests/bugs/1405878-1.xml diff --git a/dom/xml/crashtests/1405878.xml b/dom/xml/crashtests/1405878.xml new file mode 100644 index 000000000000..12677ade938d --- /dev/null +++ b/dom/xml/crashtests/1405878.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/dom/xml/crashtests/crashtests.list b/dom/xml/crashtests/crashtests.list index f18767d582c2..2c06ffc545ec 100644 --- a/dom/xml/crashtests/crashtests.list +++ b/dom/xml/crashtests/crashtests.list @@ -10,3 +10,4 @@ load 453278.html load 803586.xhtml load 994740-1.xhtml load 1038887.xhtml +load 1405878.xml diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index c922d1bab380..0049ec9a0791 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -1070,6 +1070,17 @@ nsXMLContentSink::HandleEndElement(const char16_t *aName, isTemplateElement, "Wrong element being closed"); #endif + // Make sure to notify on our kids before we call out to any other code that + // might reenter us and call FlushTags, in a state in which we've already + // popped "content" from the stack but haven't notified on its kids yet. + int32_t stackLen = mContentStack.Length(); + if (mNotifyLevel >= stackLen) { + if (numFlushed < content->GetChildCount()) { + NotifyAppend(content, numFlushed); + } + mNotifyLevel = stackLen - 1; + } + result = CloseElement(content); if (mCurrentHead == content) { @@ -1085,13 +1096,6 @@ nsXMLContentSink::HandleEndElement(const char16_t *aName, MaybeStartLayout(false); } - int32_t stackLen = mContentStack.Length(); - if (mNotifyLevel >= stackLen) { - if (numFlushed < content->GetChildCount()) { - NotifyAppend(content, numFlushed); - } - mNotifyLevel = stackLen - 1; - } DidAddContent(); if (content->IsSVGElement(nsGkAtoms::svg)) { diff --git a/layout/reftests/bugs/1405878-1-ref.xml b/layout/reftests/bugs/1405878-1-ref.xml new file mode 100644 index 000000000000..6d1dd199b41e --- /dev/null +++ b/layout/reftests/bugs/1405878-1-ref.xml @@ -0,0 +1,7 @@ + + + diff --git a/layout/reftests/bugs/1405878-1.xml b/layout/reftests/bugs/1405878-1.xml new file mode 100644 index 000000000000..3915711b1103 --- /dev/null +++ b/layout/reftests/bugs/1405878-1.xml @@ -0,0 +1,6 @@ + + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 379998b76494..1483ee8b2c9a 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -2042,5 +2042,6 @@ needs-focus != 1377447-1.html 1377447-2.html == 1398500-1.html 1398500-1-ref.html == 1401317.html 1401317-ref.html == 1401992.html 1401992-ref.html +== 1405878-1.xml 1405878-1-ref.xml == 1404057.html 1404057-ref.html != 1404057.html 1404057-noref.html