--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1018,8 +1018,89 @@ js::regexp_test_no_statics(JSContext* cx
RootedString string(cx, args[1].toString());
size_t ignored = 0;
RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, 0, false,
nullptr, &ignored, DontUpdateRegExpStatics);
args.rval().setBoolean(status == RegExpRunStatus_Success);
return status != RegExpRunStatus_Error;
}
+
+bool
+js::RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp)
+{
+ // This can only be called from self-hosted code.
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+
+ uint8_t result = false;
+ if (!RegExpPrototypeOptimizableRaw(cx, &args[0].toObject(), &result))
+ return false;
+
+ args.rval().setBoolean(result);
+ return true;
+}
+
+bool
+js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* result)
+{
+ JS::AutoCheckCannotGC nogc;
+ if (!proto->isNative()) {
+ *result = false;
+ return true;
+ }
+
+ NativeObject* nproto = static_cast<NativeObject*>(proto);
+
+ Shape* shape = cx->compartment()->regExps.getOptimizableRegExpPrototypeShape();
+ if (shape == nproto->lastProperty()) {
+ *result = true;
+ return true;
+ }
+
+ JSNative globalGetter;
+ if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().global), &globalGetter))
+ return false;
+
+ if (globalGetter != regexp_global) {
+ *result = false;
+ return true;
+ }
+
+ JSNative stickyGetter;
+ if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().sticky), &stickyGetter))
+ return false;
+
+ if (stickyGetter != regexp_sticky) {
+ *result = false;
+ return true;
+ }
+
+ // Check if @@match, @@search, and exec are own data properties,
+ // those values should be tested in selfhosted JS.
+ bool has = false;
+ if (!HasOwnDataPropertyPure(cx, proto, SYMBOL_TO_JSID(cx->wellKnownSymbols().match), &has))
+ return false;
+ if (!has) {
+ *result = false;
+ return true;
+ }
+
+ /*
+ if (!HasOwnDataPropertyPure(cx, proto, SYMBOL_TO_JSID(cx->wellKnownSymbols().search), &has))
+ return false;
+ if (!has) {
+ *result = false;
+ return true;
+ }
+ */
+
+ if (!HasOwnDataPropertyPure(cx, proto, NameToId(cx->names().exec), &has))
+ return false;
+ if (!has) {
+ *result = false;
+ return true;
+ }
+
+ cx->compartment()->regExps.setOptimizableRegExpPrototypeShape(nproto->lastProperty());
+ *result = true;
+ return true;
+}
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -86,16 +86,22 @@ extern bool
regexp_construct_self_hosting(JSContext* cx, unsigned argc, Value* vp);
extern bool
IsRegExp(JSContext* cx, HandleValue value, bool* result);
extern bool
RegExpCreate(JSContext* cx, HandleValue pattern, HandleValue flags, MutableHandleValue rval);
+extern bool
+RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp);
+
+extern bool
+RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* result);
+
// RegExp ClassSpec members used in RegExpObject.cpp.
extern bool
regexp_construct(JSContext* cx, unsigned argc, Value* vp);
extern const JSPropertySpec regexp_static_props[];
extern const JSPropertySpec regexp_properties[];
extern const JSFunctionSpec regexp_methods[];
// Used in RegExpObject::isOriginalFlagGetter.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -14,16 +14,17 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/SizePrintfMacros.h"
#include "jslibmath.h"
#include "jsmath.h"
#include "jsnum.h"
#include "jsprf.h"
+#include "jsstr.h"
#include "builtin/Eval.h"
#include "builtin/TypedObject.h"
#include "gc/Nursery.h"
#include "irregexp/NativeRegExpMacroAssembler.h"
#include "jit/AtomicOperations.h"
#include "jit/BaselineCompiler.h"
#include "jit/IonBuilder.h"
@@ -33,16 +34,17 @@
#include "jit/JitSpewer.h"
#include "jit/Linker.h"
#include "jit/Lowering.h"
#include "jit/MIRGenerator.h"
#include "jit/MoveEmitter.h"
#include "jit/RangeAnalysis.h"
#include "jit/SharedICHelpers.h"
#include "vm/MatchPairs.h"
+#include "vm/RegExpObject.h"
#include "vm/RegExpStatics.h"
#include "vm/TraceLogging.h"
#include "vm/Unicode.h"
#include "jsboolinlines.h"
#include "jit/MacroAssembler-inl.h"
#include "jit/shared/CodeGenerator-shared-inl.h"
@@ -1959,16 +1961,85 @@ CodeGenerator::visitRegExpTester(LRegExp
JitCode* regExpTesterStub = gen->compartment->jitCompartment()->regExpTesterStubNoBarrier();
masm.call(regExpTesterStub);
masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpTesterResultFailed), ool->entry());
masm.bind(ool->rejoin());
}
+class OutOfLineRegExpPrototypeOptimizable : public OutOfLineCodeBase<CodeGenerator>
+{
+ LRegExpPrototypeOptimizable* ins_;
+
+ public:
+ explicit OutOfLineRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
+ : ins_(ins)
+ { }
+
+ void accept(CodeGenerator* codegen) {
+ codegen->visitOutOfLineRegExpPrototypeOptimizable(this);
+ }
+ LRegExpPrototypeOptimizable* ins() const {
+ return ins_;
+ }
+};
+
+void
+CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
+{
+ Register object = ToRegister(ins->object());
+ Register output = ToRegister(ins->output());
+ Register temp = ToRegister(ins->temp());
+
+ OutOfLineRegExpPrototypeOptimizable* ool = new(alloc()) OutOfLineRegExpPrototypeOptimizable(ins);
+ addOutOfLineCode(ool, ins->mir());
+
+ masm.loadJSContext(temp);
+ masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
+ masm.loadPtr(Address(temp, JSCompartment::offsetOfRegExps()), temp);
+ masm.loadPtr(Address(temp, RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape()),
+ temp);
+
+ masm.loadPtr(Address(object, JSObject::offsetOfShape()), output);
+ masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
+ masm.move32(Imm32(0x1), output);
+
+ masm.bind(ool->rejoin());
+}
+
+void
+CodeGenerator::visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool)
+{
+ LRegExpPrototypeOptimizable* ins = ool->ins();
+ Register object = ToRegister(ins->object());
+ Register output = ToRegister(ins->output());
+ Register temp = ToRegister(ins->temp());
+
+ saveVolatile(output);
+
+ masm.reserveStack(sizeof(void*));
+ masm.moveStackPtrTo(temp);
+
+ masm.setupUnalignedABICall(output);
+ masm.loadJSContext(output);
+ masm.passABIArg(output);
+ masm.passABIArg(object);
+ masm.passABIArg(temp);
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpPrototypeOptimizableRaw));
+ masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
+
+ masm.load8ZeroExtend(Address(masm.getStackPointer(), 0), output);
+ masm.freeStack(sizeof(void*));
+
+ restoreVolatile(output);
+
+ masm.jump(ool->rejoin());
+}
+
typedef JSString* (*RegExpReplaceFn)(JSContext*, HandleString, HandleObject, HandleString);
static const VMFunction RegExpReplaceInfo = FunctionInfo<RegExpReplaceFn>(RegExpReplace);
void
CodeGenerator::visitRegExpReplace(LRegExpReplace* lir)
{
if (lir->replacement()->isConstant())
pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -43,16 +43,17 @@ class OutOfLineStoreElementHole;
class OutOfLineTypeOfV;
class OutOfLineUpdateCache;
class OutOfLineCallPostWriteBarrier;
class OutOfLineCallPostWriteElementBarrier;
class OutOfLineIsCallable;
class OutOfLineIsConstructor;
class OutOfLineRegExpMatcher;
class OutOfLineRegExpTester;
+class OutOfLineRegExpPrototypeOptimizable;
class OutOfLineLambdaArrow;
class CodeGenerator : public CodeGeneratorSpecific
{
void generateArgumentsChecks(bool bailout = true);
bool generateBody();
ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n, MIRType type);
@@ -108,16 +109,18 @@ class CodeGenerator : public CodeGenerat
void visitValueToObjectOrNull(LValueToObjectOrNull* lir);
void visitInteger(LInteger* lir);
void visitInteger64(LInteger64* lir);
void visitRegExp(LRegExp* lir);
void visitRegExpMatcher(LRegExpMatcher* lir);
void visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool);
void visitRegExpTester(LRegExpTester* lir);
void visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool);
+ void visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* lir);
+ void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool);
void visitRegExpReplace(LRegExpReplace* lir);
void visitStringReplace(LStringReplace* lir);
void emitSharedStub(ICStub::Kind kind, LInstruction* lir);
void visitBinarySharedStub(LBinarySharedStub* lir);
void visitUnarySharedStub(LUnarySharedStub* lir);
void visitLambda(LLambda* lir);
void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
void visitLambdaArrow(LLambdaArrow* lir);
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -63,16 +63,17 @@
_(MathACosH) \
_(MathSign) \
_(MathTrunc) \
_(MathCbrt) \
\
_(RegExpMatcher) \
_(RegExpTester) \
_(IsRegExpObject) \
+ _(RegExpPrototypeOptimizable) \
\
_(String) \
_(StringSplit) \
_(StringCharCodeAt) \
_(StringFromCharCode) \
_(StringCharAt) \
_(StringReplace) \
\
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -818,16 +818,17 @@ class IonBuilder
InliningStatus inlineStrFromCharCode(CallInfo& callInfo);
InliningStatus inlineStrCharAt(CallInfo& callInfo);
InliningStatus inlineStrReplace(CallInfo& callInfo);
// RegExp intrinsics.
InliningStatus inlineRegExpMatcher(CallInfo& callInfo);
InliningStatus inlineRegExpTester(CallInfo& callInfo);
InliningStatus inlineIsRegExpObject(CallInfo& callInfo);
+ InliningStatus inlineRegExpPrototypeOptimizable(CallInfo& callInfo);
// Object natives and intrinsics.
InliningStatus inlineObjectCreate(CallInfo& callInfo);
InliningStatus inlineDefineDataProperty(CallInfo& callInfo);
// Atomics natives.
InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo);
InliningStatus inlineAtomicsExchange(CallInfo& callInfo);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2281,16 +2281,26 @@ LIRGenerator::visitRegExpTester(MRegExpT
useFixedAtStart(ins->string(), RegExpTesterStringReg),
useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg),
useFixedAtStart(ins->sticky(), RegExpTesterStickyReg));
defineReturn(lir, ins);
assignSafepoint(lir, ins);
}
void
+LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins)
+{
+ MOZ_ASSERT(ins->object()->type() == MIRType_Object);
+ MOZ_ASSERT(ins->type() == MIRType_Boolean);
+ LRegExpPrototypeOptimizable* lir = new(alloc()) LRegExpPrototypeOptimizable(useRegister(ins->object()),
+ temp());
+ define(lir, ins);
+}
+
+void
LIRGenerator::visitRegExpReplace(MRegExpReplace* ins)
{
MOZ_ASSERT(ins->pattern()->type() == MIRType_Object);
MOZ_ASSERT(ins->string()->type() == MIRType_String);
MOZ_ASSERT(ins->replacement()->type() == MIRType_String);
LRegExpReplace* lir = new(alloc()) LRegExpReplace(useRegisterOrConstantAtStart(ins->string()),
useRegisterAtStart(ins->pattern()),
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -160,16 +160,17 @@ class LIRGenerator : public LIRGenerator
void visitTruncateToInt32(MTruncateToInt32* truncate);
void visitWrapInt64ToInt32(MWrapInt64ToInt32* ins);
void visitExtendInt32ToInt64(MExtendInt32ToInt64* ins);
void visitToString(MToString* convert);
void visitToObjectOrNull(MToObjectOrNull* convert);
void visitRegExp(MRegExp* ins);
void visitRegExpMatcher(MRegExpMatcher* ins);
void visitRegExpTester(MRegExpTester* ins);
+ void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
void visitRegExpReplace(MRegExpReplace* ins);
void visitStringReplace(MStringReplace* ins);
void visitBinarySharedStub(MBinarySharedStub* ins);
void visitUnarySharedStub(MUnarySharedStub* ins);
void visitLambda(MLambda* ins);
void visitLambdaArrow(MLambdaArrow* ins);
void visitKeepAliveObject(MKeepAliveObject* ins);
void visitSlots(MSlots* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1,15 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsmath.h"
+#include "jsstr.h"
#include "builtin/AtomicsObject.h"
#include "builtin/SIMD.h"
#include "builtin/TestingFunctions.h"
#include "builtin/TypedObject.h"
#include "jit/BaselineInspector.h"
#include "jit/InlinableNatives.h"
#include "jit/IonBuilder.h"
@@ -176,16 +177,18 @@ IonBuilder::inlineNativeCall(CallInfo& c
// RegExp natives.
case InlinableNative::RegExpMatcher:
return inlineRegExpMatcher(callInfo);
case InlinableNative::RegExpTester:
return inlineRegExpTester(callInfo);
case InlinableNative::IsRegExpObject:
return inlineIsRegExpObject(callInfo);
+ case InlinableNative::RegExpPrototypeOptimizable:
+ return inlineRegExpPrototypeOptimizable(callInfo);
// String natives.
case InlinableNative::String:
return inlineStringObject(callInfo);
case InlinableNative::StringSplit:
return inlineStringSplit(callInfo);
case InlinableNative::StringCharCodeAt:
return inlineStrCharCodeAt(callInfo);
@@ -1877,16 +1880,41 @@ IonBuilder::inlineIsRegExpObject(CallInf
pushConstant(BooleanValue(isRegExpObject));
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
+IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo)
+{
+ if (callInfo.argc() != 1 || callInfo.constructing()) {
+ trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
+ return InliningStatus_NotInlined;
+ }
+
+ MDefinition* protoArg = callInfo.getArg(0);
+
+ if (protoArg->type() != MIRType_Object)
+ return InliningStatus_NotInlined;
+
+ if (getInlineReturnType() != MIRType_Boolean)
+ return InliningStatus_NotInlined;
+
+ callInfo.setImplicitlyUsedUnchecked();
+
+ MInstruction* opt = MRegExpPrototypeOptimizable::New(alloc(), protoArg);
+ current->add(opt);
+ current->push(opt);
+
+ return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
IonBuilder::inlineStrReplace(CallInfo& callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Return: String.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -7987,16 +7987,41 @@ class MRegExpTester
}
bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
return true;
}
};
+class MRegExpPrototypeOptimizable
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MRegExpPrototypeOptimizable(MDefinition* object)
+ : MUnaryInstruction(object)
+ {
+ setResultType(MIRType_Boolean);
+ setMovable();
+ }
+
+ public:
+ INSTRUCTION_HEADER(RegExpPrototypeOptimizable)
+
+ static MRegExpPrototypeOptimizable* New(TempAllocator& alloc, MDefinition* obj) {
+ return new(alloc) MRegExpPrototypeOptimizable(obj);
+ }
+ MDefinition* object() const {
+ return getOperand(0);
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::None();
+ }
+};
+
template <class Policy1>
class MStrReplace
: public MTernaryInstruction,
public Mix3Policy<StringPolicy<0>, Policy1, StringPolicy<2> >::Data
{
protected:
MStrReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -142,16 +142,17 @@ namespace jit {
_(InitPropGetterSetter) \
_(Start) \
_(OsrEntry) \
_(Nop) \
_(LimitedTruncate) \
_(RegExp) \
_(RegExpMatcher) \
_(RegExpTester) \
+ _(RegExpPrototypeOptimizable) \
_(RegExpReplace) \
_(StringReplace) \
_(Lambda) \
_(LambdaArrow) \
_(KeepAliveObject) \
_(Slots) \
_(Elements) \
_(ConstantElements) \
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -4328,16 +4328,35 @@ class LRegExpTester : public LCallInstru
return getOperand(3);
}
const MRegExpTester* mir() const {
return mir_->toRegExpTester();
}
};
+class LRegExpPrototypeOptimizable : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(RegExpPrototypeOptimizable);
+ explicit LRegExpPrototypeOptimizable(const LAllocation& object, const LDefinition& temp) {
+ setOperand(0, object);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MRegExpPrototypeOptimizable* mir() const {
+ return mir_->toRegExpPrototypeOptimizable();
+ }
+};
class LStrReplace : public LCallInstructionHelper<1, 3, 0>
{
public:
LStrReplace(const LAllocation& string, const LAllocation& pattern,
const LAllocation& replacement)
{
setOperand(0, string);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -203,16 +203,17 @@
_(OsrEntry) \
_(OsrValue) \
_(OsrScopeChain) \
_(OsrReturnValue) \
_(OsrArgumentsObject) \
_(RegExp) \
_(RegExpMatcher) \
_(RegExpTester) \
+ _(RegExpPrototypeOptimizable) \
_(RegExpReplace) \
_(StringReplace) \
_(Substr) \
_(BinarySharedStub) \
_(UnarySharedStub) \
_(Lambda) \
_(LambdaArrow) \
_(LambdaForSingleton) \
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -620,16 +620,20 @@ struct JSCompartment
js::DtoaCache dtoaCache;
// Random number generator for Math.random().
mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
// Initialize randomNumberGenerator if needed.
void ensureRandomNumberGenerator();
+ static size_t offsetOfRegExps() {
+ return offsetof(JSCompartment, regExps);
+ }
+
private:
JSCompartment* thisForCtor() { return this; }
public:
//
// The Debugger observes execution on a frame-by-frame basis. The
// invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
// InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -91,16 +91,17 @@
macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \
macro(endTimestamp, endTimestamp, "endTimestamp") \
macro(entries, entries, "entries") \
macro(enumerable, enumerable, "enumerable") \
macro(enumerate, enumerate, "enumerate") \
macro(era, era, "era") \
macro(escape, escape, "escape") \
macro(eval, eval, "eval") \
+ macro(exec, exec, "exec") \
macro(false, false_, "false") \
macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
macro(fieldTypes, fieldTypes, "fieldTypes") \
macro(fileName, fileName, "fileName") \
macro(fill, fill, "fill") \
macro(find, find, "find") \
macro(findIndex, findIndex, "findIndex") \
macro(fix, fix, "fix") \
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -714,17 +714,19 @@ RegExpShared::sizeOfIncludingThis(mozill
n += mallocSizeOf(tables[i]);
return n;
}
/* RegExpCompartment */
RegExpCompartment::RegExpCompartment(JSRuntime* rt)
- : set_(rt), matchResultTemplateObject_(nullptr)
+ : set_(rt),
+ matchResultTemplateObject_(nullptr),
+ optimizableRegExpPrototypeShape_(nullptr)
{}
RegExpCompartment::~RegExpCompartment()
{
// Because of stray mark bits being set (see RegExpCompartment::sweep)
// there might still be RegExpShared instances which haven't been deleted.
if (set_.initialized()) {
for (Set::Enum e(set_); !e.empty(); e.popFront()) {
@@ -839,16 +841,22 @@ RegExpCompartment::sweep(JSRuntime* rt)
}
}
if (matchResultTemplateObject_ &&
IsAboutToBeFinalized(&matchResultTemplateObject_))
{
matchResultTemplateObject_.set(nullptr);
}
+
+ if (optimizableRegExpPrototypeShape_ &&
+ IsAboutToBeFinalized(&optimizableRegExpPrototypeShape_))
+ {
+ optimizableRegExpPrototypeShape_.set(nullptr);
+ }
}
bool
RegExpCompartment::get(JSContext* cx, JSAtom* source, RegExpFlag flags, RegExpGuard* g)
{
Key key(source, flags);
Set::AddPtr p = set_.lookupForAdd(key);
if (p) {
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -321,16 +321,26 @@ class RegExpCompartment
/*
* This is the template object where the result of re.exec() is based on,
* if there is a result. This is used in CreateRegExpMatchResult to set
* the input/index properties faster.
*/
ReadBarriered<ArrayObject*> matchResultTemplateObject_;
+ /*
+ * The shape of RegExp.prototype object that satisfies following:
+ * * RegExp.prototype.global getter is not modified
+ * * RegExp.prototype.sticky getter is not modified
+ * * RegExp.prototype.exec is an own data property
+ * * RegExp.prototype[@@match] is an own data property
+ * * RegExp.prototype[@@search] is an own data property
+ */
+ ReadBarriered<Shape*> optimizableRegExpPrototypeShape_;
+
ArrayObject* createMatchResultTemplateObject(JSContext* cx);
public:
explicit RegExpCompartment(JSRuntime* rt);
~RegExpCompartment();
bool init(JSContext* cx);
void sweep(JSRuntime* rt);
@@ -344,16 +354,27 @@ class RegExpCompartment
/* Get or create template object used to base the result of .exec() on. */
ArrayObject* getOrCreateMatchResultTemplateObject(JSContext* cx) {
if (matchResultTemplateObject_)
return matchResultTemplateObject_;
return createMatchResultTemplateObject(cx);
}
+ Shape* getOptimizableRegExpPrototypeShape() {
+ return optimizableRegExpPrototypeShape_;
+ }
+ void setOptimizableRegExpPrototypeShape(Shape* shape) {
+ optimizableRegExpPrototypeShape_ = shape;
+ }
+
+ static size_t offsetOfOptimizableRegExpPrototypeShape() {
+ return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_);
+ }
+
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
};
class RegExpObject : public NativeObject
{
static const unsigned LAST_INDEX_SLOT = 0;
static const unsigned SOURCE_SLOT = 1;
static const unsigned FLAGS_SLOT = 2;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2366,16 +2366,18 @@ static const JSFunctionSpec intrinsic_fu
IsRegExpObject),
JS_FN("CallRegExpMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2,0),
JS_INLINABLE_FN("RegExpMatcher", RegExpMatcher, 4,0,
RegExpMatcher),
JS_INLINABLE_FN("RegExpTester", RegExpTester, 4,0,
RegExpTester),
JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
+ JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
+ RegExpPrototypeOptimizable),
// See builtin/RegExp.h for descriptions of the regexp_* functions.
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
JS_FN("regexp_construct", regexp_construct_self_hosting, 2,0),
JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
JS_FN("CallModuleMethodIfWrapped",