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:
André Bargull 2021-02-16 13:18:00 +00:00
Родитель 6b07227f3a
Коммит 156536c558
6 изменённых файлов: 173 добавлений и 5 удалений

Просмотреть файл

@ -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;