зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1332946 - CacheIR: IC for function.length. r=jandem
This commit is contained in:
Родитель
397131ee0d
Коммит
4d206d61cf
|
@ -0,0 +1,48 @@
|
|||
function interpreted() {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var f = function () {};
|
||||
assertEq(f.length, 0);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var f = function (a, b) {};
|
||||
assertEq(f.length, 2);
|
||||
}
|
||||
}
|
||||
|
||||
function bound() {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var f = (function () {}).bind({});
|
||||
assertEq(f.length, 0);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 50; i++) {
|
||||
var f = (function (a, b) {}).bind({});
|
||||
assertEq(f.length, 2);
|
||||
}
|
||||
}
|
||||
|
||||
function native() {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
// Use the interpreted function for getting the IC generated in the first place.
|
||||
var f = function (a) {};
|
||||
|
||||
if (i == 15) {
|
||||
f = Math.sin;
|
||||
} else if (i == 20) {
|
||||
f = Math.cos;
|
||||
} else if (i == 25) {
|
||||
f = Math.ceil;
|
||||
} else if (i == 30) {
|
||||
f = Math.tan;
|
||||
} else if (i == 35) {
|
||||
f = Math.tanh;
|
||||
}
|
||||
|
||||
assertEq(f.length, 1);
|
||||
}
|
||||
}
|
||||
|
||||
interpreted();
|
||||
bound();
|
||||
native();
|
|
@ -149,6 +149,8 @@ GetPropIRGenerator::tryAttachStub()
|
|||
return true;
|
||||
if (tryAttachWindowProxy(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachFunction(obj, objId, id))
|
||||
return true;
|
||||
if (tryAttachProxy(obj, objId, id))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -911,6 +913,42 @@ GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
// Function properties are lazily resolved so they might not be defined yet.
|
||||
// And we might end up in a situation where we always have a fresh function
|
||||
// object during the IC generation.
|
||||
if (!obj->is<JSFunction>())
|
||||
return false;
|
||||
|
||||
JSObject* holder = nullptr;
|
||||
PropertyResult prop;
|
||||
// This property exists already, don't attach the stub.
|
||||
if (LookupPropertyPure(cx_, obj, id, &holder, &prop))
|
||||
return false;
|
||||
|
||||
JSFunction* fun = &obj->as<JSFunction>();
|
||||
|
||||
if (JSID_IS_ATOM(id, cx_->names().length)) {
|
||||
// length was probably deleted from the function.
|
||||
if (fun->hasResolvedLength())
|
||||
return false;
|
||||
|
||||
// Lazy functions don't store the length.
|
||||
if (fun->isInterpretedLazy())
|
||||
return false;
|
||||
|
||||
maybeEmitIdGuard(id);
|
||||
writer.guardClass(objId, GuardClassKind::JSFunction);
|
||||
writer.loadFunctionLengthResult(objId);
|
||||
writer.returnFromIC();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id)
|
||||
{
|
||||
|
|
|
@ -189,6 +189,7 @@ enum class CacheKind : uint8_t
|
|||
_(LoadUnboxedArrayLengthResult) \
|
||||
_(LoadArgumentsObjectArgResult) \
|
||||
_(LoadArgumentsObjectLengthResult) \
|
||||
_(LoadFunctionLengthResult) \
|
||||
_(LoadStringCharResult) \
|
||||
_(LoadStringLengthResult) \
|
||||
_(LoadFrameCalleeResult) \
|
||||
|
@ -280,6 +281,7 @@ enum class GuardClassKind : uint8_t
|
|||
MappedArguments,
|
||||
UnmappedArguments,
|
||||
WindowProxy,
|
||||
JSFunction,
|
||||
};
|
||||
|
||||
// Class to record CacheIR + some additional metadata for code generation.
|
||||
|
@ -628,6 +630,12 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
void loadUnboxedArrayLengthResult(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj);
|
||||
}
|
||||
void loadArgumentsObjectLengthResult(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
|
||||
}
|
||||
void loadFunctionLengthResult(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::LoadFunctionLengthResult, obj);
|
||||
}
|
||||
void loadArgumentsObjectArgResult(ObjOperandId obj, Int32OperandId index) {
|
||||
writeOpWithOperandId(CacheOp::LoadArgumentsObjectArgResult, obj);
|
||||
writeOperandId(index);
|
||||
|
@ -652,9 +660,6 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
|
|||
buffer_.writeByte(uint32_t(layout));
|
||||
buffer_.writeByte(uint32_t(elementType));
|
||||
}
|
||||
void loadArgumentsObjectLengthResult(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
|
||||
}
|
||||
void loadStringLengthResult(StringOperandId str) {
|
||||
writeOpWithOperandId(CacheOp::LoadStringLengthResult, str);
|
||||
}
|
||||
|
@ -804,6 +809,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
|
|||
bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
||||
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId, HandleId id);
|
||||
|
|
|
@ -1228,6 +1228,9 @@ CacheIRCompiler::emitGuardClass()
|
|||
case GuardClassKind::WindowProxy:
|
||||
clasp = cx_->maybeWindowProxyClass();
|
||||
break;
|
||||
case GuardClassKind::JSFunction:
|
||||
clasp = &JSFunction::class_;
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(clasp);
|
||||
|
@ -1514,6 +1517,55 @@ CacheIRCompiler::emitLoadArgumentsObjectLengthResult()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitLoadFunctionLengthResult()
|
||||
{
|
||||
AutoOutputRegister output(*this);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
// Get the JSFunction flags.
|
||||
masm.load16ZeroExtend(Address(obj, JSFunction::offsetOfFlags()), scratch);
|
||||
|
||||
// Functions with lazy scripts don't store their length.
|
||||
// If the length was resolved before the length property might be shadowed.
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
scratch,
|
||||
Imm32(JSFunction::INTERPRETED_LAZY |
|
||||
JSFunction::RESOLVED_LENGTH),
|
||||
failure->label());
|
||||
|
||||
Label boundFunction;
|
||||
masm.branchTest32(Assembler::NonZero, scratch, Imm32(JSFunction::BOUND_FUN), &boundFunction);
|
||||
Label interpreted;
|
||||
masm.branchTest32(Assembler::NonZero, scratch, Imm32(JSFunction::INTERPRETED), &interpreted);
|
||||
|
||||
// Load the length of the native function.
|
||||
masm.load16ZeroExtend(Address(obj, JSFunction::offsetOfNargs()), scratch);
|
||||
Label done;
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&boundFunction);
|
||||
// Bound functions might have a non-int32 length.
|
||||
Address boundLength(obj, FunctionExtended::offsetOfExtendedSlot(BOUND_FUN_LENGTH_SLOT));
|
||||
masm.branchTestInt32(Assembler::NotEqual, boundLength, failure->label());
|
||||
masm.unboxInt32(boundLength, scratch);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&interpreted);
|
||||
// Load the length from the function's script.
|
||||
masm.loadPtr(Address(obj, JSFunction::offsetOfNativeOrScript()), scratch);
|
||||
masm.load16ZeroExtend(Address(scratch, JSScript::offsetOfFunLength()), scratch);
|
||||
|
||||
masm.bind(&done);
|
||||
EmitStoreResult(masm, scratch, JSVAL_TYPE_INT32, output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheIRCompiler::emitLoadStringLengthResult()
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace jit {
|
|||
_(LoadInt32ArrayLengthResult) \
|
||||
_(LoadUnboxedArrayLengthResult) \
|
||||
_(LoadArgumentsObjectLengthResult) \
|
||||
_(LoadFunctionLengthResult) \
|
||||
_(LoadStringLengthResult) \
|
||||
_(LoadStringCharResult) \
|
||||
_(LoadArgumentsObjectArgResult) \
|
||||
|
|
|
@ -1171,6 +1171,10 @@ class JSScript : public js::gc::TenuredCell
|
|||
return funLength_;
|
||||
}
|
||||
|
||||
static size_t offsetOfFunLength() {
|
||||
return offsetof(JSScript, funLength_);
|
||||
}
|
||||
|
||||
size_t sourceStart() const {
|
||||
return sourceStart_;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче