mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-28 18:17:29 +09:00
1344477 - Part 1: Add JSOP_CALL_IGNORES_RV for function call that ignores return value.
This commit is contained in:
parent
43c3ab5a0e
commit
417aa02122
22 changed files with 243 additions and 92 deletions
|
|
@ -128,7 +128,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
|
||||||
protected:
|
protected:
|
||||||
Value* argv_;
|
Value* argv_;
|
||||||
unsigned argc_;
|
unsigned argc_;
|
||||||
bool constructing_;
|
bool constructing_:1;
|
||||||
|
|
||||||
|
// True if the caller does not use the return value.
|
||||||
|
bool ignoresReturnValue_:1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CALLEE ACCESS
|
// CALLEE ACCESS
|
||||||
|
|
@ -164,6 +167,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ignoresReturnValue() const {
|
||||||
|
return ignoresReturnValue_;
|
||||||
|
}
|
||||||
|
|
||||||
MutableHandleValue newTarget() const {
|
MutableHandleValue newTarget() const {
|
||||||
MOZ_ASSERT(constructing_);
|
MOZ_ASSERT(constructing_);
|
||||||
return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
|
return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
|
||||||
|
|
@ -280,14 +287,17 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
|
friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
|
||||||
friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing);
|
friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing,
|
||||||
|
bool ignoresReturnValue);
|
||||||
|
|
||||||
static CallArgs create(unsigned argc, Value* argv, bool constructing) {
|
static CallArgs create(unsigned argc, Value* argv, bool constructing,
|
||||||
|
bool ignoresReturnValue = false) {
|
||||||
CallArgs args;
|
CallArgs args;
|
||||||
args.clearUsedRval();
|
args.clearUsedRval();
|
||||||
args.argv_ = argv;
|
args.argv_ = argv;
|
||||||
args.argc_ = argc;
|
args.argc_ = argc;
|
||||||
args.constructing_ = constructing;
|
args.constructing_ = constructing;
|
||||||
|
args.ignoresReturnValue_ = ignoresReturnValue;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (unsigned i = 0; i < argc; ++i)
|
for (unsigned i = 0; i < argc; ++i)
|
||||||
MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
|
MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
|
||||||
|
|
@ -314,9 +324,11 @@ CallArgsFromVp(unsigned argc, Value* vp)
|
||||||
// eventually move it to an internal header. Embedders should use
|
// eventually move it to an internal header. Embedders should use
|
||||||
// JS::CallArgsFromVp!
|
// JS::CallArgsFromVp!
|
||||||
MOZ_ALWAYS_INLINE CallArgs
|
MOZ_ALWAYS_INLINE CallArgs
|
||||||
CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false)
|
CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false,
|
||||||
|
bool ignoresReturnValue = false)
|
||||||
{
|
{
|
||||||
return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing);
|
return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing,
|
||||||
|
ignoresReturnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
|
||||||
|
|
@ -4603,7 +4603,7 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
|
||||||
// If the expression is a literal, suppress line number emission so
|
// If the expression is a literal, suppress line number emission so
|
||||||
// that debugging works more naturally.
|
// that debugging works more naturally.
|
||||||
if (caseValue) {
|
if (caseValue) {
|
||||||
if (!emitTree(caseValue,
|
if (!emitTree(caseValue, ValueUsage::WantValue,
|
||||||
caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
|
caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -6652,7 +6652,7 @@ BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line notes were updated by emitLexicalScope.
|
// Line notes were updated by emitLexicalScope.
|
||||||
return emitTree(body, emitLineNote);
|
return emitTree(body, ValueUsage::WantValue, emitLineNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
|
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
|
||||||
|
|
@ -6754,9 +6754,9 @@ BytecodeEmitter::emitRequireObjectCoercible()
|
||||||
return false;
|
return false;
|
||||||
if (!emit2(JSOP_PICK, 2)) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
|
if (!emit2(JSOP_PICK, 2)) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
|
||||||
return false;
|
return false;
|
||||||
if (!emitCall(JSOP_CALL, 1)) // VAL IGNORED
|
if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED
|
||||||
return false;
|
return false;
|
||||||
checkTypeSet(JSOP_CALL);
|
checkTypeSet(JSOP_CALL_IGNORES_RV);
|
||||||
|
|
||||||
if (!emit1(JSOP_POP)) // VAL
|
if (!emit1(JSOP_POP)) // VAL
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -7276,12 +7276,14 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
|
||||||
// scope, but we still need to emit code for the initializers.)
|
// scope, but we still need to emit code for the initializers.)
|
||||||
if (!updateSourceCoordNotes(init->pn_pos.begin))
|
if (!updateSourceCoordNotes(init->pn_pos.begin))
|
||||||
return false;
|
return false;
|
||||||
|
if (init->isForLoopDeclaration()) {
|
||||||
if (!emitTree(init))
|
if (!emitTree(init))
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
if (!init->isForLoopDeclaration()) {
|
|
||||||
// 'init' is an expression, not a declaration. emitTree left its
|
// 'init' is an expression, not a declaration. emitTree left its
|
||||||
// value on the stack.
|
// value on the stack.
|
||||||
|
if (!emitTree(init, ValueUsage::IgnoreValue))
|
||||||
|
return false;
|
||||||
if (!emit1(JSOP_POP))
|
if (!emit1(JSOP_POP))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -7363,7 +7365,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
|
||||||
|
|
||||||
if (!updateSourceCoordNotes(update->pn_pos.begin))
|
if (!updateSourceCoordNotes(update->pn_pos.begin))
|
||||||
return false;
|
return false;
|
||||||
if (!emitTree(update))
|
if (!emitTree(update, ValueUsage::IgnoreValue))
|
||||||
return false;
|
return false;
|
||||||
if (!emit1(JSOP_POP))
|
if (!emit1(JSOP_POP))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -8690,8 +8692,9 @@ BytecodeEmitter::emitStatement(ParseNode* pn)
|
||||||
|
|
||||||
if (useful) {
|
if (useful) {
|
||||||
JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
|
JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
|
||||||
|
ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
|
||||||
MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
|
MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
|
||||||
if (!emitTree(pn2))
|
if (!emitTree(pn2, valueUsage))
|
||||||
return false;
|
return false;
|
||||||
if (!emit1(op))
|
if (!emit1(op))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -9041,7 +9044,7 @@ BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitte
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||||
{
|
{
|
||||||
bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
|
bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
|
||||||
/*
|
/*
|
||||||
|
|
@ -9220,13 +9223,20 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spread) {
|
if (!spread) {
|
||||||
|
if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
|
||||||
|
if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
|
||||||
|
return false;
|
||||||
|
checkTypeSet(JSOP_CALL_IGNORES_RV);
|
||||||
|
} else {
|
||||||
if (!emitCall(pn->getOp(), argc, pn))
|
if (!emitCall(pn->getOp(), argc, pn))
|
||||||
return false;
|
return false;
|
||||||
|
checkTypeSet(pn->getOp());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!emit1(pn->getOp()))
|
if (!emit1(pn->getOp()))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
checkTypeSet(pn->getOp());
|
checkTypeSet(pn->getOp());
|
||||||
|
}
|
||||||
if (pn->isOp(JSOP_EVAL) ||
|
if (pn->isOp(JSOP_EVAL) ||
|
||||||
pn->isOp(JSOP_STRICTEVAL) ||
|
pn->isOp(JSOP_STRICTEVAL) ||
|
||||||
pn->isOp(JSOP_SPREADEVAL) ||
|
pn->isOp(JSOP_SPREADEVAL) ||
|
||||||
|
|
@ -9324,12 +9334,13 @@ BytecodeEmitter::emitLogical(ParseNode* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitSequenceExpr(ParseNode* pn)
|
BytecodeEmitter::emitSequenceExpr(ParseNode* pn,
|
||||||
|
ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||||
{
|
{
|
||||||
for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
|
for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
|
||||||
if (!updateSourceCoordNotes(child->pn_pos.begin))
|
if (!updateSourceCoordNotes(child->pn_pos.begin))
|
||||||
return false;
|
return false;
|
||||||
if (!emitTree(child))
|
if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
|
||||||
return false;
|
return false;
|
||||||
if (!child->pn_next)
|
if (!child->pn_next)
|
||||||
break;
|
break;
|
||||||
|
|
@ -9392,7 +9403,8 @@ BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
|
BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
|
||||||
|
ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||||
{
|
{
|
||||||
/* Emit the condition, then branch if false to the else part. */
|
/* Emit the condition, then branch if false to the else part. */
|
||||||
if (!emitTree(&conditional.condition()))
|
if (!emitTree(&conditional.condition()))
|
||||||
|
|
@ -9402,13 +9414,13 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
|
||||||
if (!ifThenElse.emitCond())
|
if (!ifThenElse.emitCond())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!emitTreeInBranch(&conditional.thenExpression()))
|
if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ifThenElse.emitElse())
|
if (!ifThenElse.emitElse())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!emitTreeInBranch(&conditional.elseExpression()))
|
if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ifThenElse.emitEnd())
|
if (!ifThenElse.emitEnd())
|
||||||
|
|
@ -10289,7 +10301,8 @@ BytecodeEmitter::emitClass(ParseNode* pn)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
|
||||||
|
EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(cx, return false);
|
JS_CHECK_RECURSION(cx, return false);
|
||||||
|
|
||||||
|
|
@ -10411,7 +10424,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PNK_COMMA:
|
case PNK_COMMA:
|
||||||
if (!emitSequenceExpr(pn))
|
if (!emitSequenceExpr(pn, valueUsage))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -10433,7 +10446,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PNK_CONDITIONAL:
|
case PNK_CONDITIONAL:
|
||||||
if (!emitConditionalExpression(pn->as<ConditionalExpression>()))
|
if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -10546,7 +10559,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
||||||
case PNK_CALL:
|
case PNK_CALL:
|
||||||
case PNK_GENEXP:
|
case PNK_GENEXP:
|
||||||
case PNK_SUPERCALL:
|
case PNK_SUPERCALL:
|
||||||
if (!emitCallOrNew(pn))
|
if (!emitCallOrNew(pn, valueUsage))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -10704,12 +10717,13 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitTreeInBranch(ParseNode* pn)
|
BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
|
||||||
|
ValueUsage valueUsage /* = ValueUsage::WantValue */)
|
||||||
{
|
{
|
||||||
// Code that may be conditionally executed always need their own TDZ
|
// Code that may be conditionally executed always need their own TDZ
|
||||||
// cache.
|
// cache.
|
||||||
TDZCheckCache tdzCache(this);
|
TDZCheckCache tdzCache(this);
|
||||||
return emitTree(pn);
|
return emitTree(pn, valueUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,11 @@ struct JumpList {
|
||||||
void patchAll(jsbytecode* code, JumpTarget target);
|
void patchAll(jsbytecode* code, JumpTarget target);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ValueUsage {
|
||||||
|
WantValue,
|
||||||
|
IgnoreValue
|
||||||
|
};
|
||||||
|
|
||||||
struct MOZ_STACK_CLASS BytecodeEmitter
|
struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
{
|
{
|
||||||
class TDZCheckCache;
|
class TDZCheckCache;
|
||||||
|
|
@ -434,10 +439,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
};
|
};
|
||||||
|
|
||||||
// Emit code for the tree rooted at pn.
|
// Emit code for the tree rooted at pn.
|
||||||
MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
|
MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
|
||||||
|
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
|
||||||
|
|
||||||
// Emit code for the tree rooted at pn with its own TDZ cache.
|
// Emit code for the tree rooted at pn with its own TDZ cache.
|
||||||
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn);
|
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
|
||||||
|
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||||
|
|
||||||
// Emit global, eval, or module code for tree rooted at body. Always
|
// Emit global, eval, or module code for tree rooted at body. Always
|
||||||
// encompasses the entire source.
|
// encompasses the entire source.
|
||||||
|
|
@ -724,16 +731,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn);
|
MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn);
|
MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitLogical(ParseNode* pn);
|
MOZ_MUST_USE bool emitLogical(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn);
|
MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn,
|
||||||
|
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||||
|
|
||||||
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
|
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional);
|
MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
|
||||||
|
ValueUsage valueUsage = ValueUsage::WantValue);
|
||||||
|
|
||||||
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
|
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
|
||||||
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
|
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn);
|
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
|
||||||
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
|
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
|
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
|
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
|
||||||
|
|
|
||||||
|
|
@ -3297,6 +3297,12 @@ BaselineCompiler::emit_JSOP_CALL()
|
||||||
return emitCall();
|
return emitCall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BaselineCompiler::emit_JSOP_CALL_IGNORES_RV()
|
||||||
|
{
|
||||||
|
return emitCall();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BaselineCompiler::emit_JSOP_CALLITER()
|
BaselineCompiler::emit_JSOP_CALLITER()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@ namespace jit {
|
||||||
_(JSOP_INITALIASEDLEXICAL) \
|
_(JSOP_INITALIASEDLEXICAL) \
|
||||||
_(JSOP_UNINITIALIZED) \
|
_(JSOP_UNINITIALIZED) \
|
||||||
_(JSOP_CALL) \
|
_(JSOP_CALL) \
|
||||||
|
_(JSOP_CALL_IGNORES_RV) \
|
||||||
_(JSOP_CALLITER) \
|
_(JSOP_CALLITER) \
|
||||||
_(JSOP_FUNCALL) \
|
_(JSOP_FUNCALL) \
|
||||||
_(JSOP_FUNAPPLY) \
|
_(JSOP_FUNAPPLY) \
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include "mozilla/SizePrintfMacros.h"
|
#include "mozilla/SizePrintfMacros.h"
|
||||||
#include "mozilla/TemplateLib.h"
|
#include "mozilla/TemplateLib.h"
|
||||||
|
|
||||||
|
#include "jsfriendapi.h"
|
||||||
|
#include "jsfun.h"
|
||||||
#include "jslibmath.h"
|
#include "jslibmath.h"
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
|
|
||||||
|
|
@ -5494,11 +5496,17 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||||
MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects());
|
MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ignoresReturnValue = false;
|
||||||
|
if (op == JSOP_CALL_IGNORES_RV && fun->isNative()) {
|
||||||
|
const JSJitInfo* jitInfo = fun->jitInfo();
|
||||||
|
ignoresReturnValue = jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative;
|
||||||
|
}
|
||||||
|
|
||||||
JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
|
JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
|
||||||
fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no");
|
fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no");
|
||||||
ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
|
ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
|
||||||
fun, templateObject, constructing, isSpread,
|
fun, templateObject, constructing, ignoresReturnValue,
|
||||||
script->pcToOffset(pc));
|
isSpread, script->pcToOffset(pc));
|
||||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||||
if (!newStub)
|
if (!newStub)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -5601,12 +5609,14 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
||||||
|
|
||||||
MOZ_ASSERT(argc == GET_ARGC(pc));
|
MOZ_ASSERT(argc == GET_ARGC(pc));
|
||||||
bool constructing = (op == JSOP_NEW);
|
bool constructing = (op == JSOP_NEW);
|
||||||
|
bool ignoresReturnValue = (op == JSOP_CALL_IGNORES_RV);
|
||||||
|
|
||||||
// Ensure vp array is rooted - we may GC in here.
|
// Ensure vp array is rooted - we may GC in here.
|
||||||
size_t numValues = argc + 2 + constructing;
|
size_t numValues = argc + 2 + constructing;
|
||||||
AutoArrayRooter vpRoot(cx, numValues, vp);
|
AutoArrayRooter vpRoot(cx, numValues, vp);
|
||||||
|
|
||||||
CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing);
|
CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing,
|
||||||
|
ignoresReturnValue);
|
||||||
RootedValue callee(cx, vp[0]);
|
RootedValue callee(cx, vp[0]);
|
||||||
|
|
||||||
// Handle funapply with JSOP_ARGUMENTS
|
// Handle funapply with JSOP_ARGUMENTS
|
||||||
|
|
@ -5636,6 +5646,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(op == JSOP_CALL ||
|
MOZ_ASSERT(op == JSOP_CALL ||
|
||||||
|
op == JSOP_CALL_IGNORES_RV ||
|
||||||
op == JSOP_CALLITER ||
|
op == JSOP_CALLITER ||
|
||||||
op == JSOP_FUNCALL ||
|
op == JSOP_FUNCALL ||
|
||||||
op == JSOP_FUNAPPLY ||
|
op == JSOP_FUNAPPLY ||
|
||||||
|
|
@ -6686,7 +6697,12 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
|
||||||
// stub and use that instead of the original one.
|
// stub and use that instead of the original one.
|
||||||
masm.callWithABI(Address(ICStubReg, ICCall_Native::offsetOfNative()));
|
masm.callWithABI(Address(ICStubReg, ICCall_Native::offsetOfNative()));
|
||||||
#else
|
#else
|
||||||
|
if (ignoresReturnValue_) {
|
||||||
|
masm.loadPtr(Address(callee, JSFunction::offsetOfJitInfo()), callee);
|
||||||
|
masm.callWithABI(Address(callee, JSJitInfo::offsetOfIgnoresReturnValueNative()));
|
||||||
|
} else {
|
||||||
masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
|
masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Test for failure.
|
// Test for failure.
|
||||||
|
|
|
||||||
|
|
@ -2277,6 +2277,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter
|
||||||
|
|
||||||
// Call
|
// Call
|
||||||
// JSOP_CALL
|
// JSOP_CALL
|
||||||
|
// JSOP_CALL_IGNORES_RV
|
||||||
// JSOP_FUNAPPLY
|
// JSOP_FUNAPPLY
|
||||||
// JSOP_FUNCALL
|
// JSOP_FUNCALL
|
||||||
// JSOP_NEW
|
// JSOP_NEW
|
||||||
|
|
@ -2547,6 +2548,7 @@ class ICCall_Native : public ICMonitoredStub
|
||||||
protected:
|
protected:
|
||||||
ICStub* firstMonitorStub_;
|
ICStub* firstMonitorStub_;
|
||||||
bool isConstructing_;
|
bool isConstructing_;
|
||||||
|
bool ignoresReturnValue_;
|
||||||
bool isSpread_;
|
bool isSpread_;
|
||||||
RootedFunction callee_;
|
RootedFunction callee_;
|
||||||
RootedObject templateObject_;
|
RootedObject templateObject_;
|
||||||
|
|
@ -2556,17 +2558,19 @@ class ICCall_Native : public ICMonitoredStub
|
||||||
virtual int32_t getKey() const {
|
virtual int32_t getKey() const {
|
||||||
return static_cast<int32_t>(engine_) |
|
return static_cast<int32_t>(engine_) |
|
||||||
(static_cast<int32_t>(kind) << 1) |
|
(static_cast<int32_t>(kind) << 1) |
|
||||||
(static_cast<int32_t>(isConstructing_) << 17) |
|
(static_cast<int32_t>(isSpread_) << 17) |
|
||||||
(static_cast<int32_t>(isSpread_) << 18);
|
(static_cast<int32_t>(isConstructing_) << 18) |
|
||||||
|
(static_cast<int32_t>(ignoresReturnValue_) << 19);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Compiler(JSContext* cx, ICStub* firstMonitorStub,
|
Compiler(JSContext* cx, ICStub* firstMonitorStub,
|
||||||
HandleFunction callee, HandleObject templateObject,
|
HandleFunction callee, HandleObject templateObject,
|
||||||
bool isConstructing, bool isSpread, uint32_t pcOffset)
|
bool isConstructing, bool ignoresReturnValue, bool isSpread, uint32_t pcOffset)
|
||||||
: ICCallStubCompiler(cx, ICStub::Call_Native),
|
: ICCallStubCompiler(cx, ICStub::Call_Native),
|
||||||
firstMonitorStub_(firstMonitorStub),
|
firstMonitorStub_(firstMonitorStub),
|
||||||
isConstructing_(isConstructing),
|
isConstructing_(isConstructing),
|
||||||
|
ignoresReturnValue_(ignoresReturnValue),
|
||||||
isSpread_(isSpread),
|
isSpread_(isSpread),
|
||||||
callee_(cx, callee),
|
callee_(cx, callee),
|
||||||
templateObject_(cx, templateObject),
|
templateObject_(cx, templateObject),
|
||||||
|
|
|
||||||
|
|
@ -3688,7 +3688,13 @@ CodeGenerator::visitCallNative(LCallNative* call)
|
||||||
masm.passABIArg(argContextReg);
|
masm.passABIArg(argContextReg);
|
||||||
masm.passABIArg(argUintNReg);
|
masm.passABIArg(argUintNReg);
|
||||||
masm.passABIArg(argVpReg);
|
masm.passABIArg(argVpReg);
|
||||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()));
|
JSNative native = target->native();
|
||||||
|
if (call->ignoresReturnValue()) {
|
||||||
|
const JSJitInfo* jitInfo = target->jitInfo();
|
||||||
|
if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
|
||||||
|
native = jitInfo->ignoresReturnValueMethod;
|
||||||
|
}
|
||||||
|
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native));
|
||||||
|
|
||||||
emitTracelogStopEvent(TraceLogger_Call);
|
emitTracelogStopEvent(TraceLogger_Call);
|
||||||
|
|
||||||
|
|
@ -3845,13 +3851,15 @@ CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
|
||||||
callVM(GetIntrinsicValueInfo, lir);
|
callVM(GetIntrinsicValueInfo, lir);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue);
|
typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*,
|
||||||
|
MutableHandleValue);
|
||||||
static const VMFunction InvokeFunctionInfo =
|
static const VMFunction InvokeFunctionInfo =
|
||||||
FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction");
|
FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction");
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
|
CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
|
||||||
bool constructing, uint32_t argc, uint32_t unusedStack)
|
bool constructing, bool ignoresReturnValue,
|
||||||
|
uint32_t argc, uint32_t unusedStack)
|
||||||
{
|
{
|
||||||
// Nestle %esp up to the argument vector.
|
// Nestle %esp up to the argument vector.
|
||||||
// Each path must account for framePushed_ separately, for callVM to be valid.
|
// Each path must account for framePushed_ separately, for callVM to be valid.
|
||||||
|
|
@ -3859,6 +3867,7 @@ CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
|
||||||
|
|
||||||
pushArg(masm.getStackPointer()); // argv.
|
pushArg(masm.getStackPointer()); // argv.
|
||||||
pushArg(Imm32(argc)); // argc.
|
pushArg(Imm32(argc)); // argc.
|
||||||
|
pushArg(Imm32(ignoresReturnValue));
|
||||||
pushArg(Imm32(constructing)); // constructing.
|
pushArg(Imm32(constructing)); // constructing.
|
||||||
pushArg(calleereg); // JSFunction*.
|
pushArg(calleereg); // JSFunction*.
|
||||||
|
|
||||||
|
|
@ -3945,8 +3954,8 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call)
|
||||||
|
|
||||||
// Handle uncompiled or native functions.
|
// Handle uncompiled or native functions.
|
||||||
masm.bind(&invoke);
|
masm.bind(&invoke);
|
||||||
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(),
|
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
|
||||||
unusedStack);
|
call->numActualArgs(), unusedStack);
|
||||||
|
|
||||||
masm.bind(&end);
|
masm.bind(&end);
|
||||||
|
|
||||||
|
|
@ -4001,7 +4010,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call)
|
||||||
masm.checkStackAlignment();
|
masm.checkStackAlignment();
|
||||||
|
|
||||||
if (target->isClassConstructor() && !call->isConstructing()) {
|
if (target->isClassConstructor() && !call->isConstructing()) {
|
||||||
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack);
|
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
|
||||||
|
call->numActualArgs(), unusedStack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4045,7 +4055,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call)
|
||||||
if (call->isConstructing() && target->nargs() > call->numActualArgs())
|
if (call->isConstructing() && target->nargs() > call->numActualArgs())
|
||||||
emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
|
emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
|
||||||
else
|
else
|
||||||
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack);
|
emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
|
||||||
|
call->numActualArgs(), unusedStack);
|
||||||
|
|
||||||
masm.bind(&end);
|
masm.bind(&end);
|
||||||
|
|
||||||
|
|
@ -4072,6 +4083,7 @@ CodeGenerator::emitCallInvokeFunction(T* apply, Register extraStackSize)
|
||||||
|
|
||||||
pushArg(objreg); // argv.
|
pushArg(objreg); // argv.
|
||||||
pushArg(ToRegister(apply->getArgc())); // argc.
|
pushArg(ToRegister(apply->getArgc())); // argc.
|
||||||
|
pushArg(Imm32(false)); // ignoresReturnValue.
|
||||||
pushArg(Imm32(false)); // isConstrucing.
|
pushArg(Imm32(false)); // isConstrucing.
|
||||||
pushArg(ToRegister(apply->getFunction())); // JSFunction*.
|
pushArg(ToRegister(apply->getFunction())); // JSFunction*.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,8 +165,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||||
void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
|
void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
|
||||||
void visitCallNative(LCallNative* call);
|
void visitCallNative(LCallNative* call);
|
||||||
void emitCallInvokeFunction(LInstruction* call, Register callereg,
|
void emitCallInvokeFunction(LInstruction* call, Register callereg,
|
||||||
bool isConstructing, uint32_t argc,
|
bool isConstructing, bool ignoresReturnValue,
|
||||||
uint32_t unusedStack);
|
uint32_t argc, uint32_t unusedStack);
|
||||||
void visitCallGeneric(LCallGeneric* call);
|
void visitCallGeneric(LCallGeneric* call);
|
||||||
void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call,
|
void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call,
|
||||||
Register calleeReg,
|
Register calleeReg,
|
||||||
|
|
|
||||||
|
|
@ -1939,6 +1939,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||||
return jsop_funapply(GET_ARGC(pc));
|
return jsop_funapply(GET_ARGC(pc));
|
||||||
|
|
||||||
case JSOP_CALL:
|
case JSOP_CALL:
|
||||||
|
case JSOP_CALL_IGNORES_RV:
|
||||||
case JSOP_CALLITER:
|
case JSOP_CALLITER:
|
||||||
case JSOP_NEW:
|
case JSOP_NEW:
|
||||||
case JSOP_SUPERCALL:
|
case JSOP_SUPERCALL:
|
||||||
|
|
@ -1946,7 +1947,8 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||||
if (!outermostBuilder()->iterators_.append(current->peek(-1)))
|
if (!outermostBuilder()->iterators_.append(current->peek(-1)))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL);
|
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL,
|
||||||
|
(JSOp)*pc == JSOP_CALL_IGNORES_RV);
|
||||||
|
|
||||||
case JSOP_EVAL:
|
case JSOP_EVAL:
|
||||||
case JSOP_STRICTEVAL:
|
case JSOP_STRICTEVAL:
|
||||||
|
|
@ -5872,7 +5874,7 @@ IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasic
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create a new CallInfo to track modified state within this block.
|
// Create a new CallInfo to track modified state within this block.
|
||||||
CallInfo fallbackInfo(alloc(), callInfo.constructing());
|
CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
|
||||||
if (!fallbackInfo.init(callInfo))
|
if (!fallbackInfo.init(callInfo))
|
||||||
return false;
|
return false;
|
||||||
fallbackInfo.popFormals(fallbackBlock);
|
fallbackInfo.popFormals(fallbackBlock);
|
||||||
|
|
@ -5911,7 +5913,7 @@ IonBuilder::inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchB
|
||||||
MOZ_ASSERT(cache->idempotent());
|
MOZ_ASSERT(cache->idempotent());
|
||||||
|
|
||||||
// Create a new CallInfo to track modified state within the fallback path.
|
// Create a new CallInfo to track modified state within the fallback path.
|
||||||
CallInfo fallbackInfo(alloc(), callInfo.constructing());
|
CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
|
||||||
if (!fallbackInfo.init(callInfo))
|
if (!fallbackInfo.init(callInfo))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -6087,7 +6089,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec
|
||||||
inlineBlock->rewriteSlot(funIndex, funcDef);
|
inlineBlock->rewriteSlot(funIndex, funcDef);
|
||||||
|
|
||||||
// Create a new CallInfo to track modified state within the inline block.
|
// Create a new CallInfo to track modified state within the inline block.
|
||||||
CallInfo inlineInfo(alloc(), callInfo.constructing());
|
CallInfo inlineInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
|
||||||
if (!inlineInfo.init(callInfo))
|
if (!inlineInfo.init(callInfo))
|
||||||
return false;
|
return false;
|
||||||
inlineInfo.popFormals(inlineBlock);
|
inlineInfo.popFormals(inlineBlock);
|
||||||
|
|
@ -6536,7 +6538,8 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
||||||
TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||||
JSFunction* native = getSingleCallTarget(calleeTypes);
|
JSFunction* native = getSingleCallTarget(calleeTypes);
|
||||||
if (!native || !native->isNative() || native->native() != &fun_call) {
|
if (!native || !native->isNative() || native->native() != &fun_call) {
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
return makeCall(native, callInfo);
|
return makeCall(native, callInfo);
|
||||||
|
|
@ -6561,7 +6564,8 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
||||||
argc -= 1;
|
argc -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -6598,7 +6602,8 @@ IonBuilder::jsop_funapply(uint32_t argc)
|
||||||
TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||||
JSFunction* native = getSingleCallTarget(calleeTypes);
|
JSFunction* native = getSingleCallTarget(calleeTypes);
|
||||||
if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) {
|
if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) {
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
return makeCall(native, callInfo);
|
return makeCall(native, callInfo);
|
||||||
|
|
@ -6627,7 +6632,8 @@ IonBuilder::jsop_funapply(uint32_t argc)
|
||||||
return jsop_funapplyarray(argc);
|
return jsop_funapplyarray(argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
return makeCall(native, callInfo);
|
return makeCall(native, callInfo);
|
||||||
|
|
@ -6736,7 +6742,8 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
||||||
// can inline the apply() target and don't care about the actual arguments
|
// can inline the apply() target and don't care about the actual arguments
|
||||||
// that were passed in.
|
// that were passed in.
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
|
|
||||||
// Vp
|
// Vp
|
||||||
MDefinition* vp = current->pop();
|
MDefinition* vp = current->pop();
|
||||||
|
|
@ -6782,7 +6789,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
IonBuilder::jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue)
|
||||||
{
|
{
|
||||||
startTrackingOptimizations();
|
startTrackingOptimizations();
|
||||||
|
|
||||||
|
|
@ -6808,7 +6815,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
||||||
if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4))
|
if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), constructing);
|
CallInfo callInfo(alloc(), constructing, ignoresReturnValue);
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -6944,7 +6951,8 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(),
|
MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(),
|
||||||
callInfo.argc(), callInfo.constructing(), isDOMCall);
|
callInfo.argc(), callInfo.constructing(),
|
||||||
|
callInfo.ignoresReturnValue(), isDOMCall);
|
||||||
if (!call)
|
if (!call)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
@ -7045,7 +7053,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||||
// Emit a normal call if the eval has never executed. This keeps us from
|
// Emit a normal call if the eval has never executed. This keeps us from
|
||||||
// disabling compilation for the script when testing with --ion-eager.
|
// disabling compilation for the script when testing with --ion-eager.
|
||||||
if (calleeTypes && calleeTypes->empty())
|
if (calleeTypes && calleeTypes->empty())
|
||||||
return jsop_call(argc, /* constructing = */ false);
|
return jsop_call(argc, /* constructing = */ false, false);
|
||||||
|
|
||||||
JSFunction* singleton = getSingleCallTarget(calleeTypes);
|
JSFunction* singleton = getSingleCallTarget(calleeTypes);
|
||||||
if (!singleton)
|
if (!singleton)
|
||||||
|
|
@ -7061,7 +7069,8 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||||
if (info().funMaybeLazy()->isArrow())
|
if (info().funMaybeLazy()->isArrow())
|
||||||
return abort("Direct eval from arrow function");
|
return abort("Direct eval from arrow function");
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), /* constructing = */ false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, argc))
|
if (!callInfo.init(current, argc))
|
||||||
return false;
|
return false;
|
||||||
callInfo.setImplicitlyUsedUnchecked();
|
callInfo.setImplicitlyUsedUnchecked();
|
||||||
|
|
@ -7100,7 +7109,8 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||||
current->push(dynamicName);
|
current->push(dynamicName);
|
||||||
current->push(constant(UndefinedValue())); // thisv
|
current->push(constant(UndefinedValue())); // thisv
|
||||||
|
|
||||||
CallInfo evalCallInfo(alloc(), /* constructing = */ false);
|
CallInfo evalCallInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!evalCallInfo.init(current, /* argc = */ 0))
|
if (!evalCallInfo.init(current, /* argc = */ 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -7117,7 +7127,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||||
return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsop_call(argc, /* constructing = */ false);
|
return jsop_call(argc, /* constructing = */ false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -11999,7 +12009,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName
|
||||||
|
|
||||||
current->push(obj);
|
current->push(obj);
|
||||||
|
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, 0))
|
if (!callInfo.init(current, 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -12494,7 +12505,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj,
|
||||||
|
|
||||||
// Call the setter. Note that we have to push the original value, not
|
// Call the setter. Note that we have to push the original value, not
|
||||||
// the setter's return value.
|
// the setter's return value.
|
||||||
CallInfo callInfo(alloc(), false);
|
CallInfo callInfo(alloc(), /* constructing = */ false,
|
||||||
|
/* ignoresReturnValue = */ BytecodeIsPopped(pc));
|
||||||
if (!callInfo.init(current, 1))
|
if (!callInfo.init(current, 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -699,6 +699,7 @@ class IonBuilder
|
||||||
MOZ_MUST_USE bool jsop_funapplyarguments(uint32_t argc);
|
MOZ_MUST_USE bool jsop_funapplyarguments(uint32_t argc);
|
||||||
MOZ_MUST_USE bool jsop_funapplyarray(uint32_t argc);
|
MOZ_MUST_USE bool jsop_funapplyarray(uint32_t argc);
|
||||||
MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing);
|
MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing);
|
||||||
|
MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue);
|
||||||
MOZ_MUST_USE bool jsop_eval(uint32_t argc);
|
MOZ_MUST_USE bool jsop_eval(uint32_t argc);
|
||||||
MOZ_MUST_USE bool jsop_ifeq(JSOp op);
|
MOZ_MUST_USE bool jsop_ifeq(JSOp op);
|
||||||
MOZ_MUST_USE bool jsop_try();
|
MOZ_MUST_USE bool jsop_try();
|
||||||
|
|
@ -1352,16 +1353,21 @@ class CallInfo
|
||||||
MDefinition* newTargetArg_;
|
MDefinition* newTargetArg_;
|
||||||
MDefinitionVector args_;
|
MDefinitionVector args_;
|
||||||
|
|
||||||
bool constructing_;
|
bool constructing_:1;
|
||||||
bool setter_;
|
|
||||||
|
// True if the caller does not use the return value.
|
||||||
|
bool ignoresReturnValue_:1;
|
||||||
|
|
||||||
|
bool setter_:1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CallInfo(TempAllocator& alloc, bool constructing)
|
CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue)
|
||||||
: fun_(nullptr),
|
: fun_(nullptr),
|
||||||
thisArg_(nullptr),
|
thisArg_(nullptr),
|
||||||
newTargetArg_(nullptr),
|
newTargetArg_(nullptr),
|
||||||
args_(alloc),
|
args_(alloc),
|
||||||
constructing_(constructing),
|
constructing_(constructing),
|
||||||
|
ignoresReturnValue_(ignoresReturnValue),
|
||||||
setter_(false)
|
setter_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
@ -1370,6 +1376,7 @@ class CallInfo
|
||||||
|
|
||||||
fun_ = callInfo.fun();
|
fun_ = callInfo.fun();
|
||||||
thisArg_ = callInfo.thisArg();
|
thisArg_ = callInfo.thisArg();
|
||||||
|
ignoresReturnValue_ = callInfo.ignoresReturnValue();
|
||||||
|
|
||||||
if (constructing())
|
if (constructing())
|
||||||
newTargetArg_ = callInfo.getNewTarget();
|
newTargetArg_ = callInfo.getNewTarget();
|
||||||
|
|
@ -1466,6 +1473,10 @@ class CallInfo
|
||||||
return constructing_;
|
return constructing_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ignoresReturnValue() const {
|
||||||
|
return ignoresReturnValue_;
|
||||||
|
}
|
||||||
|
|
||||||
void setNewTarget(MDefinition* newTarget) {
|
void setNewTarget(MDefinition* newTarget) {
|
||||||
MOZ_ASSERT(constructing());
|
MOZ_ASSERT(constructing());
|
||||||
newTargetArg_ = newTarget;
|
newTargetArg_ = newTarget;
|
||||||
|
|
|
||||||
|
|
@ -1970,7 +1970,7 @@ WrappedFunction::WrappedFunction(JSFunction* fun)
|
||||||
|
|
||||||
MCall*
|
MCall*
|
||||||
MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
|
MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
|
||||||
bool construct, bool isDOMCall)
|
bool construct, bool ignoresReturnValue, bool isDOMCall)
|
||||||
{
|
{
|
||||||
WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr;
|
WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr;
|
||||||
MOZ_ASSERT(maxArgc >= numActualArgs);
|
MOZ_ASSERT(maxArgc >= numActualArgs);
|
||||||
|
|
@ -1979,7 +1979,7 @@ MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numA
|
||||||
MOZ_ASSERT(!construct);
|
MOZ_ASSERT(!construct);
|
||||||
ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs);
|
ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs);
|
||||||
} else {
|
} else {
|
||||||
ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct);
|
ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct, ignoresReturnValue);
|
||||||
}
|
}
|
||||||
if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
|
if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -4043,14 +4043,18 @@ class MCall
|
||||||
uint32_t numActualArgs_;
|
uint32_t numActualArgs_;
|
||||||
|
|
||||||
// True if the call is for JSOP_NEW.
|
// True if the call is for JSOP_NEW.
|
||||||
bool construct_;
|
bool construct_:1;
|
||||||
|
|
||||||
bool needsArgCheck_;
|
// True if the caller does not use the return value.
|
||||||
|
bool ignoresReturnValue_:1;
|
||||||
|
|
||||||
MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct)
|
bool needsArgCheck_:1;
|
||||||
|
|
||||||
|
MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue)
|
||||||
: target_(target),
|
: target_(target),
|
||||||
numActualArgs_(numActualArgs),
|
numActualArgs_(numActualArgs),
|
||||||
construct_(construct),
|
construct_(construct),
|
||||||
|
ignoresReturnValue_(ignoresReturnValue),
|
||||||
needsArgCheck_(true)
|
needsArgCheck_(true)
|
||||||
{
|
{
|
||||||
setResultType(MIRType::Value);
|
setResultType(MIRType::Value);
|
||||||
|
|
@ -4059,7 +4063,7 @@ class MCall
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(Call)
|
INSTRUCTION_HEADER(Call)
|
||||||
static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
|
static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
|
||||||
bool construct, bool isDOMCall);
|
bool construct, bool ignoresReturnValue, bool isDOMCall);
|
||||||
|
|
||||||
void initFunction(MDefinition* func) {
|
void initFunction(MDefinition* func) {
|
||||||
initOperand(FunctionOperandIndex, func);
|
initOperand(FunctionOperandIndex, func);
|
||||||
|
|
@ -4104,6 +4108,10 @@ class MCall
|
||||||
return construct_;
|
return construct_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ignoresReturnValue() const {
|
||||||
|
return ignoresReturnValue_;
|
||||||
|
}
|
||||||
|
|
||||||
// The number of stack arguments is the max between the number of formal
|
// The number of stack arguments is the max between the number of formal
|
||||||
// arguments and the number of actual arguments. The number of stack
|
// arguments and the number of actual arguments. The number of stack
|
||||||
// argument includes the |undefined| padding added in case of underflow.
|
// argument includes the |undefined| padding added in case of underflow.
|
||||||
|
|
@ -4147,7 +4155,7 @@ class MCallDOMNative : public MCall
|
||||||
// virtual things from MCall.
|
// virtual things from MCall.
|
||||||
protected:
|
protected:
|
||||||
MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs)
|
MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs)
|
||||||
: MCall(target, numActualArgs, false)
|
: MCall(target, numActualArgs, false, false)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
|
MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
|
||||||
|
|
||||||
|
|
@ -4162,7 +4170,8 @@ class MCallDOMNative : public MCall
|
||||||
}
|
}
|
||||||
|
|
||||||
friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
|
friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
|
||||||
size_t numActualArgs, bool construct, bool isDOMCall);
|
size_t numActualArgs, bool construct, bool ignoresReturnValue,
|
||||||
|
bool isDOMCall);
|
||||||
|
|
||||||
const JSJitInfo* getJitInfo() const;
|
const JSJitInfo* getJitInfo() const;
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ VMFunction::addToFunctions()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv,
|
InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue,
|
||||||
MutableHandleValue rval)
|
uint32_t argc, Value* argv, MutableHandleValue rval)
|
||||||
{
|
{
|
||||||
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
|
TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
|
||||||
TraceLogStartEvent(logger, TraceLogger_Call);
|
TraceLogStartEvent(logger, TraceLogger_Call);
|
||||||
|
|
@ -104,7 +104,7 @@ InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc
|
||||||
return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
|
return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
InvokeArgs args(cx);
|
InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue);
|
||||||
if (!args.init(cx, argc))
|
if (!args.init(cx, argc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActu
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(numFormalArgs > numActualArgs);
|
MOZ_ASSERT(numFormalArgs > numActualArgs);
|
||||||
argv[1 + numActualArgs] = argv[1 + numFormalArgs];
|
argv[1 + numActualArgs] = argv[1 + numFormalArgs];
|
||||||
return InvokeFunction(cx, obj, true, numActualArgs, argv, rval);
|
return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -584,8 +584,8 @@ class AutoDetectInvalidation
|
||||||
};
|
};
|
||||||
|
|
||||||
MOZ_MUST_USE bool
|
MOZ_MUST_USE bool
|
||||||
InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, uint32_t argc, Value* argv,
|
InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, bool ignoresReturnValue,
|
||||||
MutableHandleValue rval);
|
uint32_t argc, Value* argv, MutableHandleValue rval);
|
||||||
MOZ_MUST_USE bool
|
MOZ_MUST_USE bool
|
||||||
InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
|
InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
|
||||||
uint32_t numFormalArgs, Value* argv, MutableHandleValue rval);
|
uint32_t numFormalArgs, Value* argv, MutableHandleValue rval);
|
||||||
|
|
|
||||||
|
|
@ -1898,6 +1898,9 @@ class LJSCallInstructionHelper : public LCallInstructionHelper<Defs, Operands, T
|
||||||
bool isConstructing() const {
|
bool isConstructing() const {
|
||||||
return mir()->isConstructing();
|
return mir()->isConstructing();
|
||||||
}
|
}
|
||||||
|
bool ignoresReturnValue() const {
|
||||||
|
return mir()->ignoresReturnValue();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generates a polymorphic callsite, wherein the function being called is
|
// Generates a polymorphic callsite, wherein the function being called is
|
||||||
|
|
|
||||||
|
|
@ -2254,6 +2254,7 @@ struct JSJitInfo {
|
||||||
Method,
|
Method,
|
||||||
StaticMethod,
|
StaticMethod,
|
||||||
InlinableNative,
|
InlinableNative,
|
||||||
|
IgnoresReturnValueNative,
|
||||||
// Must be last
|
// Must be last
|
||||||
OpTypeCount
|
OpTypeCount
|
||||||
};
|
};
|
||||||
|
|
@ -2345,8 +2346,13 @@ struct JSJitInfo {
|
||||||
JSJitMethodOp method;
|
JSJitMethodOp method;
|
||||||
/** A DOM static method, used for Promise wrappers */
|
/** A DOM static method, used for Promise wrappers */
|
||||||
JSNative staticMethod;
|
JSNative staticMethod;
|
||||||
|
JSNative ignoresReturnValueMethod;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static unsigned offsetOfIgnoresReturnValueNative() {
|
||||||
|
return offsetof(JSJitInfo, ignoresReturnValueMethod);
|
||||||
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t protoID;
|
uint16_t protoID;
|
||||||
js::jit::InlinableNative inlinableNative;
|
js::jit::InlinableNative inlinableNative;
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,10 @@ class JSFunction : public js::NativeObject
|
||||||
return offsetof(JSFunction, u.nativeOrScript);
|
return offsetof(JSFunction, u.nativeOrScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned offsetOfJitInfo() {
|
||||||
|
return offsetof(JSFunction, u.n.jitinfo);
|
||||||
|
}
|
||||||
|
|
||||||
inline void trace(JSTracer* trc);
|
inline void trace(JSTracer* trc);
|
||||||
|
|
||||||
/* Bound function accessors. */
|
/* Bound function accessors. */
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,8 @@ js::StackUses(JSScript* script, jsbytecode* pc)
|
||||||
return 2 + GET_ARGC(pc) + 1;
|
return 2 + GET_ARGC(pc) + 1;
|
||||||
default:
|
default:
|
||||||
/* stack: fun, this, [argc arguments] */
|
/* stack: fun, this, [argc arguments] */
|
||||||
MOZ_ASSERT(op == JSOP_CALL || op == JSOP_EVAL || op == JSOP_CALLITER ||
|
MOZ_ASSERT(op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_EVAL ||
|
||||||
|
op == JSOP_CALLITER ||
|
||||||
op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
|
op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
|
||||||
return 2 + GET_ARGC(pc);
|
return 2 + GET_ARGC(pc);
|
||||||
}
|
}
|
||||||
|
|
@ -1363,6 +1364,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc)
|
||||||
case JSOP_NEWTARGET:
|
case JSOP_NEWTARGET:
|
||||||
return write("new.target");
|
return write("new.target");
|
||||||
case JSOP_CALL:
|
case JSOP_CALL:
|
||||||
|
case JSOP_CALL_IGNORES_RV:
|
||||||
case JSOP_CALLITER:
|
case JSOP_CALLITER:
|
||||||
case JSOP_FUNCALL:
|
case JSOP_FUNCALL:
|
||||||
return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) &&
|
return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) &&
|
||||||
|
|
@ -1662,7 +1664,7 @@ DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res)
|
||||||
|
|
||||||
/* Don't handle getters, setters or calls from fun.call/fun.apply. */
|
/* Don't handle getters, setters or calls from fun.call/fun.apply. */
|
||||||
JSOp op = JSOp(*current);
|
JSOp op = JSOp(*current);
|
||||||
if (op != JSOP_CALL && op != JSOP_NEW)
|
if (op != JSOP_CALL && op != JSOP_CALL_IGNORES_RV && op != JSOP_NEW)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current))
|
if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current))
|
||||||
|
|
@ -1725,6 +1727,8 @@ js::CallResultEscapes(jsbytecode* pc)
|
||||||
|
|
||||||
if (*pc == JSOP_CALL)
|
if (*pc == JSOP_CALL)
|
||||||
pc += JSOP_CALL_LENGTH;
|
pc += JSOP_CALL_LENGTH;
|
||||||
|
else if (*pc == JSOP_CALL_IGNORES_RV)
|
||||||
|
pc += JSOP_CALL_IGNORES_RV_LENGTH;
|
||||||
else if (*pc == JSOP_SPREADCALL)
|
else if (*pc == JSOP_SPREADCALL)
|
||||||
pc += JSOP_SPREADCALL_LENGTH;
|
pc += JSOP_SPREADCALL_LENGTH;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,13 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct
|
||||||
|
|
||||||
if (fun->isNative()) {
|
if (fun->isNative()) {
|
||||||
MOZ_ASSERT_IF(construct, !fun->isConstructor());
|
MOZ_ASSERT_IF(construct, !fun->isConstructor());
|
||||||
return CallJSNative(cx, fun->native(), args);
|
JSNative native = fun->native();
|
||||||
|
if (!construct && args.ignoresReturnValue()) {
|
||||||
|
const JSJitInfo* jitInfo = fun->jitInfo();
|
||||||
|
if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
|
||||||
|
native = jitInfo->ignoresReturnValueMethod;
|
||||||
|
}
|
||||||
|
return CallJSNative(cx, native, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JSFunction::getOrCreateScript(cx, fun))
|
if (!JSFunction::getOrCreateScript(cx, fun))
|
||||||
|
|
@ -2974,6 +2980,7 @@ CASE(JSOP_FUNAPPLY)
|
||||||
|
|
||||||
CASE(JSOP_NEW)
|
CASE(JSOP_NEW)
|
||||||
CASE(JSOP_CALL)
|
CASE(JSOP_CALL)
|
||||||
|
CASE(JSOP_CALL_IGNORES_RV)
|
||||||
CASE(JSOP_CALLITER)
|
CASE(JSOP_CALLITER)
|
||||||
CASE(JSOP_SUPERCALL)
|
CASE(JSOP_SUPERCALL)
|
||||||
CASE(JSOP_FUNCALL)
|
CASE(JSOP_FUNCALL)
|
||||||
|
|
@ -2982,10 +2989,11 @@ CASE(JSOP_FUNCALL)
|
||||||
cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
|
cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
|
||||||
|
|
||||||
MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
|
MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
|
||||||
|
bool ignoresReturnValue = *REGS.pc == JSOP_CALL_IGNORES_RV;
|
||||||
unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
|
unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
|
||||||
|
|
||||||
MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
|
MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
|
||||||
CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct);
|
CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
|
||||||
|
|
||||||
JSFunction* maybeFun;
|
JSFunction* maybeFun;
|
||||||
bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
|
bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
|
||||||
|
|
|
||||||
|
|
@ -2292,14 +2292,23 @@
|
||||||
* Operands:
|
* Operands:
|
||||||
* Stack: =>
|
* Stack: =>
|
||||||
*/ \
|
*/ \
|
||||||
macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)
|
macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)\
|
||||||
|
/*
|
||||||
|
* Like JSOP_CALL, but tells the function that the return value is ignored.
|
||||||
|
* stack.
|
||||||
|
* Category: Statements
|
||||||
|
* Type: Function
|
||||||
|
* Operands: uint16_t argc
|
||||||
|
* Stack: callee, this, args[0], ..., args[argc-1] => rval
|
||||||
|
* nuses: (argc+2)
|
||||||
|
*/ \
|
||||||
|
macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In certain circumstances it may be useful to "pad out" the opcode space to
|
* In certain circumstances it may be useful to "pad out" the opcode space to
|
||||||
* a power of two. Use this macro to do so.
|
* a power of two. Use this macro to do so.
|
||||||
*/
|
*/
|
||||||
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
||||||
macro(231) \
|
|
||||||
macro(232) \
|
macro(232) \
|
||||||
macro(233) \
|
macro(233) \
|
||||||
macro(234) \
|
macro(234) \
|
||||||
|
|
|
||||||
|
|
@ -1006,6 +1006,17 @@ class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT>
|
||||||
explicit InvokeArgs(JSContext* cx) : Base(cx) {}
|
explicit InvokeArgs(JSContext* cx) : Base(cx) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Function call args of statically-unknown count. */
|
||||||
|
class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase<NO_CONSTRUCT>
|
||||||
|
{
|
||||||
|
using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) {
|
||||||
|
this->ignoresReturnValue_ = ignoresReturnValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Function call args of statically-known count. */
|
/** Function call args of statically-known count. */
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
|
class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue