mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
parent
444483bf81
commit
5bf58e6044
14 changed files with 189 additions and 43 deletions
|
|
@ -1381,6 +1381,26 @@ BaselineCompiler::emit_JSOP_CHECKISOBJ()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
|
||||
static const VMFunction CheckIsCallableInfo =
|
||||
FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_CHECKISCALLABLE()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(Imm32(GET_UINT8(pc)));
|
||||
pushArg(R0);
|
||||
if (!callVM(CheckIsCallableInfo))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowUninitializedThisFn)(JSContext*, BaselineFrame* frame);
|
||||
static const VMFunction ThrowUninitializedThisInfo =
|
||||
FunctionInfo<ThrowUninitializedThisFn>(BaselineThrowUninitializedThis,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ namespace jit {
|
|||
_(JSOP_FUNCTIONTHIS) \
|
||||
_(JSOP_GLOBALTHIS) \
|
||||
_(JSOP_CHECKISOBJ) \
|
||||
_(JSOP_CHECKISCALLABLE) \
|
||||
_(JSOP_CHECKTHIS) \
|
||||
_(JSOP_CHECKRETURN) \
|
||||
_(JSOP_NEWTARGET) \
|
||||
|
|
|
|||
|
|
@ -11326,25 +11326,35 @@ class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
|
|||
}
|
||||
};
|
||||
|
||||
template <CodeGenerator::CallableOrConstructor mode>
|
||||
void
|
||||
CodeGenerator::visitIsCallable(LIsCallable* ins)
|
||||
CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
|
||||
{
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
|
||||
Label notFunction, hasCOps, done;
|
||||
masm.loadObjClass(object, output);
|
||||
|
||||
// Just skim proxies off. Their notion of isCallable() is more complicated.
|
||||
masm.branchTestClassIsProxy(true, output, ool->entry());
|
||||
// Just skim proxies off. Their notion of isCallable()/isConstructor() is
|
||||
// more complicated.
|
||||
masm.branchTestClassIsProxy(true, output, failure);
|
||||
|
||||
// An object is callable iff:
|
||||
// is<JSFunction>() || (getClass()->cOps && getClass()->cOps->call).
|
||||
// An object is constructor iff:
|
||||
// ((is<JSFunction>() && as<JSFunction>().isConstructor) ||
|
||||
// (getClass()->cOps && getClass()->cOps->construct)).
|
||||
masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function);
|
||||
masm.move32(Imm32(1), output);
|
||||
if (mode == Callable) {
|
||||
masm.move32(Imm32(1), output);
|
||||
} else {
|
||||
Label notConstructor;
|
||||
masm.load16ZeroExtend(Address(object, JSFunction::offsetOfFlags()), output);
|
||||
masm.and32(Imm32(JSFunction::CONSTRUCTOR), output);
|
||||
masm.branchTest32(Assembler::Zero, output, output, ¬Constructor);
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Constructor);
|
||||
masm.move32(Imm32(0), output);
|
||||
}
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(¬Function);
|
||||
|
|
@ -11355,10 +11365,26 @@ CodeGenerator::visitIsCallable(LIsCallable* ins)
|
|||
|
||||
masm.bind(&hasCOps);
|
||||
masm.loadPtr(Address(output, offsetof(js::Class, cOps)), output);
|
||||
masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::ClassOps, call)),
|
||||
size_t opsOffset = mode == Callable
|
||||
? offsetof(js::ClassOps, call)
|
||||
: offsetof(js::ClassOps, construct);
|
||||
masm.cmpPtrSet(Assembler::NonZero, Address(output, opsOffset),
|
||||
ImmPtr(nullptr), output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitIsCallable(LIsCallable* ins)
|
||||
{
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
|
||||
emitIsCallableOrConstructor<Callable>(object, output, ool->entry());
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
|
|
@ -11378,6 +11404,36 @@ CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable* ool)
|
|||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
|
||||
static const VMFunction CheckIsCallableInfo =
|
||||
FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
|
||||
|
||||
void
|
||||
CodeGenerator::visitCheckIsCallable(LCheckIsCallable* ins)
|
||||
{
|
||||
ValueOperand checkValue = ToValue(ins, LCheckIsCallable::CheckValue);
|
||||
Register temp = ToRegister(ins->temp());
|
||||
|
||||
// OOL code is used in the following 2 cases:
|
||||
// * checkValue is not callable
|
||||
// * checkValue is proxy and it's unknown whether it's callable or not
|
||||
// CheckIsCallable checks if passed value is callable, regardless of the
|
||||
// cases above. IsCallable operation is not observable and checking it
|
||||
// again doesn't matter.
|
||||
OutOfLineCode* ool = oolCallVM(CheckIsCallableInfo, ins,
|
||||
ArgList(checkValue, Imm32(ins->mir()->checkKind())),
|
||||
StoreNothing());
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, checkValue, ool->entry());
|
||||
|
||||
Register object = masm.extractObject(checkValue, temp);
|
||||
emitIsCallableOrConstructor<Callable>(object, temp, ool->entry());
|
||||
|
||||
masm.branchTest32(Assembler::Zero, temp, temp, ool->entry());
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
class OutOfLineIsConstructor : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LIsConstructor* ins_;
|
||||
|
|
@ -11404,37 +11460,8 @@ CodeGenerator::visitIsConstructor(LIsConstructor* ins)
|
|||
OutOfLineIsConstructor* ool = new(alloc()) OutOfLineIsConstructor(ins);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
|
||||
Label notFunction, notConstructor, hasCOps, done;
|
||||
masm.loadObjClass(object, output);
|
||||
emitIsCallableOrConstructor<Constructor>(object, output, ool->entry());
|
||||
|
||||
// Just skim proxies off. Their notion of isConstructor() is more complicated.
|
||||
masm.branchTestClassIsProxy(true, output, ool->entry());
|
||||
|
||||
// An object is constructor iff
|
||||
// ((is<JSFunction>() && as<JSFunction>().isConstructor) ||
|
||||
// (getClass()->cOps && getClass()->cOps->construct)).
|
||||
masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function);
|
||||
masm.load16ZeroExtend(Address(object, JSFunction::offsetOfFlags()), output);
|
||||
masm.and32(Imm32(JSFunction::CONSTRUCTOR), output);
|
||||
masm.branchTest32(Assembler::Zero, output, output, ¬Constructor);
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Constructor);
|
||||
masm.move32(Imm32(0), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(¬Function);
|
||||
masm.branchPtr(Assembler::NonZero, Address(output, offsetof(js::Class, cOps)),
|
||||
ImmPtr(nullptr), &hasCOps);
|
||||
masm.move32(Imm32(0), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&hasCOps);
|
||||
masm.loadPtr(Address(output, offsetof(js::Class, cOps)), output);
|
||||
masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::ClassOps, construct)),
|
||||
ImmPtr(nullptr), output);
|
||||
|
||||
masm.bind(&done);
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,6 +364,12 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitCallDOMNative(LCallDOMNative* lir);
|
||||
void visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir);
|
||||
void visitCallBindVar(LCallBindVar* lir);
|
||||
enum CallableOrConstructor {
|
||||
Callable,
|
||||
Constructor
|
||||
};
|
||||
template <CallableOrConstructor mode>
|
||||
void emitIsCallableOrConstructor(Register object, Register output, Label* failure);
|
||||
void visitIsCallable(LIsCallable* lir);
|
||||
void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
|
||||
void visitIsConstructor(LIsConstructor* lir);
|
||||
|
|
@ -384,6 +390,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitArrowNewTarget(LArrowNewTarget* ins);
|
||||
void visitCheckReturn(LCheckReturn* ins);
|
||||
void visitCheckIsObj(LCheckIsObj* ins);
|
||||
void visitCheckIsCallable(LCheckIsCallable* ins);
|
||||
void visitCheckObjCoercible(LCheckObjCoercible* ins);
|
||||
void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins);
|
||||
void visitNaNToZero(LNaNToZero* ins);
|
||||
|
|
|
|||
|
|
@ -2183,6 +2183,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_CHECKISOBJ:
|
||||
return jsop_checkisobj(GET_UINT8(pc));
|
||||
|
||||
case JSOP_CHECKISCALLABLE:
|
||||
return jsop_checkiscallable(GET_UINT8(pc));
|
||||
|
||||
case JSOP_CHECKOBJCOERCIBLE:
|
||||
return jsop_checkobjcoercible();
|
||||
|
||||
|
|
@ -10899,6 +10902,15 @@ IonBuilder::jsop_checkisobj(uint8_t kind)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_checkiscallable(uint8_t kind)
|
||||
{
|
||||
MCheckIsCallable* check = MCheckIsCallable::New(alloc(), current->pop(), kind);
|
||||
current->add(check);
|
||||
current->push(check);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_checkobjcoercible()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -783,6 +783,7 @@ class IonBuilder
|
|||
MOZ_MUST_USE bool jsop_debugger();
|
||||
MOZ_MUST_USE bool jsop_newtarget();
|
||||
MOZ_MUST_USE bool jsop_checkisobj(uint8_t kind);
|
||||
MOZ_MUST_USE bool jsop_checkiscallable(uint8_t kind);
|
||||
MOZ_MUST_USE bool jsop_checkobjcoercible();
|
||||
MOZ_MUST_USE bool jsop_pushcallobj();
|
||||
|
||||
|
|
|
|||
|
|
@ -4688,6 +4688,19 @@ LIRGenerator::visitCheckIsObj(MCheckIsObj* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCheckIsCallable(MCheckIsCallable* ins)
|
||||
{
|
||||
MDefinition* checkVal = ins->checkValue();
|
||||
MOZ_ASSERT(checkVal->type() == MIRType::Value);
|
||||
|
||||
LCheckIsCallable* lir = new(alloc()) LCheckIsCallable(useBox(checkVal),
|
||||
temp());
|
||||
redefine(ins, checkVal);
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -329,6 +329,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
|
||||
void visitCheckReturn(MCheckReturn* ins);
|
||||
void visitCheckIsObj(MCheckIsObj* ins);
|
||||
void visitCheckIsCallable(MCheckIsCallable* ins);
|
||||
void visitCheckObjCoercible(MCheckObjCoercible* ins);
|
||||
void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13455,8 +13455,9 @@ class MCheckIsObj
|
|||
{
|
||||
uint8_t checkKind_;
|
||||
|
||||
explicit MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
|
||||
: MUnaryInstruction(toCheck), checkKind_(checkKind)
|
||||
MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
|
||||
: MUnaryInstruction(toCheck),
|
||||
checkKind_(checkKind)
|
||||
{
|
||||
setResultType(MIRType::Value);
|
||||
setResultTypeSet(toCheck->resultTypeSet());
|
||||
|
|
@ -13475,6 +13476,33 @@ class MCheckIsObj
|
|||
}
|
||||
};
|
||||
|
||||
class MCheckIsCallable
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
{
|
||||
uint8_t checkKind_;
|
||||
|
||||
MCheckIsCallable(MDefinition* toCheck, uint8_t checkKind)
|
||||
: MUnaryInstruction(toCheck),
|
||||
checkKind_(checkKind)
|
||||
{
|
||||
setResultType(MIRType::Value);
|
||||
setResultTypeSet(toCheck->resultTypeSet());
|
||||
setGuard();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CheckIsCallable)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, checkValue))
|
||||
|
||||
uint8_t checkKind() const { return checkKind_; }
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MCheckObjCoercible
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ namespace jit {
|
|||
_(ArrowNewTarget) \
|
||||
_(CheckReturn) \
|
||||
_(CheckIsObj) \
|
||||
_(CheckIsCallable) \
|
||||
_(CheckObjCoercible) \
|
||||
_(DebugCheckSelfHosted) \
|
||||
_(AsmJSNeg) \
|
||||
|
|
|
|||
|
|
@ -1349,5 +1349,14 @@ BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue
|
|||
return GetFunctionThis(cx, frame, res);
|
||||
}
|
||||
|
||||
bool
|
||||
CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind)
|
||||
{
|
||||
if (!IsCallable(v))
|
||||
return ThrowCheckIsCallable(cx, kind);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
@ -802,6 +803,9 @@ ThrowObjectCoercible(JSContext* cx, HandleValue v);
|
|||
MOZ_MUST_USE bool
|
||||
BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame, MutableHandleValue res);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
|||
|
|
@ -8893,6 +8893,27 @@ class LCheckIsObj : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LCheckIsCallable : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CheckIsCallable)
|
||||
|
||||
static const size_t CheckValue = 0;
|
||||
|
||||
LCheckIsCallable(const LBoxAllocation& value, const LDefinition& temp) {
|
||||
setBoxOperand(CheckValue, value);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
|
||||
MCheckIsCallable* mir() const {
|
||||
return mir_->toCheckIsCallable();
|
||||
}
|
||||
};
|
||||
|
||||
class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -402,6 +402,7 @@
|
|||
_(ArrowNewTarget) \
|
||||
_(CheckReturn) \
|
||||
_(CheckIsObj) \
|
||||
_(CheckIsCallable) \
|
||||
_(CheckObjCoercible) \
|
||||
_(DebugCheckSelfHosted) \
|
||||
_(AsmJSLoadHeap) \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue