зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1692517 - Part 8: Inline RegExp flags getters. r=jandem
For Warp this reuses the same approach we had in Ion to convert the flag to a boolean, i.e. `MBitAnd` with a constant and then two `MNot` to convert the int32 to a boolean. Differential Revision: https://phabricator.services.mozilla.com/D105183
This commit is contained in:
Родитель
6b07227f3a
Коммит
156536c558
|
@ -0,0 +1,61 @@
|
|||
// Test inlining for RegExp flag getters.
|
||||
|
||||
function testGlobal() {
|
||||
const xs = [/a/, /b/g];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.global, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testGlobal();
|
||||
|
||||
function testIgnoreCase() {
|
||||
const xs = [/a/, /b/i];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.ignoreCase, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testIgnoreCase();
|
||||
|
||||
function testMultiline() {
|
||||
const xs = [/a/, /b/m];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.multiline, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testMultiline();
|
||||
|
||||
function testDotAll() {
|
||||
const xs = [/a/, /b/s];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.dotAll, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testDotAll();
|
||||
|
||||
function testUnicode() {
|
||||
const xs = [/a/, /b/u];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.unicode, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testUnicode();
|
||||
|
||||
function testSticky() {
|
||||
const xs = [/a/, /b/y];
|
||||
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
let x = xs[i & 1];
|
||||
assertEq(x.sticky, !!(i & 1));
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 2; ++i) testSticky();
|
|
@ -27,6 +27,7 @@
|
|||
#include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration
|
||||
#include "js/friend/WindowProxy.h" // js::IsWindow, js::IsWindowProxy, js::ToWindowIfWindowProxy
|
||||
#include "js/friend/XrayJitInfo.h" // js::jit::GetXrayJitInfo, JS::XrayJitInfo
|
||||
#include "js/RegExpFlags.h" // JS::RegExpFlags
|
||||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "js/Wrapper.h"
|
||||
#include "proxy/DOMProxy.h" // js::GetDOMProxyHandlerFamily
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "vm/Iteration.h"
|
||||
#include "vm/PlainObject.h" // js::PlainObject
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/ThrowMsgKind.h" // ThrowCondition
|
||||
#include "wasm/TypedObject.h"
|
||||
|
@ -375,6 +377,7 @@ AttachDecision GetPropIRGenerator::tryAttachStub() {
|
|||
TRY_ATTACH(tryAttachTypedArray(obj, objId, id));
|
||||
TRY_ATTACH(tryAttachDataView(obj, objId, id));
|
||||
TRY_ATTACH(tryAttachArrayBufferMaybeShared(obj, objId, id));
|
||||
TRY_ATTACH(tryAttachRegExp(obj, objId, id));
|
||||
TRY_ATTACH(tryAttachNative(obj, objId, id, receiverId));
|
||||
TRY_ATTACH(tryAttachModuleNamespace(obj, objId, id));
|
||||
TRY_ATTACH(tryAttachWindowProxy(obj, objId, id));
|
||||
|
@ -1950,6 +1953,48 @@ AttachDecision GetPropIRGenerator::tryAttachArrayBufferMaybeShared(
|
|||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision GetPropIRGenerator::tryAttachRegExp(HandleObject obj,
|
||||
ObjOperandId objId,
|
||||
HandleId id) {
|
||||
if (!obj->is<RegExpObject>()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
if (mode_ != ICState::Mode::Specialized) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Receiver should be the object.
|
||||
if (isSuper()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability type =
|
||||
CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_);
|
||||
if (type != CanAttachNativeGetter) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
auto& fun = shape->getterValue().toObject().as<JSFunction>();
|
||||
JS::RegExpFlags flags = JS::RegExpFlag::NoFlags;
|
||||
if (!RegExpObject::isOriginalFlagGetter(fun.native(), &flags)) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
// Emit all the normal guards for calling this native, but specialize
|
||||
// callNativeGetterResult.
|
||||
EmitCallGetterResultGuards(writer, obj, holder, shape, objId, mode_);
|
||||
|
||||
writer.regExpFlagResult(objId, flags.value());
|
||||
writer.returnFromIC();
|
||||
|
||||
trackAttached("RegExpFlag");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision GetPropIRGenerator::tryAttachFunction(HandleObject obj,
|
||||
ObjOperandId objId,
|
||||
HandleId id) {
|
||||
|
|
|
@ -1289,6 +1289,8 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator {
|
|||
AttachDecision tryAttachArrayBufferMaybeShared(HandleObject obj,
|
||||
ObjOperandId objId,
|
||||
HandleId id);
|
||||
AttachDecision tryAttachRegExp(HandleObject obj, ObjOperandId objId,
|
||||
HandleId id);
|
||||
AttachDecision tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId,
|
||||
HandleId id);
|
||||
AttachDecision tryAttachWindowProxy(HandleObject obj, ObjOperandId objId,
|
||||
|
|
|
@ -7444,6 +7444,30 @@ bool CacheIRCompiler::emitCallRegExpTesterResult(ObjOperandId regexpId,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitRegExpFlagResult(ObjOperandId regexpId,
|
||||
int32_t flagsMask) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoOutputRegister output(*this);
|
||||
Register regexp = allocator.useRegister(masm, regexpId);
|
||||
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
|
||||
|
||||
Address flagsAddr(
|
||||
regexp, NativeObject::getFixedSlotOffset(RegExpObject::flagsSlot()));
|
||||
masm.unboxInt32(flagsAddr, scratch);
|
||||
|
||||
Label ifFalse, done;
|
||||
masm.branchTest32(Assembler::Zero, scratch, Imm32(flagsMask), &ifFalse);
|
||||
masm.moveValue(BooleanValue(true), output.valueReg());
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&ifFalse);
|
||||
masm.moveValue(BooleanValue(false), output.valueReg());
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitCallSubstringKernelResult(StringOperandId strId,
|
||||
Int32OperandId beginId,
|
||||
Int32OperandId lengthId) {
|
||||
|
|
|
@ -308,6 +308,14 @@
|
|||
input: StringId
|
||||
lastIndex: Int32Id
|
||||
|
||||
- name: RegExpFlagResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 2
|
||||
args:
|
||||
regexp: ObjId
|
||||
flagsMask: Int32Imm
|
||||
|
||||
- name: CallSubstringKernelResult
|
||||
shared: true
|
||||
transpile: true
|
||||
|
|
|
@ -214,6 +214,8 @@ class MOZ_RAII WarpCacheIRTranspiler : public WarpBuilderShared {
|
|||
|
||||
MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
|
||||
|
||||
[[nodiscard]] MInstruction* convertToBoolean(MDefinition* input);
|
||||
|
||||
bool emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind kind,
|
||||
ObjOperandId objId, uint32_t offsetOffset,
|
||||
ValOperandId rhsId, uint32_t newShapeOffset);
|
||||
|
@ -3179,6 +3181,36 @@ bool WarpCacheIRTranspiler::emitCallRegExpTesterResult(
|
|||
return resumeAfter(tester);
|
||||
}
|
||||
|
||||
MInstruction* WarpCacheIRTranspiler::convertToBoolean(MDefinition* input) {
|
||||
// Convert to bool with the '!!' idiom.
|
||||
auto* resultInverted = MNot::New(alloc(), input);
|
||||
add(resultInverted);
|
||||
auto* result = MNot::New(alloc(), resultInverted);
|
||||
add(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitRegExpFlagResult(ObjOperandId regexpId,
|
||||
int32_t flagsMask) {
|
||||
MDefinition* regexp = getOperand(regexpId);
|
||||
|
||||
auto* flags = MLoadFixedSlot::New(alloc(), regexp, RegExpObject::flagsSlot());
|
||||
flags->setResultType(MIRType::Int32);
|
||||
add(flags);
|
||||
|
||||
auto* mask = MConstant::New(alloc(), Int32Value(flagsMask));
|
||||
add(mask);
|
||||
|
||||
auto* maskedFlag = MBitAnd::New(alloc(), flags, mask, MIRType::Int32);
|
||||
add(maskedFlag);
|
||||
|
||||
auto* result = convertToBoolean(maskedFlag);
|
||||
|
||||
pushResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WarpCacheIRTranspiler::emitCallSubstringKernelResult(
|
||||
StringOperandId strId, Int32OperandId beginId, Int32OperandId lengthId) {
|
||||
MDefinition* str = getOperand(strId);
|
||||
|
@ -3853,11 +3885,7 @@ bool WarpCacheIRTranspiler::emitBigIntAsUintNResult(Int32OperandId bitsId,
|
|||
bool WarpCacheIRTranspiler::emitLoadValueTruthyResult(ValOperandId inputId) {
|
||||
MDefinition* input = getOperand(inputId);
|
||||
|
||||
// Convert to bool with the '!!' idiom.
|
||||
auto* resultInverted = MNot::New(alloc(), input);
|
||||
add(resultInverted);
|
||||
auto* result = MNot::New(alloc(), resultInverted);
|
||||
add(result);
|
||||
auto* result = convertToBoolean(input);
|
||||
|
||||
pushResult(result);
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче