mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1066828 - Fully inline RegExp.exec and .test in jitcode, r=jandem.
This commit is contained in:
parent
d8efbd5466
commit
2b950d362d
@ -59,15 +59,12 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs
|
||||
if (pair.isUndefined()) {
|
||||
MOZ_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
|
||||
arr->setDenseInitializedLength(i + 1);
|
||||
arr->initDenseElementWithType(cx, i, UndefinedValue());
|
||||
arr->initDenseElement(i, UndefinedValue());
|
||||
} else {
|
||||
JSLinearString *str = NewDependentString(cx, input, pair.start, pair.length());
|
||||
if (!str)
|
||||
return false;
|
||||
arr->setDenseInitializedLength(i + 1);
|
||||
|
||||
// We don't have to update type information here, since the match
|
||||
// result template is already known to have string elements.
|
||||
arr->initDenseElement(i, StringValue(str));
|
||||
}
|
||||
}
|
||||
@ -678,8 +675,13 @@ js::regexp_exec(JSContext *cx, unsigned argc, Value *vp)
|
||||
|
||||
/* Separate interface for use by IonMonkey. */
|
||||
bool
|
||||
js::regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, MutableHandleValue output)
|
||||
js::regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input,
|
||||
MatchPairs *maybeMatches, MutableHandleValue output)
|
||||
{
|
||||
// The MatchPairs will always be passed in, but RegExp execution was
|
||||
// successful only if the pairs have actually been filled in.
|
||||
if (maybeMatches && maybeMatches->pairsRaw()[0] >= 0)
|
||||
return CreateRegExpMatchResult(cx, input, *maybeMatches, output);
|
||||
return regexp_exec_impl(cx, regexp, input, UpdateRegExpStatics, output);
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs &mat
|
||||
MutableHandleValue rval);
|
||||
|
||||
extern bool
|
||||
regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, MutableHandleValue output);
|
||||
regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, MatchPairs *maybeMatches,
|
||||
MutableHandleValue output);
|
||||
|
||||
extern bool
|
||||
regexp_exec(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
@ -903,15 +903,6 @@ jit::FinishDiscardBaselineScript(FreeOp *fop, JSScript *script)
|
||||
BaselineScript::Destroy(fop, baseline);
|
||||
}
|
||||
|
||||
void
|
||||
jit::JitCompartment::toggleBaselineStubBarriers(bool enabled)
|
||||
{
|
||||
for (ICStubCodeMap::Enum e(*stubCodes_); !e.empty(); e.popFront()) {
|
||||
JitCode *code = *e.front().value().unsafeGet();
|
||||
code->togglePreBarriers(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
jit::AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size_t *data,
|
||||
size_t *fallbackStubs)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
# include "gc/Nursery.h"
|
||||
#endif
|
||||
#include "irregexp/NativeRegExpMacroAssembler.h"
|
||||
#include "jit/BaselineCompiler.h"
|
||||
#include "jit/IonBuilder.h"
|
||||
#include "jit/IonCaches.h"
|
||||
@ -36,6 +37,8 @@
|
||||
#include "jit/ParallelSafetyAnalysis.h"
|
||||
#include "jit/RangeAnalysis.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsboolinlines.h"
|
||||
@ -1012,28 +1015,633 @@ CodeGenerator::visitRegExp(LRegExp *lir)
|
||||
return callVM(CloneRegExpObjectInfo, lir);
|
||||
}
|
||||
|
||||
// The maximum number of pairs we can handle when executing RegExps inline.
|
||||
static const size_t RegExpMaxPairCount = 6;
|
||||
|
||||
// Amount of space to reserve on the stack when executing RegExps inline.
|
||||
static const size_t RegExpReservedStack = sizeof(irregexp::InputOutputData)
|
||||
+ sizeof(MatchPairs)
|
||||
+ RegExpMaxPairCount * sizeof(MatchPair);
|
||||
|
||||
static size_t
|
||||
RegExpPairsVectorStartOffset(size_t inputOutputDataStartOffset)
|
||||
{
|
||||
return inputOutputDataStartOffset + sizeof(irregexp::InputOutputData) + sizeof(MatchPairs);
|
||||
}
|
||||
|
||||
static Address
|
||||
RegExpPairCountAddress(size_t inputOutputDataStartOffset)
|
||||
{
|
||||
return Address(StackPointer, inputOutputDataStartOffset
|
||||
+ sizeof(irregexp::InputOutputData)
|
||||
+ MatchPairs::offsetOfPairCount());
|
||||
}
|
||||
|
||||
// Prepare an InputOutputData and optional MatchPairs which space has been
|
||||
// allocated for on the stack, and try to execute a RegExp on a string input.
|
||||
// If the RegExp was successfully executed and matched the input, fallthrough,
|
||||
// otherwise jump to notFound or failure.
|
||||
static bool
|
||||
PrepareAndExecuteRegExp(JSContext *cx, MacroAssembler &masm, Register regexp, Register input,
|
||||
Register temp1, Register temp2, Register temp3,
|
||||
size_t inputOutputDataStartOffset,
|
||||
RegExpShared::CompilationMode mode,
|
||||
Label *notFound, Label *failure)
|
||||
{
|
||||
size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
|
||||
size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
|
||||
|
||||
Address inputStartAddress(StackPointer,
|
||||
inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputStart));
|
||||
Address inputEndAddress(StackPointer,
|
||||
inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputEnd));
|
||||
Address matchesPointerAddress(StackPointer,
|
||||
inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, matches));
|
||||
Address startIndexAddress(StackPointer,
|
||||
inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, startIndex));
|
||||
Address matchResultAddress(StackPointer,
|
||||
inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, result));
|
||||
|
||||
Address pairCountAddress = RegExpPairCountAddress(inputOutputDataStartOffset);
|
||||
Address pairsPointerAddress(StackPointer, matchPairsStartOffset + MatchPairs::offsetOfPairs());
|
||||
|
||||
Address pairsVectorAddress(StackPointer, pairsVectorStartOffset);
|
||||
|
||||
RegExpStatics *res = cx->global()->getRegExpStatics(cx);
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
if (mode == RegExpShared::Normal) {
|
||||
// First, fill in a skeletal MatchPairs instance on the stack. This will be
|
||||
// passed to the OOL stub in the caller if we aren't able to execute the
|
||||
// RegExp inline, and that stub needs to be able to determine whether the
|
||||
// execution finished successfully.
|
||||
masm.store32(Imm32(1), pairCountAddress);
|
||||
masm.store32(Imm32(-1), pairsVectorAddress);
|
||||
masm.computeEffectiveAddress(pairsVectorAddress, temp1);
|
||||
masm.storePtr(temp1, pairsPointerAddress);
|
||||
}
|
||||
|
||||
// Check for a linear input string.
|
||||
masm.branchIfRope(input, failure);
|
||||
|
||||
// Get the RegExpShared for the RegExp.
|
||||
masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp1);
|
||||
masm.branchPtr(Assembler::Equal, temp1, ImmWord(0), failure);
|
||||
|
||||
// Don't handle RegExps which read and write to lastIndex.
|
||||
masm.branchTest32(Assembler::NonZero, Address(temp1, RegExpShared::offsetOfFlags()),
|
||||
Imm32(StickyFlag | GlobalFlag), failure);
|
||||
|
||||
if (mode == RegExpShared::Normal) {
|
||||
// Don't handle RegExps with excessive parens.
|
||||
masm.load32(Address(temp1, RegExpShared::offsetOfParenCount()), temp2);
|
||||
masm.branch32(Assembler::AboveOrEqual, temp2, Imm32(RegExpMaxPairCount), failure);
|
||||
|
||||
// Fill in the paren count in the MatchPairs on the stack.
|
||||
masm.add32(Imm32(1), temp2);
|
||||
masm.store32(temp2, pairCountAddress);
|
||||
}
|
||||
|
||||
// Load the code pointer for the type of input string we have, and compute
|
||||
// the input start/end pointers in the InputOutputData.
|
||||
Register codePointer = temp1;
|
||||
{
|
||||
masm.loadStringChars(input, temp2);
|
||||
masm.storePtr(temp2, inputStartAddress);
|
||||
masm.loadStringLength(input, temp3);
|
||||
Label isLatin1, done;
|
||||
masm.branchTest32(Assembler::NonZero, Address(input, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
|
||||
{
|
||||
masm.lshiftPtr(Imm32(1), temp3);
|
||||
masm.loadPtr(Address(temp1, RegExpShared::offsetOfJitCode(mode, false)), codePointer);
|
||||
}
|
||||
masm.jump(&done);
|
||||
{
|
||||
masm.bind(&isLatin1);
|
||||
masm.loadPtr(Address(temp1, RegExpShared::offsetOfJitCode(mode, true)), codePointer);
|
||||
}
|
||||
masm.bind(&done);
|
||||
masm.addPtr(temp3, temp2);
|
||||
masm.storePtr(temp2, inputEndAddress);
|
||||
}
|
||||
|
||||
// Check the RegExpShared has been compiled for this type of input.
|
||||
masm.branchPtr(Assembler::Equal, codePointer, ImmWord(0), failure);
|
||||
masm.loadPtr(Address(codePointer, JitCode::offsetOfCode()), codePointer);
|
||||
|
||||
// Don't handle execution inside a PreserveRegExpStatics instance.
|
||||
masm.branchPtr(Assembler::NotEqual, AbsoluteAddress(res->addressOfBufferLink()), ImmWord(0), failure);
|
||||
|
||||
// Finish filling in the InputOutputData instance on the stack.
|
||||
if (mode == RegExpShared::Normal) {
|
||||
masm.computeEffectiveAddress(Address(StackPointer, matchPairsStartOffset), temp2);
|
||||
masm.storePtr(temp2, matchesPointerAddress);
|
||||
}
|
||||
masm.storePtr(ImmWord(0), startIndexAddress);
|
||||
masm.store32(Imm32(0), matchResultAddress);
|
||||
|
||||
// Save any volatile inputs.
|
||||
GeneralRegisterSet volatileRegs;
|
||||
if (input.volatile_())
|
||||
volatileRegs.add(input);
|
||||
if (regexp.volatile_())
|
||||
volatileRegs.add(regexp);
|
||||
|
||||
// Execute the RegExp.
|
||||
masm.computeEffectiveAddress(Address(StackPointer, inputOutputDataStartOffset), temp2);
|
||||
masm.PushRegsInMask(volatileRegs);
|
||||
masm.setupUnalignedABICall(1, temp3);
|
||||
masm.passABIArg(temp2);
|
||||
masm.callWithABI(codePointer);
|
||||
masm.PopRegsInMask(volatileRegs);
|
||||
|
||||
Label success;
|
||||
masm.branch32(Assembler::Equal, matchResultAddress,
|
||||
Imm32(RegExpRunStatus_Success_NotFound), notFound);
|
||||
masm.branch32(Assembler::Equal, matchResultAddress,
|
||||
Imm32(RegExpRunStatus_Error), failure);
|
||||
|
||||
// Lazily update the RegExpStatics.
|
||||
masm.movePtr(ImmPtr(res), temp1);
|
||||
|
||||
Address pendingInputAddress(temp1, RegExpStatics::offsetOfPendingInput());
|
||||
Address matchesInputAddress(temp1, RegExpStatics::offsetOfMatchesInput());
|
||||
Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource());
|
||||
|
||||
masm.patchableCallPreBarrier(pendingInputAddress, MIRType_String);
|
||||
masm.patchableCallPreBarrier(matchesInputAddress, MIRType_String);
|
||||
masm.patchableCallPreBarrier(lazySourceAddress, MIRType_String);
|
||||
|
||||
masm.storePtr(input, pendingInputAddress);
|
||||
masm.storePtr(input, matchesInputAddress);
|
||||
masm.storePtr(ImmWord(0), Address(temp1, RegExpStatics::offsetOfLazyIndex()));
|
||||
masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
|
||||
|
||||
masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp2);
|
||||
masm.loadPtr(Address(temp2, RegExpShared::offsetOfSource()), temp3);
|
||||
masm.storePtr(temp3, lazySourceAddress);
|
||||
masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3);
|
||||
masm.store32(temp3, Address(temp1, RegExpStatics::offsetOfLazyFlags()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch,
|
||||
size_t fromWidth, size_t toWidth);
|
||||
|
||||
static void
|
||||
CreateDependentString(MacroAssembler &masm, const JSAtomState &names,
|
||||
bool latin1, Register string,
|
||||
Register base, Register temp1, Register temp2,
|
||||
BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
|
||||
Label *failure)
|
||||
{
|
||||
// Compute the string length.
|
||||
masm.load32(startIndexAddress, temp2);
|
||||
masm.load32(limitIndexAddress, temp1);
|
||||
masm.sub32(temp2, temp1);
|
||||
|
||||
Label done, nonEmpty;
|
||||
|
||||
// Zero length matches use the empty string.
|
||||
masm.branchTest32(Assembler::NonZero, temp1, temp1, &nonEmpty);
|
||||
masm.movePtr(ImmGCPtr(names.empty), string);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&nonEmpty);
|
||||
|
||||
Label notInline;
|
||||
|
||||
int32_t maxInlineLength =
|
||||
latin1 ? JSFatInlineString::MAX_LENGTH_LATIN1 : JSFatInlineString::MAX_LENGTH_TWO_BYTE;
|
||||
masm.branch32(Assembler::Above, temp1, Imm32(maxInlineLength), ¬Inline);
|
||||
|
||||
{
|
||||
// Make a normal or fat inline string.
|
||||
Label stringAllocated, fatInline;
|
||||
|
||||
int32_t maxNormalInlineLength =
|
||||
latin1 ? JSInlineString::MAX_LENGTH_LATIN1 : JSInlineString::MAX_LENGTH_TWO_BYTE;
|
||||
masm.branch32(Assembler::Above, temp1, Imm32(maxNormalInlineLength), &fatInline);
|
||||
|
||||
int32_t normalFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_INLINE_FLAGS;
|
||||
masm.newGCString(string, temp2, failure);
|
||||
masm.store32(Imm32(normalFlags), Address(string, JSString::offsetOfFlags()));
|
||||
masm.jump(&stringAllocated);
|
||||
|
||||
masm.bind(&fatInline);
|
||||
|
||||
int32_t fatFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_FAT_INLINE_FLAGS;
|
||||
masm.newGCFatInlineString(string, temp2, failure);
|
||||
masm.store32(Imm32(fatFlags), Address(string, JSString::offsetOfFlags()));
|
||||
|
||||
masm.bind(&stringAllocated);
|
||||
masm.store32(temp1, Address(string, JSString::offsetOfLength()));
|
||||
|
||||
masm.push(string);
|
||||
masm.push(base);
|
||||
|
||||
// Adjust the start index address for the above pushes.
|
||||
MOZ_ASSERT(startIndexAddress.base == StackPointer);
|
||||
BaseIndex newStartIndexAddress = startIndexAddress;
|
||||
newStartIndexAddress.offset += 2 * sizeof(void *);
|
||||
|
||||
// Load chars pointer for the new string.
|
||||
masm.addPtr(ImmWord(JSInlineString::offsetOfInlineStorage()), string);
|
||||
|
||||
// Load the source characters pointer.
|
||||
masm.loadStringChars(base, base);
|
||||
masm.load32(newStartIndexAddress, temp2);
|
||||
if (latin1)
|
||||
masm.addPtr(temp2, base);
|
||||
else
|
||||
masm.computeEffectiveAddress(BaseIndex(base, temp2, TimesTwo), base);
|
||||
|
||||
CopyStringChars(masm, string, base, temp1, temp2, latin1 ? 1 : 2, latin1 ? 1 : 2);
|
||||
|
||||
// Null-terminate.
|
||||
if (latin1)
|
||||
masm.store8(Imm32(0), Address(string, 0));
|
||||
else
|
||||
masm.store16(Imm32(0), Address(string, 0));
|
||||
|
||||
masm.pop(base);
|
||||
masm.pop(string);
|
||||
}
|
||||
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Inline);
|
||||
|
||||
{
|
||||
// Make a dependent string.
|
||||
int32_t flags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::DEPENDENT_FLAGS;
|
||||
|
||||
masm.newGCString(string, temp2, failure);
|
||||
masm.store32(Imm32(flags), Address(string, JSString::offsetOfFlags()));
|
||||
masm.store32(temp1, Address(string, JSString::offsetOfLength()));
|
||||
|
||||
masm.loadPtr(Address(base, JSString::offsetOfNonInlineChars()), temp1);
|
||||
masm.load32(startIndexAddress, temp2);
|
||||
if (latin1)
|
||||
masm.addPtr(temp2, temp1);
|
||||
else
|
||||
masm.computeEffectiveAddress(BaseIndex(temp1, temp2, TimesTwo), temp1);
|
||||
masm.storePtr(temp1, Address(string, JSString::offsetOfNonInlineChars()));
|
||||
masm.storePtr(base, Address(string, JSDependentString::offsetOfBase()));
|
||||
|
||||
// Follow any base pointer if the input is itself a dependent string.
|
||||
// Watch for undepended strings, which have a base pointer but don't
|
||||
// actually share their characters with it.
|
||||
Label noBase;
|
||||
masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::HAS_BASE_BIT), &noBase);
|
||||
masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::FLAT_BIT), &noBase);
|
||||
masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
|
||||
masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
|
||||
masm.bind(&noBase);
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
JitCode *
|
||||
JitCompartment::generateRegExpExecStub(JSContext *cx)
|
||||
{
|
||||
Register regexp = CallTempReg0;
|
||||
Register input = CallTempReg1;
|
||||
ValueOperand result = JSReturnOperand;
|
||||
|
||||
// We are free to clobber all registers, as LRegExpExec is a call instruction.
|
||||
GeneralRegisterSet regs = GeneralRegisterSet::All();
|
||||
regs.take(input);
|
||||
regs.take(regexp);
|
||||
|
||||
// temp5 is used in single byte instructions when creating dependent
|
||||
// strings, and has restrictions on which register it can be on some
|
||||
// platforms.
|
||||
Register temp5;
|
||||
{
|
||||
GeneralRegisterSet oregs = regs;
|
||||
do {
|
||||
temp5 = oregs.takeAny();
|
||||
} while (!MacroAssembler::canUseInSingleByteInstruction(temp5));
|
||||
regs.take(temp5);
|
||||
}
|
||||
|
||||
Register temp1 = regs.takeAny();
|
||||
Register temp2 = regs.takeAny();
|
||||
Register temp3 = regs.takeAny();
|
||||
Register temp4 = regs.takeAny();
|
||||
|
||||
ArrayObject *templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
|
||||
if (!templateObject)
|
||||
return nullptr;
|
||||
|
||||
// The template object should have enough space for the maximum number of
|
||||
// pairs this stub can handle.
|
||||
MOZ_ASSERT(ObjectElements::VALUES_PER_HEADER + RegExpMaxPairCount ==
|
||||
gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()));
|
||||
|
||||
MacroAssembler masm(cx);
|
||||
|
||||
// The InputOutputData is placed above the return address on the stack.
|
||||
size_t inputOutputDataStartOffset = sizeof(void *);
|
||||
|
||||
Label notFound, oolEntry;
|
||||
if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, temp1, temp2, temp3,
|
||||
inputOutputDataStartOffset, RegExpShared::Normal,
|
||||
¬Found, &oolEntry))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Construct the result.
|
||||
Register object = temp1;
|
||||
masm.createGCObject(object, temp2, templateObject, gc::DefaultHeap, &oolEntry);
|
||||
|
||||
Register matchIndex = temp2;
|
||||
masm.move32(Imm32(0), matchIndex);
|
||||
|
||||
size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
|
||||
Address pairsVectorAddress(StackPointer, pairsVectorStartOffset);
|
||||
Address pairCountAddress = RegExpPairCountAddress(inputOutputDataStartOffset);
|
||||
|
||||
size_t elementsOffset = NativeObject::offsetOfFixedElements();
|
||||
BaseIndex stringAddress(object, matchIndex, TimesEight, elementsOffset);
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(MatchPair) == 8);
|
||||
BaseIndex stringIndexAddress(StackPointer, matchIndex, TimesEight,
|
||||
pairsVectorStartOffset + offsetof(MatchPair, start));
|
||||
BaseIndex stringLimitAddress(StackPointer, matchIndex, TimesEight,
|
||||
pairsVectorStartOffset + offsetof(MatchPair, limit));
|
||||
|
||||
// Loop to construct the match strings. There are two different loops,
|
||||
// depending on whether the input is latin1.
|
||||
{
|
||||
Label isLatin1, done;
|
||||
masm.branchTest32(Assembler::NonZero, Address(input, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
|
||||
|
||||
for (int isLatin = 0; isLatin <= 1; isLatin++) {
|
||||
if (isLatin)
|
||||
masm.bind(&isLatin1);
|
||||
|
||||
Label matchLoop;
|
||||
masm.bind(&matchLoop);
|
||||
|
||||
Label isUndefined, storeDone;
|
||||
masm.branch32(Assembler::LessThan, stringIndexAddress, Imm32(0), &isUndefined);
|
||||
|
||||
CreateDependentString(masm, cx->names(), isLatin, temp3, input, temp4, temp5,
|
||||
stringIndexAddress, stringLimitAddress, &oolEntry);
|
||||
masm.storeValue(JSVAL_TYPE_STRING, temp3, stringAddress);
|
||||
|
||||
masm.jump(&storeDone);
|
||||
masm.bind(&isUndefined);
|
||||
|
||||
masm.storeValue(UndefinedValue(), stringAddress);
|
||||
masm.bind(&storeDone);
|
||||
|
||||
masm.add32(Imm32(1), matchIndex);
|
||||
masm.branch32(Assembler::LessThanOrEqual, pairCountAddress, matchIndex, &done);
|
||||
masm.jump(&matchLoop);
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
// Fill in the rest of the output object.
|
||||
masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
|
||||
masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
|
||||
|
||||
masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
|
||||
|
||||
MOZ_ASSERT(templateObject->numFixedSlots() == 0);
|
||||
MOZ_ASSERT(templateObject->lookupPure(cx->names().index)->slot() == 0);
|
||||
MOZ_ASSERT(templateObject->lookupPure(cx->names().input)->slot() == 1);
|
||||
|
||||
masm.load32(pairsVectorAddress, temp3);
|
||||
masm.storeValue(JSVAL_TYPE_INT32, temp3, Address(temp2, 0));
|
||||
masm.storeValue(JSVAL_TYPE_STRING, input, Address(temp2, sizeof(Value)));
|
||||
|
||||
// All done!
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, object, result);
|
||||
masm.ret();
|
||||
|
||||
masm.bind(¬Found);
|
||||
masm.moveValue(NullValue(), result);
|
||||
masm.ret();
|
||||
|
||||
// Use an undefined value to signal to the caller that the OOL stub needs to be called.
|
||||
masm.bind(&oolEntry);
|
||||
masm.moveValue(UndefinedValue(), result);
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("RegExpExecStub");
|
||||
JitCode *code = linker.newCode<CanGC>(cx, OTHER_CODE);
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "RegExpExecStub");
|
||||
#endif
|
||||
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
code->togglePreBarriers(true);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
class OutOfLineRegExpExec : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LRegExpExec *lir_;
|
||||
|
||||
public:
|
||||
explicit OutOfLineRegExpExec(LRegExpExec *lir)
|
||||
: lir_(lir)
|
||||
{ }
|
||||
|
||||
bool accept(CodeGenerator *codegen) {
|
||||
return codegen->visitOutOfLineRegExpExec(this);
|
||||
}
|
||||
|
||||
LRegExpExec *lir() const {
|
||||
return lir_;
|
||||
}
|
||||
};
|
||||
|
||||
typedef bool (*RegExpExecRawFn)(JSContext *cx, HandleObject regexp,
|
||||
HandleString input, MutableHandleValue output);
|
||||
HandleString input, MatchPairs *pairs, MutableHandleValue output);
|
||||
static const VMFunction RegExpExecRawInfo = FunctionInfo<RegExpExecRawFn>(regexp_exec_raw);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitOutOfLineRegExpExec(OutOfLineRegExpExec *ool)
|
||||
{
|
||||
LRegExpExec *lir = ool->lir();
|
||||
Register input = ToRegister(lir->string());
|
||||
Register regexp = ToRegister(lir->regexp());
|
||||
|
||||
GeneralRegisterSet regs = GeneralRegisterSet::All();
|
||||
regs.take(input);
|
||||
regs.take(regexp);
|
||||
Register temp = regs.takeAny();
|
||||
|
||||
masm.computeEffectiveAddress(Address(StackPointer, sizeof(irregexp::InputOutputData)), temp);
|
||||
|
||||
pushArg(temp);
|
||||
pushArg(input);
|
||||
pushArg(regexp);
|
||||
|
||||
if (!callVM(RegExpExecRawInfo, lir))
|
||||
return false;
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitRegExpExec(LRegExpExec *lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->string()));
|
||||
pushArg(ToRegister(lir->regexp()));
|
||||
return callVM(RegExpExecRawInfo, lir);
|
||||
MOZ_ASSERT(ToRegister(lir->regexp()) == CallTempReg0);
|
||||
MOZ_ASSERT(ToRegister(lir->string()) == CallTempReg1);
|
||||
MOZ_ASSERT(GetValueOutput(lir) == JSReturnOperand);
|
||||
|
||||
masm.reserveStack(RegExpReservedStack);
|
||||
|
||||
OutOfLineRegExpExec *ool = new(alloc()) OutOfLineRegExpExec(lir);
|
||||
if (!addOutOfLineCode(ool, lir->mir()))
|
||||
return false;
|
||||
|
||||
JitCode *regExpExecStub = gen->compartment->jitCompartment()->regExpExecStubNoBarrier();
|
||||
masm.call(regExpExecStub);
|
||||
masm.branchTestUndefined(Assembler::Equal, JSReturnOperand, ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
|
||||
masm.freeStack(RegExpReservedStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The value returned by the RegExp test stub if inline execution failed.
|
||||
static const int32_t RegExpTestFailedValue = 2;
|
||||
|
||||
JitCode *
|
||||
JitCompartment::generateRegExpTestStub(JSContext *cx)
|
||||
{
|
||||
Register regexp = CallTempReg2;
|
||||
Register input = CallTempReg3;
|
||||
Register result = ReturnReg;
|
||||
|
||||
MOZ_ASSERT(regexp != result && input != result);
|
||||
|
||||
// We are free to clobber all registers, as LRegExpTest is a call instruction.
|
||||
GeneralRegisterSet regs = GeneralRegisterSet::All();
|
||||
regs.take(input);
|
||||
regs.take(regexp);
|
||||
Register temp1 = regs.takeAny();
|
||||
Register temp2 = regs.takeAny();
|
||||
Register temp3 = regs.takeAny();
|
||||
|
||||
MacroAssembler masm(cx);
|
||||
|
||||
masm.reserveStack(sizeof(irregexp::InputOutputData));
|
||||
|
||||
Label notFound, oolEntry;
|
||||
if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, temp1, temp2, temp3, 0,
|
||||
RegExpShared::MatchOnly, ¬Found, &oolEntry))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Label done;
|
||||
|
||||
masm.move32(Imm32(1), result);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(¬Found);
|
||||
masm.move32(Imm32(0), result);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&oolEntry);
|
||||
masm.move32(Imm32(RegExpTestFailedValue), result);
|
||||
|
||||
masm.bind(&done);
|
||||
masm.freeStack(sizeof(irregexp::InputOutputData));
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("RegExpTestStub");
|
||||
JitCode *code = linker.newCode<CanGC>(cx, OTHER_CODE);
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "RegExpTestStub");
|
||||
#endif
|
||||
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
code->togglePreBarriers(true);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
class OutOfLineRegExpTest : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LRegExpTest *lir_;
|
||||
|
||||
public:
|
||||
explicit OutOfLineRegExpTest(LRegExpTest *lir)
|
||||
: lir_(lir)
|
||||
{ }
|
||||
|
||||
bool accept(CodeGenerator *codegen) {
|
||||
return codegen->visitOutOfLineRegExpTest(this);
|
||||
}
|
||||
|
||||
LRegExpTest *lir() const {
|
||||
return lir_;
|
||||
}
|
||||
};
|
||||
|
||||
typedef bool (*RegExpTestRawFn)(JSContext *cx, HandleObject regexp,
|
||||
HandleString input, bool *result);
|
||||
static const VMFunction RegExpTestRawInfo = FunctionInfo<RegExpTestRawFn>(regexp_test_raw);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitOutOfLineRegExpTest(OutOfLineRegExpTest *ool)
|
||||
{
|
||||
LRegExpTest *lir = ool->lir();
|
||||
Register input = ToRegister(lir->string());
|
||||
Register regexp = ToRegister(lir->regexp());
|
||||
|
||||
pushArg(input);
|
||||
pushArg(regexp);
|
||||
|
||||
if (!callVM(RegExpTestRawInfo, lir))
|
||||
return false;
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitRegExpTest(LRegExpTest *lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->string()));
|
||||
pushArg(ToRegister(lir->regexp()));
|
||||
return callVM(RegExpTestRawInfo, lir);
|
||||
MOZ_ASSERT(ToRegister(lir->regexp()) == CallTempReg2);
|
||||
MOZ_ASSERT(ToRegister(lir->string()) == CallTempReg3);
|
||||
MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
|
||||
|
||||
OutOfLineRegExpTest *ool = new(alloc()) OutOfLineRegExpTest(lir);
|
||||
if (!addOutOfLineCode(ool, lir->mir()))
|
||||
return false;
|
||||
|
||||
JitCode *regExpTestStub = gen->compartment->jitCompartment()->regExpTestStubNoBarrier();
|
||||
masm.call(regExpTestStub);
|
||||
|
||||
masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpTestFailedValue), ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSString *(*RegExpReplaceFn)(JSContext *, HandleString, HandleObject, HandleString);
|
||||
|
@ -44,6 +44,8 @@ class OutOfLineNewGCThingPar;
|
||||
class OutOfLineUpdateCache;
|
||||
class OutOfLineCallPostWriteBarrier;
|
||||
class OutOfLineIsCallable;
|
||||
class OutOfLineRegExpExec;
|
||||
class OutOfLineRegExpTest;
|
||||
|
||||
class CodeGenerator : public CodeGeneratorSpecific
|
||||
{
|
||||
@ -101,7 +103,9 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitInteger(LInteger *lir);
|
||||
bool visitRegExp(LRegExp *lir);
|
||||
bool visitRegExpExec(LRegExpExec *lir);
|
||||
bool visitOutOfLineRegExpExec(OutOfLineRegExpExec *ool);
|
||||
bool visitRegExpTest(LRegExpTest *lir);
|
||||
bool visitOutOfLineRegExpTest(OutOfLineRegExpTest *ool);
|
||||
bool visitRegExpReplace(LRegExpReplace *lir);
|
||||
bool visitStringReplace(LStringReplace *lir);
|
||||
bool visitLambda(LLambda *lir);
|
||||
|
@ -276,6 +276,11 @@ JitRuntime::initialize(JSContext *cx)
|
||||
if (!valuePreBarrier_)
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for String");
|
||||
stringPreBarrier_ = generatePreBarrier(cx, MIRType_String);
|
||||
if (!stringPreBarrier_)
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_Codegen, "# Emitting Pre Barrier for Shape");
|
||||
shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape);
|
||||
if (!shapePreBarrier_)
|
||||
@ -498,6 +503,8 @@ JitCompartment::JitCompartment()
|
||||
baselineSetPropReturnAddr_(nullptr),
|
||||
stringConcatStub_(nullptr),
|
||||
parallelStringConcatStub_(nullptr),
|
||||
regExpExecStub_(nullptr),
|
||||
regExpTestStub_(nullptr),
|
||||
activeParallelEntryScripts_(nullptr)
|
||||
{
|
||||
}
|
||||
@ -738,6 +745,12 @@ JitCompartment::sweep(FreeOp *fop, JSCompartment *compartment)
|
||||
if (parallelStringConcatStub_ && !IsJitCodeMarked(¶llelStringConcatStub_))
|
||||
parallelStringConcatStub_ = nullptr;
|
||||
|
||||
if (regExpExecStub_ && !IsJitCodeMarked(®ExpExecStub_))
|
||||
regExpExecStub_ = nullptr;
|
||||
|
||||
if (regExpTestStub_ && !IsJitCodeMarked(®ExpTestStub_))
|
||||
regExpTestStub_ = nullptr;
|
||||
|
||||
if (activeParallelEntryScripts_) {
|
||||
for (ScriptSet::Enum e(*activeParallelEntryScripts_); !e.empty(); e.popFront()) {
|
||||
JSScript *script = e.front();
|
||||
@ -749,6 +762,22 @@ JitCompartment::sweep(FreeOp *fop, JSCompartment *compartment)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitCompartment::toggleBarriers(bool enabled)
|
||||
{
|
||||
// Toggle barriers in compartment wide stubs that have patchable pre barriers.
|
||||
if (regExpExecStub_)
|
||||
regExpExecStub_->togglePreBarriers(enabled);
|
||||
if (regExpTestStub_)
|
||||
regExpTestStub_->togglePreBarriers(enabled);
|
||||
|
||||
// Toggle barriers in baseline IC stubs.
|
||||
for (ICStubCodeMap::Enum e(*stubCodes_); !e.empty(); e.popFront()) {
|
||||
JitCode *code = *e.front().value().unsafeGet();
|
||||
code->togglePreBarriers(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
JitCode *
|
||||
JitRuntime::getBailoutTable(const FrameSizeClass &frameClass) const
|
||||
{
|
||||
@ -1353,7 +1382,7 @@ jit::ToggleBarriers(JS::Zone *zone, bool needs)
|
||||
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
|
||||
if (comp->jitCompartment())
|
||||
comp->jitCompartment()->toggleBaselineStubBarriers(needs);
|
||||
comp->jitCompartment()->toggleBarriers(needs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +186,7 @@ class JitRuntime
|
||||
|
||||
// Thunk that calls the GC pre barrier.
|
||||
JitCode *valuePreBarrier_;
|
||||
JitCode *stringPreBarrier_;
|
||||
JitCode *shapePreBarrier_;
|
||||
JitCode *typeObjectPreBarrier_;
|
||||
|
||||
@ -359,6 +360,7 @@ class JitRuntime
|
||||
JitCode *preBarrier(MIRType type) const {
|
||||
switch (type) {
|
||||
case MIRType_Value: return valuePreBarrier_;
|
||||
case MIRType_String: return stringPreBarrier_;
|
||||
case MIRType_Shape: return shapePreBarrier_;
|
||||
case MIRType_TypeObject: return typeObjectPreBarrier_;
|
||||
default: MOZ_CRASH();
|
||||
@ -439,13 +441,16 @@ class JitCompartment
|
||||
void *baselineGetPropReturnAddr_;
|
||||
void *baselineSetPropReturnAddr_;
|
||||
|
||||
// Stub to concatenate two strings inline. Note that it can't be
|
||||
// stored in JitRuntime because masm.newGCString bakes in zone-specific
|
||||
// pointers. These are weak pointers, but are not declared as ReadBarriered
|
||||
// since they are only read from during Ion compilation, which may occur
|
||||
// off thread and whose barriers are captured during CodeGenerator::link.
|
||||
// Stubs to concatenate two strings inline, or perform RegExp calls inline.
|
||||
// These bake in zone and compartment specific pointers and can't be stored
|
||||
// in JitRuntime. These are weak pointers, but are not declared as
|
||||
// ReadBarriered since they are only read from during Ion compilation,
|
||||
// which may occur off thread and whose barriers are captured during
|
||||
// CodeGenerator::link.
|
||||
JitCode *stringConcatStub_;
|
||||
JitCode *parallelStringConcatStub_;
|
||||
JitCode *regExpExecStub_;
|
||||
JitCode *regExpTestStub_;
|
||||
|
||||
// Set of JSScripts invoked by ForkJoin (i.e. the entry script). These
|
||||
// scripts are marked if their respective parallel IonScripts' age is less
|
||||
@ -454,6 +459,8 @@ class JitCompartment
|
||||
ScriptSet *activeParallelEntryScripts_;
|
||||
|
||||
JitCode *generateStringConcatStub(JSContext *cx, ExecutionMode mode);
|
||||
JitCode *generateRegExpExecStub(JSContext *cx);
|
||||
JitCode *generateRegExpTestStub(JSContext *cx);
|
||||
|
||||
public:
|
||||
JitCode *getStubCode(uint32_t key) {
|
||||
@ -498,7 +505,7 @@ class JitCompartment
|
||||
bool notifyOfActiveParallelEntryScript(JSContext *cx, HandleScript script);
|
||||
bool hasRecentParallelActivity() const;
|
||||
|
||||
void toggleBaselineStubBarriers(bool enabled);
|
||||
void toggleBarriers(bool enabled);
|
||||
|
||||
ExecutableAllocator *createIonAlloc();
|
||||
|
||||
@ -521,6 +528,28 @@ class JitCompartment
|
||||
default: MOZ_CRASH("No such execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
JitCode *regExpExecStubNoBarrier() const {
|
||||
return regExpExecStub_;
|
||||
}
|
||||
|
||||
bool ensureRegExpExecStubExists(JSContext *cx) {
|
||||
if (regExpExecStub_)
|
||||
return true;
|
||||
regExpExecStub_ = generateRegExpExecStub(cx);
|
||||
return regExpExecStub_ != nullptr;
|
||||
}
|
||||
|
||||
JitCode *regExpTestStubNoBarrier() const {
|
||||
return regExpTestStub_;
|
||||
}
|
||||
|
||||
bool ensureRegExpTestStubExists(JSContext *cx) {
|
||||
if (regExpTestStub_)
|
||||
return true;
|
||||
regExpTestStub_ = generateRegExpTestStub(cx);
|
||||
return regExpTestStub_ != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Called from JSCompartment::discardJitCode().
|
||||
|
@ -2095,8 +2095,8 @@ LIRGenerator::visitRegExpExec(MRegExpExec *ins)
|
||||
MOZ_ASSERT(ins->regexp()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->string()->type() == MIRType_String);
|
||||
|
||||
LRegExpExec *lir = new(alloc()) LRegExpExec(useRegisterAtStart(ins->regexp()),
|
||||
useRegisterAtStart(ins->string()));
|
||||
LRegExpExec *lir = new(alloc()) LRegExpExec(useFixedAtStart(ins->regexp(), CallTempReg0),
|
||||
useFixedAtStart(ins->string(), CallTempReg1));
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
@ -2106,8 +2106,8 @@ LIRGenerator::visitRegExpTest(MRegExpTest *ins)
|
||||
MOZ_ASSERT(ins->regexp()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->string()->type() == MIRType_String);
|
||||
|
||||
LRegExpTest *lir = new(alloc()) LRegExpTest(useRegisterAtStart(ins->regexp()),
|
||||
useRegisterAtStart(ins->string()));
|
||||
LRegExpTest *lir = new(alloc()) LRegExpTest(useFixedAtStart(ins->regexp(), CallTempReg2),
|
||||
useFixedAtStart(ins->string(), CallTempReg3));
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
|
@ -1389,6 +1389,10 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
|
||||
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
if (!cx->compartment()->jitCompartment()->ensureRegExpExecStubExists(cx))
|
||||
return InliningStatus_Error;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MInstruction *exec = MRegExpExec::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
|
||||
@ -1423,6 +1427,10 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
|
||||
if (callInfo.getArg(0)->mightBeType(MIRType_Object))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
if (!cx->compartment()->jitCompartment()->ensureRegExpTestStubExists(cx))
|
||||
return InliningStatus_Error;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MInstruction *match = MRegExpTest::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
|
||||
|
@ -906,7 +906,7 @@ bool RRegExpExec::recover(JSContext *cx, SnapshotIterator &iter) const{
|
||||
|
||||
RootedValue result(cx);
|
||||
|
||||
if(!regexp_exec_raw(cx, regexp, input, &result))
|
||||
if (!regexp_exec_raw(cx, regexp, input, nullptr, &result))
|
||||
return false;
|
||||
|
||||
iter.storeInstructionResult(result);
|
||||
|
@ -1216,6 +1216,13 @@ MarkValueFromIon(JSRuntime *rt, Value *vp)
|
||||
gc::MarkValueUnbarriered(&rt->gc.marker, vp, "write barrier");
|
||||
}
|
||||
|
||||
void
|
||||
MarkStringFromIon(JSRuntime *rt, JSString **stringp)
|
||||
{
|
||||
if (*stringp)
|
||||
gc::MarkStringUnbarriered(&rt->gc.marker, stringp, "write barrier");
|
||||
}
|
||||
|
||||
void
|
||||
MarkShapeFromIon(JSRuntime *rt, Shape **shapep)
|
||||
{
|
||||
|
@ -742,6 +742,7 @@ void AssertValidValue(JSContext *cx, Value *v);
|
||||
JSObject *TypedObjectProto(JSObject *obj);
|
||||
|
||||
void MarkValueFromIon(JSRuntime *rt, Value *vp);
|
||||
void MarkStringFromIon(JSRuntime *rt, JSString **stringp);
|
||||
void MarkShapeFromIon(JSRuntime *rt, Shape **shapep);
|
||||
void MarkTypeObjectFromIon(JSRuntime *rt, types::TypeObject **typep);
|
||||
|
||||
@ -752,6 +753,8 @@ IonMarkFunction(MIRType type)
|
||||
switch (type) {
|
||||
case MIRType_Value:
|
||||
return JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon);
|
||||
case MIRType_String:
|
||||
return JS_FUNC_TO_DATA_PTR(void *, MarkStringFromIon);
|
||||
case MIRType_Shape:
|
||||
return JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon);
|
||||
case MIRType_TypeObject:
|
||||
|
@ -4158,6 +4158,17 @@ MacroAssemblerARMCompat::callWithABI(const Address &fun, MoveOp::Type result)
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in r12, as above.
|
||||
ma_mov(fun, r12);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(r12);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
|
@ -886,6 +886,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
load32(lhs, secondScratchReg_);
|
||||
branch32(cond, secondScratchReg_, rhs, label);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Imm32 rhs, Label *label) {
|
||||
// branch32 will use ScratchRegister.
|
||||
load32(lhs, secondScratchReg_);
|
||||
branch32(cond, secondScratchReg_, rhs, label);
|
||||
}
|
||||
void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
|
||||
branch32(cond, lhs, rhs, label);
|
||||
}
|
||||
@ -1056,6 +1061,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_cmp(ScratchRegister, ptr);
|
||||
ma_b(label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, AbsoluteAddress addr, ImmWord ptr, Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ptr);
|
||||
ma_b(label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, AsmJSAbsoluteAddress addr, Register ptr, Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, ptr);
|
||||
@ -1122,10 +1132,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void storeValue(ValueOperand val, Operand dst);
|
||||
void storeValue(ValueOperand val, const BaseIndex &dest);
|
||||
void storeValue(JSValueType type, Register reg, BaseIndex dest) {
|
||||
// Harder cases not handled yet.
|
||||
MOZ_ASSERT(dest.offset == 0);
|
||||
ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, OpAdd);
|
||||
storeValue(type, reg, Address(ScratchRegister, 0));
|
||||
storeValue(type, reg, Address(ScratchRegister, dest.offset));
|
||||
}
|
||||
void storeValue(ValueOperand val, const Address &dest) {
|
||||
storeValue(val, Operand(dest));
|
||||
@ -1146,10 +1154,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
ma_str(secondScratchReg_, dest);
|
||||
}
|
||||
void storeValue(const Value &val, BaseIndex dest) {
|
||||
// Harder cases not handled yet.
|
||||
MOZ_ASSERT(dest.offset == 0);
|
||||
ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, OpAdd);
|
||||
storeValue(val, Address(ScratchRegister, 0));
|
||||
storeValue(val, Address(ScratchRegister, dest.offset));
|
||||
}
|
||||
|
||||
void loadValue(Address src, ValueOperand val);
|
||||
@ -1558,6 +1564,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
CodeOffsetLabel labelForPatch() {
|
||||
return CodeOffsetLabel(nextOffset().getOffset());
|
||||
|
@ -3440,6 +3440,17 @@ MacroAssemblerMIPSCompat::callWithABI(const Address &fun, MoveOp::Type result)
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in t9, as above.
|
||||
ma_move(t9, fun);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(t9);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
|
@ -629,6 +629,10 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
||||
ma_lw(SecondScratchReg, lhs);
|
||||
ma_b(SecondScratchReg, rhs, label, cond);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Imm32 rhs, Label *label) {
|
||||
load32(lhs, SecondScratchReg);
|
||||
ma_b(SecondScratchReg, rhs, label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
|
||||
branch32(cond, lhs, rhs, label);
|
||||
}
|
||||
@ -796,6 +800,10 @@ public:
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_b(ScratchRegister, ptr, label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, AbsoluteAddress addr, ImmWord ptr, Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_b(ScratchRegister, Imm32(ptr.value), label, cond);
|
||||
}
|
||||
void branchPtr(Condition cond, AsmJSAbsoluteAddress addr, Register ptr,
|
||||
Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
@ -1253,6 +1261,7 @@ public:
|
||||
void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
CodeOffsetLabel labelForPatch() {
|
||||
return CodeOffsetLabel(nextOffset().getOffset());
|
||||
|
@ -865,6 +865,8 @@ class AssemblerShared
|
||||
void append(AsmJSAbsoluteLink link) { enoughMemory_ &= asmJSAbsoluteLinks_.append(link); }
|
||||
size_t numAsmJSAbsoluteLinks() const { return asmJSAbsoluteLinks_.length(); }
|
||||
AsmJSAbsoluteLink asmJSAbsoluteLink(size_t i) const { return asmJSAbsoluteLinks_[i]; }
|
||||
|
||||
static bool canUseInSingleByteInstruction(Register reg) { return true; }
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
@ -161,6 +161,13 @@ namespace X86Registers {
|
||||
|
||||
} /* namespace X86Registers */
|
||||
|
||||
// Byte operand register spl & above require a REX prefix (to prevent
|
||||
// the 'H' registers be accessed).
|
||||
static inline bool
|
||||
ByteRegRequiresRex(int reg)
|
||||
{
|
||||
return (reg >= X86Registers::esp);
|
||||
}
|
||||
|
||||
class X86Assembler : public GenericAssembler {
|
||||
public:
|
||||
@ -4407,16 +4414,16 @@ private:
|
||||
// byte of the second four registers (spl..dil).
|
||||
//
|
||||
// Address operands should still be checked using regRequiresRex(),
|
||||
// while byteRegRequiresRex() is provided to check byte register
|
||||
// while ByteRegRequiresRex() is provided to check byte register
|
||||
// operands.
|
||||
|
||||
void oneByteOp8(OneByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X86
|
||||
MOZ_ASSERT(!byteRegRequiresRex(rm));
|
||||
MOZ_ASSERT(!ByteRegRequiresRex(rm));
|
||||
#endif
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(rm), 0, 0, rm);
|
||||
emitRexIf(ByteRegRequiresRex(rm), 0, 0, rm);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
registerModRM(groupOp, rm);
|
||||
}
|
||||
@ -4433,10 +4440,10 @@ private:
|
||||
void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X86
|
||||
MOZ_ASSERT(!byteRegRequiresRex(reg));
|
||||
MOZ_ASSERT(!ByteRegRequiresRex(reg));
|
||||
#endif
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg), reg, 0, base);
|
||||
emitRexIf(ByteRegRequiresRex(reg), reg, 0, base);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM(reg, base, offset);
|
||||
}
|
||||
@ -4444,10 +4451,10 @@ private:
|
||||
void oneByteOp8_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X86
|
||||
MOZ_ASSERT(!byteRegRequiresRex(reg));
|
||||
MOZ_ASSERT(!ByteRegRequiresRex(reg));
|
||||
#endif
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg), reg, 0, base);
|
||||
emitRexIf(ByteRegRequiresRex(reg), reg, 0, base);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM_disp32(reg, base, offset);
|
||||
}
|
||||
@ -4455,10 +4462,10 @@ private:
|
||||
void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X86
|
||||
MOZ_ASSERT(!byteRegRequiresRex(reg));
|
||||
MOZ_ASSERT(!ByteRegRequiresRex(reg));
|
||||
#endif
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg), reg, index, base);
|
||||
emitRexIf(ByteRegRequiresRex(reg), reg, index, base);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM(reg, base, index, scale, offset);
|
||||
}
|
||||
@ -4466,10 +4473,10 @@ private:
|
||||
void oneByteOp8(OneByteOpcodeID opcode, int reg, const void* address)
|
||||
{
|
||||
#ifdef JS_CODEGEN_X86
|
||||
MOZ_ASSERT(!byteRegRequiresRex(reg));
|
||||
MOZ_ASSERT(!ByteRegRequiresRex(reg));
|
||||
#endif
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg), reg, 0, 0);
|
||||
emitRexIf(ByteRegRequiresRex(reg), reg, 0, 0);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM_disp32(reg, address);
|
||||
}
|
||||
@ -4477,7 +4484,7 @@ private:
|
||||
void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm)
|
||||
{
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
|
||||
emitRexIf(ByteRegRequiresRex(reg)|ByteRegRequiresRex(rm), reg, 0, rm);
|
||||
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
registerModRM(reg, rm);
|
||||
@ -4490,7 +4497,7 @@ private:
|
||||
void twoByteOp8_movx(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm)
|
||||
{
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(regRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
|
||||
emitRexIf(regRequiresRex(reg)|ByteRegRequiresRex(rm), reg, 0, rm);
|
||||
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
registerModRM(reg, rm);
|
||||
@ -4499,7 +4506,7 @@ private:
|
||||
void twoByteOp8(TwoByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm)
|
||||
{
|
||||
m_buffer.ensureSpace(maxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(rm), 0, 0, rm);
|
||||
emitRexIf(ByteRegRequiresRex(rm), 0, 0, rm);
|
||||
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
registerModRM(groupOp, rm);
|
||||
@ -4612,13 +4619,6 @@ private:
|
||||
|
||||
// Internals; ModRm and REX formatters.
|
||||
|
||||
// Byte operand register spl & above require a REX prefix (to prevent
|
||||
// the 'H' registers be accessed).
|
||||
inline bool byteRegRequiresRex(int reg)
|
||||
{
|
||||
return (reg >= X86Registers::esp);
|
||||
}
|
||||
|
||||
static const RegisterID noBase = X86Registers::ebp;
|
||||
static const RegisterID hasSib = X86Registers::esp;
|
||||
static const RegisterID noIndex = X86Registers::esp;
|
||||
@ -4644,7 +4644,7 @@ private:
|
||||
emitRex(true, r, x, b);
|
||||
}
|
||||
|
||||
// Used for operations with byte operands - use byteRegRequiresRex() to
|
||||
// Used for operations with byte operands - use ByteRegRequiresRex() to
|
||||
// check register operands, regRequiresRex() to check other registers
|
||||
// (i.e. address base & index).
|
||||
//
|
||||
|
@ -219,6 +219,14 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
cmpl(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Register rhs, Label *label) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Imm32 imm, Label *label) {
|
||||
cmpl(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
cmpl(lhs, imm);
|
||||
j(cond, label);
|
||||
|
@ -359,6 +359,24 @@ MacroAssemblerX64::callWithABI(Address fun, MoveOp::Type result)
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
if (IsIntArgReg(fun)) {
|
||||
// Callee register may be clobbered for an argument. Move the callee to
|
||||
// r10, a volatile, non-argument register.
|
||||
moveResolver_.addMove(MoveOperand(fun), MoveOperand(r10), MoveOp::GENERAL);
|
||||
fun = r10;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsIntArgReg(fun));
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(Operand(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
|
@ -634,6 +634,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label);
|
||||
}
|
||||
}
|
||||
void branchPtr(Condition cond, AbsoluteAddress addr, ImmWord ptr, Label *label) {
|
||||
if (X86Assembler::isAddressImmediate(addr.addr)) {
|
||||
branchPtr(cond, Operand(addr), ptr, label);
|
||||
} else {
|
||||
mov(ImmPtr(addr.addr), ScratchReg);
|
||||
branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label);
|
||||
}
|
||||
}
|
||||
void branchPtr(Condition cond, AsmJSAbsoluteAddress addr, Register ptr, Label *label) {
|
||||
MOZ_ASSERT(ptr != ScratchReg);
|
||||
mov(AsmJSImmPtr(addr.kind()), ScratchReg);
|
||||
@ -1361,6 +1369,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
void handleFailureWithHandler(void *handler);
|
||||
void handleFailureWithHandlerTail();
|
||||
|
@ -572,6 +572,10 @@ class Assembler : public AssemblerX86Shared
|
||||
CodeOffsetLabel label = movlWithPatch(PatchedAbsoluteAddress(), dest);
|
||||
append(AsmJSGlobalAccess(label, AsmJSActivationGlobalDataOffset));
|
||||
}
|
||||
|
||||
static bool canUseInSingleByteInstruction(Register reg) {
|
||||
return !ByteRegRequiresRex(reg.code());
|
||||
}
|
||||
};
|
||||
|
||||
// Get a register in which we plan to put a quantity that will be used as an
|
||||
|
@ -348,6 +348,15 @@ MacroAssemblerX86::callWithABI(const Address &fun, MoveOp::Type result)
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(Operand(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::handleFailureWithHandler(void *handler)
|
||||
{
|
||||
|
@ -1120,6 +1120,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
// Used from within an Exit frame to handle a pending exception.
|
||||
void handleFailureWithHandler(void *handler);
|
||||
|
@ -699,7 +699,7 @@ RegExpCompartment::~RegExpCompartment()
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *
|
||||
ArrayObject *
|
||||
RegExpCompartment::createMatchResultTemplateObject(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(!matchResultTemplateObject_);
|
||||
@ -737,6 +737,7 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext *cx)
|
||||
// Make sure type information reflects the indexed properties which might
|
||||
// be added.
|
||||
types::AddTypePropertyId(cx, templateObject, JSID_VOID, types::Type::StringType());
|
||||
types::AddTypePropertyId(cx, templateObject, JSID_VOID, types::Type::UndefinedType());
|
||||
|
||||
matchResultTemplateObject_.set(templateObject);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "proxy/Proxy.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/Shape.h"
|
||||
|
||||
/*
|
||||
@ -201,6 +202,24 @@ class RegExpShared
|
||||
bool marked() const { return marked_; }
|
||||
void clearMarked() { marked_ = false; }
|
||||
|
||||
static size_t offsetOfSource() {
|
||||
return offsetof(RegExpShared, source);
|
||||
}
|
||||
|
||||
static size_t offsetOfFlags() {
|
||||
return offsetof(RegExpShared, flags);
|
||||
}
|
||||
|
||||
static size_t offsetOfParenCount() {
|
||||
return offsetof(RegExpShared, parenCount);
|
||||
}
|
||||
|
||||
static size_t offsetOfJitCode(CompilationMode mode, bool latin1) {
|
||||
return offsetof(RegExpShared, compilationArray)
|
||||
+ (CompilationIndex(mode, latin1) * sizeof(RegExpCompilation))
|
||||
+ offsetof(RegExpCompilation, jitCode);
|
||||
}
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
};
|
||||
|
||||
@ -286,9 +305,9 @@ class RegExpCompartment
|
||||
* if there is a result. This is used in CreateRegExpMatchResult to set
|
||||
* the input/index properties faster.
|
||||
*/
|
||||
ReadBarrieredObject matchResultTemplateObject_;
|
||||
ReadBarriered<ArrayObject *> matchResultTemplateObject_;
|
||||
|
||||
JSObject *createMatchResultTemplateObject(JSContext *cx);
|
||||
ArrayObject *createMatchResultTemplateObject(JSContext *cx);
|
||||
|
||||
public:
|
||||
explicit RegExpCompartment(JSRuntime *rt);
|
||||
@ -305,7 +324,7 @@ class RegExpCompartment
|
||||
bool get(JSContext *cx, HandleAtom source, JSString *maybeOpt, RegExpGuard *g);
|
||||
|
||||
/* Get or create template object used to base the result of .exec() on. */
|
||||
JSObject *getOrCreateMatchResultTemplateObject(JSContext *cx) {
|
||||
ArrayObject *getOrCreateMatchResultTemplateObject(JSContext *cx) {
|
||||
if (matchResultTemplateObject_)
|
||||
return matchResultTemplateObject_;
|
||||
return createMatchResultTemplateObject(cx);
|
||||
@ -325,6 +344,7 @@ class RegExpObject : public NativeObject
|
||||
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 6;
|
||||
static const unsigned PRIVATE_SLOT = 7;
|
||||
|
||||
static const Class class_;
|
||||
|
||||
@ -436,7 +456,7 @@ class RegExpObject : public NativeObject
|
||||
*/
|
||||
bool createShared(JSContext *cx, RegExpGuard *g);
|
||||
RegExpShared *maybeShared() const {
|
||||
return static_cast<RegExpShared *>(NativeObject::getPrivate());
|
||||
return static_cast<RegExpShared *>(NativeObject::getPrivate(PRIVATE_SLOT));
|
||||
}
|
||||
|
||||
/* Call setShared in preference to setPrivate. */
|
||||
|
@ -37,10 +37,10 @@ class RegExpStatics
|
||||
RegExpFlag flags;
|
||||
|
||||
/*
|
||||
* If true, |matchesInput| and the |lazy*| fields may be used
|
||||
* If non-zero, |matchesInput| and the |lazy*| fields may be used
|
||||
* to replay the last executed RegExp, and |matches| is invalid.
|
||||
*/
|
||||
bool pendingLazyEvaluation;
|
||||
int32_t pendingLazyEvaluation;
|
||||
|
||||
/* Linkage for preserving RegExpStatics during nested RegExp execution. */
|
||||
RegExpStatics *bufferLink;
|
||||
@ -156,6 +156,34 @@ class RegExpStatics
|
||||
void getLastParen(JSSubString *out) const;
|
||||
void getLeftContext(JSSubString *out) const;
|
||||
void getRightContext(JSSubString *out) const;
|
||||
|
||||
const void *addressOfBufferLink() {
|
||||
return &bufferLink;
|
||||
}
|
||||
|
||||
static size_t offsetOfPendingInput() {
|
||||
return offsetof(RegExpStatics, pendingInput);
|
||||
}
|
||||
|
||||
static size_t offsetOfMatchesInput() {
|
||||
return offsetof(RegExpStatics, matchesInput);
|
||||
}
|
||||
|
||||
static size_t offsetOfLazySource() {
|
||||
return offsetof(RegExpStatics, lazySource);
|
||||
}
|
||||
|
||||
static size_t offsetOfLazyFlags() {
|
||||
return offsetof(RegExpStatics, lazyFlags);
|
||||
}
|
||||
|
||||
static size_t offsetOfLazyIndex() {
|
||||
return offsetof(RegExpStatics, lazyIndex);
|
||||
}
|
||||
|
||||
static size_t offsetOfPendingLazyEvaluation() {
|
||||
return offsetof(RegExpStatics, pendingLazyEvaluation);
|
||||
}
|
||||
};
|
||||
|
||||
class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
|
||||
@ -439,7 +467,7 @@ RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input,
|
||||
lazySource = shared->source;
|
||||
lazyFlags = shared->flags;
|
||||
lazyIndex = lastIndex;
|
||||
pendingLazyEvaluation = true;
|
||||
pendingLazyEvaluation = 1;
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -161,10 +161,11 @@ JSDependentString::new_(js::ExclusiveContext *cx, JSLinearString *baseArg, size_
|
||||
size_t length)
|
||||
{
|
||||
/* Try to avoid long chains of dependent strings. */
|
||||
while (baseArg->isDependent()) {
|
||||
if (baseArg->isDependent()) {
|
||||
start += baseArg->asDependent().baseOffset();
|
||||
baseArg = baseArg->asDependent().base();
|
||||
}
|
||||
MOZ_ASSERT(!baseArg->isDependent());
|
||||
|
||||
MOZ_ASSERT(start + length <= baseArg->length());
|
||||
MOZ_ASSERT(baseArg->isFlat());
|
||||
|
@ -682,6 +682,10 @@ class JSDependentString : public JSLinearString
|
||||
public:
|
||||
static inline JSLinearString *new_(js::ExclusiveContext *cx, JSLinearString *base,
|
||||
size_t start, size_t length);
|
||||
|
||||
inline static size_t offsetOfBase() {
|
||||
return offsetof(JSDependentString, d.s.u3.base);
|
||||
}
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSDependentString) == sizeof(JSString));
|
||||
@ -769,10 +773,10 @@ JS_STATIC_ASSERT(sizeof(JSExtensibleString) == sizeof(JSString));
|
||||
*/
|
||||
class JSInlineString : public JSFlatString
|
||||
{
|
||||
public:
|
||||
static const size_t MAX_LENGTH_LATIN1 = NUM_INLINE_CHARS_LATIN1 - 1;
|
||||
static const size_t MAX_LENGTH_TWO_BYTE = NUM_INLINE_CHARS_TWO_BYTE - 1;
|
||||
|
||||
public:
|
||||
template <js::AllowGC allowGC>
|
||||
static inline JSInlineString *new_(js::ThreadSafeContext *cx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user