diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp index 04a53426e..f1a40e10f 100644 --- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp +++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp @@ -617,7 +617,7 @@ NativeRegExpMacroAssembler::Backtrack() // Check for an interrupt. Label noInterrupt; masm.branch32(Assembler::Equal, - AbsoluteAddress(runtime->addressOfInterruptUint32()), Imm32(0), + AbsoluteAddress(runtime->addressOfInterruptRegExpJitUint32()), Imm32(0), &noInterrupt); masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0); masm.jump(&exit_label_); @@ -627,7 +627,7 @@ NativeRegExpMacroAssembler::Backtrack() PopBacktrack(temp0); masm.jump(temp0); #else - masm.x_li32(addressTempRegister, (uint32_t)runtime->addressOfInterruptUint32()); + masm.x_li32(addressTempRegister, (uint32_t)runtime->addressOfInterruptRegExpJitUint32()); masm.lwz(tempRegister, addressTempRegister, 0); PPC_BC(noIRQ, tempRegister, Imm32(0), Equal); masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0); diff --git a/js/src/jit-test/tests/basic/indexof-equal.js b/js/src/jit-test/tests/basic/indexof-equal.js new file mode 100644 index 000000000..f6e325604 --- /dev/null +++ b/js/src/jit-test/tests/basic/indexof-equal.js @@ -0,0 +1,10 @@ +var x = "abc"; +assertEq(x.indexOf(x), 0); +assertEq(x.indexOf(x, -1), 0); +assertEq(x.indexOf(x, 1), -1); +assertEq(x.indexOf(x, 100), -1); + +assertEq(x.lastIndexOf(x), 0); +assertEq(x.lastIndexOf(x, -1), 0); +assertEq(x.lastIndexOf(x, 1), 0); +assertEq(x.lastIndexOf(x, 100), 0); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index e2336fd1f..0133cae7b 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -2330,13 +2330,16 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo) } if (getInlineReturnType() != MIRType_Undefined) return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType_Object) + + MDefinition* obj = callInfo.getArg(0); + if (obj->type() != MIRType_Object && obj->type() != MIRType_Value) return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType_Int32) + + MDefinition* arg = callInfo.getArg(1); + if (arg->type() != MIRType_Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. - MDefinition* arg = callInfo.getArg(1); if (!arg->isConstantValue()) return InliningStatus_NotInlined; uint32_t slot = arg->constantValue().toPrivateUint32(); @@ -2344,12 +2347,12 @@ IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo) callInfo.setImplicitlyUsedUnchecked(); MStoreFixedSlot* store = - MStoreFixedSlot::NewBarriered(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2)); + MStoreFixedSlot::NewBarriered(alloc(), obj, slot, callInfo.getArg(2)); current->add(store); current->push(store); if (NeedsPostBarrier(callInfo.getArg(2))) - current->add(MPostWriteBarrier::New(alloc(), callInfo.getArg(0), callInfo.getArg(2))); + current->add(MPostWriteBarrier::New(alloc(), obj, callInfo.getArg(2))); return InliningStatus_Inlined; } @@ -2361,20 +2364,23 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueTy trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; } - if (callInfo.getArg(0)->type() != MIRType_Object) + + MDefinition* obj = callInfo.getArg(0); + if (obj->type() != MIRType_Object && obj->type() != MIRType_Value) return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType_Int32) + + MDefinition* arg = callInfo.getArg(1); + if (arg->type() != MIRType_Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. - MDefinition* arg = callInfo.getArg(1); if (!arg->isConstantValue()) return InliningStatus_NotInlined; uint32_t slot = arg->constantValue().toPrivateUint32(); callInfo.setImplicitlyUsedUnchecked(); - MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot); + MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot); current->add(load); current->push(load); if (knownValueType != MIRType_Value) { diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 902f10847..1df251898 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1596,6 +1596,13 @@ js::str_indexOf(JSContext* cx, unsigned argc, Value* vp) // Step 9 uint32_t start = Min(Max(pos, 0U), textLen); + if (str == searchStr) { + // AngularJS often invokes "false".indexOf("false"). This check should + // be cheap enough to not hurt anything else. + args.rval().setInt32(start == 0 ? 0 : -1); + return true; + } + // Steps 10 and 11 JSLinearString* text = str->ensureLinear(cx); if (!text) @@ -1646,6 +1653,11 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp) if (!pat) return false; + if (textstr == pat) { + args.rval().setInt32(0); + return true; + } + size_t textLen = textstr->length(); size_t patLen = pat->length(); int start = textLen - patLen; // Start searching here diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index a3a3fda41..79f27f643 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -144,6 +144,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) entryMonitor(nullptr), parentRuntime(parentRuntime), interrupt_(false), + interruptRegExpJit_(false), telemetryCallback(nullptr), handlingSignal(false), interruptCallback(nullptr), @@ -641,11 +642,11 @@ JSRuntime::requestInterrupt(InterruptMode mode) jitStackLimit_ = UINTPTR_MAX; if (mode == JSRuntime::RequestInterruptUrgent) { - // If this interrupt is urgent (slow script dialog and garbage - // collection among others), take additional steps to - // interrupt corner cases where the above fields are not - // regularly polled. Wake both ilooping JIT code and - // futexWait. + // If this interrupt is urgent (slow script dialog for instance), take + // additional steps to interrupt corner cases where the above fields are + // not regularly polled. Wake ilooping Ion code, irregexp JIT code and + // Atomics.wait() + interruptRegExpJit_ = true; fx.lock(); if (fx.isWaiting()) fx.wake(FutexRuntime::WakeForJSInterrupt); @@ -660,6 +661,7 @@ JSRuntime::handleInterrupt(JSContext* cx) MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); if (interrupt_ || jitStackLimit_ == UINTPTR_MAX) { interrupt_ = false; + interruptRegExpJit_ = false; resetJitStackLimit(); return InvokeInterruptCallback(cx); } diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 9df53087c..d91e9ceb0 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -794,6 +794,7 @@ struct JSRuntime : public JS::shadow::Runtime, private: mozilla::Atomic interrupt_; + mozilla::Atomic interruptRegExpJit_; /* Call this to accumulate telemetry data. */ JSAccumulateTelemetryDataCallback telemetryCallback; @@ -841,6 +842,10 @@ struct JSRuntime : public JS::shadow::Runtime, static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers"); return &interrupt_; } + void* addressOfInterruptRegExpJitUint32() { // see bug 1386199 + static_assert(sizeof(interruptRegExpJit_) == sizeof(uint32_t), "Assumed by JIT callers"); + return &interruptRegExpJit_; + } /* Set when handling a signal for a thread associated with this runtime. */ bool handlingSignal;