mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 921120 - Enable Ion-compilation of JSOP_SETARG for functions which use magic arguments. r=nbp
This commit is contained in:
parent
a2e77150b6
commit
44f1bc368f
@ -166,6 +166,10 @@ BytecodeAnalysis::init(JSContext *cx)
|
||||
hasTryFinally_ = true;
|
||||
break;
|
||||
|
||||
case JSOP_SETARG:
|
||||
hasSetArg_ = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ class BytecodeAnalysis
|
||||
|
||||
bool usesScopeChain_;
|
||||
bool hasTryFinally_;
|
||||
bool hasSetArg_;
|
||||
|
||||
public:
|
||||
explicit BytecodeAnalysis(JSScript *script);
|
||||
@ -59,13 +60,17 @@ class BytecodeAnalysis
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool usesScopeChain() {
|
||||
bool usesScopeChain() const {
|
||||
return usesScopeChain_;
|
||||
}
|
||||
|
||||
bool hasTryFinally() {
|
||||
bool hasTryFinally() const {
|
||||
return hasTryFinally_;
|
||||
}
|
||||
|
||||
bool hasSetArg() const {
|
||||
return hasSetArg_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -5455,7 +5455,7 @@ CodeGenerator::visitArgumentsLength(LArgumentsLength *lir)
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitGetArgument(LGetArgument *lir)
|
||||
CodeGenerator::visitGetFrameArgument(LGetFrameArgument *lir)
|
||||
{
|
||||
ValueOperand result = GetValueOutput(lir);
|
||||
const LAllocation *index = lir->index();
|
||||
@ -5473,6 +5473,45 @@ CodeGenerator::visitGetArgument(LGetArgument *lir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitSetFrameArgumentT(LSetFrameArgumentT *lir)
|
||||
{
|
||||
size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
|
||||
(sizeof(Value) * lir->mir()->argno());
|
||||
|
||||
MIRType type = lir->mir()->value()->type();
|
||||
|
||||
if (type == MIRType_Double) {
|
||||
// Store doubles directly.
|
||||
FloatRegister input = ToFloatRegister(lir->input());
|
||||
masm.storeDouble(input, Address(StackPointer, argOffset));
|
||||
|
||||
} else {
|
||||
Register input = ToRegister(lir->input());
|
||||
masm.storeValue(ValueTypeFromMIRType(type), input, Address(StackPointer, argOffset));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator:: visitSetFrameArgumentC(LSetFrameArgumentC *lir)
|
||||
{
|
||||
size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
|
||||
(sizeof(Value) * lir->mir()->argno());
|
||||
masm.storeValue(lir->val(), Address(StackPointer, argOffset));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator:: visitSetFrameArgumentV(LSetFrameArgumentV *lir)
|
||||
{
|
||||
const ValueOperand val = ToValue(lir, LSetFrameArgumentV::Input);
|
||||
size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
|
||||
(sizeof(Value) * lir->mir()->argno());
|
||||
masm.storeValue(val, Address(StackPointer, argOffset));
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
|
||||
static const VMFunction RunOnceScriptPrologueInfo =
|
||||
FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
|
||||
|
@ -237,7 +237,10 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitIteratorMore(LIteratorMore *lir);
|
||||
bool visitIteratorEnd(LIteratorEnd *lir);
|
||||
bool visitArgumentsLength(LArgumentsLength *lir);
|
||||
bool visitGetArgument(LGetArgument *lir);
|
||||
bool visitGetFrameArgument(LGetFrameArgument *lir);
|
||||
bool visitSetFrameArgumentT(LSetFrameArgumentT *lir);
|
||||
bool visitSetFrameArgumentC(LSetFrameArgumentC *lir);
|
||||
bool visitSetFrameArgumentV(LSetFrameArgumentV *lir);
|
||||
bool visitRunOncePrologue(LRunOncePrologue *lir);
|
||||
bool emitRest(LInstruction *lir, Register array, Register numActuals,
|
||||
Register temp0, Register temp1, unsigned numFormals,
|
||||
|
@ -238,6 +238,9 @@ class CompileInfo
|
||||
bool hasArguments() const {
|
||||
return script()->argumentsHasVarBinding();
|
||||
}
|
||||
bool argumentsAliasesFormals() const {
|
||||
return script()->argumentsAliasesFormals();
|
||||
}
|
||||
bool needsArgsObj() const {
|
||||
return script()->needsArgsObj();
|
||||
}
|
||||
|
@ -1388,49 +1388,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
return true;
|
||||
|
||||
case JSOP_SETARG:
|
||||
// To handle this case, we should spill the arguments to the space where
|
||||
// actual arguments are stored. The tricky part is that if we add a MIR
|
||||
// to wrap the spilling action, we don't want the spilling to be
|
||||
// captured by the GETARG and by the resume point, only by
|
||||
// MGetArgument.
|
||||
if (info().argsObjAliasesFormals()) {
|
||||
current->add(MSetArgumentsObjectArg::New(current->argumentsObject(), GET_SLOTNO(pc),
|
||||
current->peek(-1)));
|
||||
} else {
|
||||
// TODO: if hasArguments() is true, and the script has a JSOP_SETARG, then
|
||||
// convert all arg accesses to go through the arguments object.
|
||||
if (info().hasArguments())
|
||||
return abort("NYI: arguments & setarg.");
|
||||
|
||||
int32_t arg = GET_SLOTNO(pc);
|
||||
|
||||
// If this assignment is at the start of the function and is coercing
|
||||
// the original value for the argument which was passed in, loosen
|
||||
// the type information for that original argument if it is currently
|
||||
// empty due to originally executing in the interpreter.
|
||||
MDefinition *value = current->peek(-1);
|
||||
if (graph().numBlocks() == 1 &&
|
||||
(value->isBitOr() || value->isBitAnd() || value->isMul() /* for JSOP_POS */))
|
||||
{
|
||||
for (size_t i = 0; i < value->numOperands(); i++) {
|
||||
MDefinition *op = value->getOperand(i);
|
||||
if (op->isParameter() &&
|
||||
op->toParameter()->index() == arg &&
|
||||
op->resultTypeSet() &&
|
||||
op->resultTypeSet()->empty())
|
||||
{
|
||||
types::TypeSet *argTypes = types::TypeScript::ArgTypes(script(), arg);
|
||||
|
||||
// Update both the original and cloned type set.
|
||||
argTypes->addType(cx, types::Type::UnknownType());
|
||||
op->resultTypeSet()->addType(cx, types::Type::UnknownType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current->setArg(arg);
|
||||
}
|
||||
return true;
|
||||
return jsop_setarg(GET_SLOTNO(pc));
|
||||
|
||||
case JSOP_GETLOCAL:
|
||||
case JSOP_CALLLOCAL:
|
||||
@ -3379,7 +3337,7 @@ IonBuilder::jsop_try()
|
||||
return abort("Has try-finally");
|
||||
|
||||
// Try-catch within inline frames is not yet supported.
|
||||
if (callerBuilder_)
|
||||
if (isInlineBuilder())
|
||||
return abort("try-catch within inline frame");
|
||||
|
||||
graph().setHasTryBlock();
|
||||
@ -3486,7 +3444,7 @@ IonBuilder::ControlStatus
|
||||
IonBuilder::processThrow()
|
||||
{
|
||||
// JSOP_THROW can't be compiled within inlined frames.
|
||||
if (callerBuilder_)
|
||||
if (isInlineBuilder())
|
||||
return ControlStatus_Abort;
|
||||
|
||||
MDefinition *def = current->pop();
|
||||
@ -6741,7 +6699,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
|
||||
if (obj->type() != MIRType_Magic)
|
||||
return true;
|
||||
|
||||
// Emit GetArgument.
|
||||
// Emit GetFrameArgument.
|
||||
|
||||
JS_ASSERT(!info().argsObjAliasesFormals());
|
||||
|
||||
@ -6761,7 +6719,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
|
||||
index = addBoundsCheck(index, length);
|
||||
|
||||
// Load the argument from the actual arguments.
|
||||
MGetArgument *load = MGetArgument::New(index);
|
||||
MGetFrameArgument *load = MGetFrameArgument::New(index, analysis_.hasSetArg());
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
@ -9082,6 +9040,67 @@ IonBuilder::jsop_lambda(JSFunction *fun)
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_setarg(uint32_t arg)
|
||||
{
|
||||
// To handle this case, we should spill the arguments to the space where
|
||||
// actual arguments are stored. The tricky part is that if we add a MIR
|
||||
// to wrap the spilling action, we don't want the spilling to be
|
||||
// captured by the GETARG and by the resume point, only by
|
||||
// MGetFrameArgument.
|
||||
JS_ASSERT(analysis_.hasSetArg());
|
||||
MDefinition *val = current->peek(-1);
|
||||
|
||||
// If an arguments object is in use, and it aliases formals, then all SETARGs
|
||||
// must go through the arguments object.
|
||||
if (info().argsObjAliasesFormals()) {
|
||||
current->add(MSetArgumentsObjectArg::New(current->argumentsObject(), GET_SLOTNO(pc), val));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, if a magic arguments is in use, and it aliases formals, and there exist
|
||||
// arguments[...] GETELEM expressions in the script, then SetFrameArgument must be used.
|
||||
// If no arguments[...] GETELEM expressions are in the script, and an argsobj is not
|
||||
// required, then it means that any aliased argument set can never be observed, and
|
||||
// the frame does not actually need to be updated with the new arg value.
|
||||
if (info().argumentsAliasesFormals()) {
|
||||
// Try-catch within inline frames is not yet supported.
|
||||
if (isInlineBuilder())
|
||||
return abort("JSOP_SETARG with magic arguments in inlined function.");
|
||||
|
||||
MSetFrameArgument *store = MSetFrameArgument::New(arg, val);
|
||||
current->add(store);
|
||||
current->setArg(arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this assignment is at the start of the function and is coercing
|
||||
// the original value for the argument which was passed in, loosen
|
||||
// the type information for that original argument if it is currently
|
||||
// empty due to originally executing in the interpreter.
|
||||
if (graph().numBlocks() == 1 &&
|
||||
(val->isBitOr() || val->isBitAnd() || val->isMul() /* for JSOP_POS */))
|
||||
{
|
||||
for (size_t i = 0; i < val->numOperands(); i++) {
|
||||
MDefinition *op = val->getOperand(i);
|
||||
if (op->isParameter() &&
|
||||
op->toParameter()->index() == (int32_t)arg &&
|
||||
op->resultTypeSet() &&
|
||||
op->resultTypeSet()->empty())
|
||||
{
|
||||
types::TypeSet *argTypes = types::TypeScript::ArgTypes(script(), arg);
|
||||
|
||||
// Update both the original and cloned type set.
|
||||
argTypes->addType(cx, types::Type::UnknownType());
|
||||
op->resultTypeSet()->addType(cx, types::Type::UnknownType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current->setArg(arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_defvar(uint32_t index)
|
||||
{
|
||||
|
@ -447,6 +447,7 @@ class IonBuilder : public MIRGenerator
|
||||
bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
|
||||
bool jsop_pos();
|
||||
bool jsop_neg();
|
||||
bool jsop_setarg(uint32_t arg);
|
||||
bool jsop_defvar(uint32_t index);
|
||||
bool jsop_deffun(uint32_t index);
|
||||
bool jsop_notearg();
|
||||
@ -673,6 +674,10 @@ class IonBuilder : public MIRGenerator
|
||||
|
||||
TypeRepresentationSetHash *getOrCreateReprSetHash(); // fallible
|
||||
|
||||
bool isInlineBuilder() const {
|
||||
return callerBuilder_ != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
bool init();
|
||||
|
||||
|
@ -4552,13 +4552,13 @@ class LArgumentsLength : public LInstructionHelper<1, 0, 0>
|
||||
};
|
||||
|
||||
// Load a value from the actual arguments.
|
||||
class LGetArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
class LGetFrameArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GetArgument)
|
||||
LIR_HEADER(GetFrameArgument)
|
||||
BOX_OUTPUT_ACCESSORS()
|
||||
|
||||
LGetArgument(const LAllocation &index) {
|
||||
LGetFrameArgument(const LAllocation &index) {
|
||||
setOperand(0, index);
|
||||
}
|
||||
const LAllocation *index() {
|
||||
@ -4566,6 +4566,58 @@ class LGetArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
|
||||
}
|
||||
};
|
||||
|
||||
// Load a value from the actual arguments.
|
||||
class LSetFrameArgumentT : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SetFrameArgumentT)
|
||||
|
||||
LSetFrameArgumentT(const LAllocation &input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
MSetFrameArgument *mir() const {
|
||||
return mir_->toSetFrameArgument();
|
||||
}
|
||||
const LAllocation *input() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Load a value from the actual arguments.
|
||||
class LSetFrameArgumentC : public LInstructionHelper<0, 0, 0>
|
||||
{
|
||||
Value val_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(SetFrameArgumentC)
|
||||
|
||||
LSetFrameArgumentC(const Value &val) {
|
||||
val_ = val;
|
||||
}
|
||||
MSetFrameArgument *mir() const {
|
||||
return mir_->toSetFrameArgument();
|
||||
}
|
||||
const Value &val() const {
|
||||
return val_;
|
||||
}
|
||||
};
|
||||
|
||||
// Load a value from the actual arguments.
|
||||
class LSetFrameArgumentV : public LInstructionHelper<0, BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SetFrameArgumentV)
|
||||
BOX_OUTPUT_ACCESSORS()
|
||||
|
||||
LSetFrameArgumentV() {}
|
||||
|
||||
static const size_t Input = 0;
|
||||
|
||||
MSetFrameArgument *mir() const {
|
||||
return mir_->toSetFrameArgument();
|
||||
}
|
||||
};
|
||||
|
||||
class LRunOncePrologue : public LCallInstructionHelper<0, 0, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -227,7 +227,10 @@
|
||||
_(TypedObjectElements) \
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(GetFrameArgument) \
|
||||
_(SetFrameArgumentT) \
|
||||
_(SetFrameArgumentC) \
|
||||
_(SetFrameArgumentV) \
|
||||
_(RunOncePrologue) \
|
||||
_(Rest) \
|
||||
_(RestPar) \
|
||||
|
@ -2914,12 +2914,34 @@ LIRGenerator::visitArgumentsLength(MArgumentsLength *ins)
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitGetArgument(MGetArgument *ins)
|
||||
LIRGenerator::visitGetFrameArgument(MGetFrameArgument *ins)
|
||||
{
|
||||
LGetArgument *lir = new LGetArgument(useRegisterOrConstant(ins->index()));
|
||||
LGetFrameArgument *lir = new LGetFrameArgument(useRegisterOrConstant(ins->index()));
|
||||
return defineBox(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitSetFrameArgument(MSetFrameArgument *ins)
|
||||
{
|
||||
MDefinition *input = ins->input();
|
||||
|
||||
if (input->type() == MIRType_Value) {
|
||||
LSetFrameArgumentV *lir = new LSetFrameArgumentV();
|
||||
if (!useBox(lir, LSetFrameArgumentV::Input, input))
|
||||
return false;
|
||||
return add(lir, ins);
|
||||
}
|
||||
|
||||
if (input->type() == MIRType_Undefined || input->type() == MIRType_Null) {
|
||||
Value val = input->type() == MIRType_Undefined ? UndefinedValue() : NullValue();
|
||||
LSetFrameArgumentC *lir = new LSetFrameArgumentC(val);
|
||||
return add(lir, ins);
|
||||
}
|
||||
|
||||
LSetFrameArgumentT *lir = new LSetFrameArgumentT(useRegister(input));
|
||||
return add(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitRunOncePrologue(MRunOncePrologue *ins)
|
||||
{
|
||||
|
@ -231,7 +231,8 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitIteratorEnd(MIteratorEnd *ins);
|
||||
bool visitStringLength(MStringLength *ins);
|
||||
bool visitArgumentsLength(MArgumentsLength *ins);
|
||||
bool visitGetArgument(MGetArgument *ins);
|
||||
bool visitGetFrameArgument(MGetFrameArgument *ins);
|
||||
bool visitSetFrameArgument(MSetFrameArgument *ins);
|
||||
bool visitRunOncePrologue(MRunOncePrologue *ins);
|
||||
bool visitRest(MRest *ins);
|
||||
bool visitRestPar(MRestPar *ins);
|
||||
|
@ -218,12 +218,13 @@ class AliasSet {
|
||||
FixedSlot = 1 << 3, // A member of obj->fixedSlots().
|
||||
TypedArrayElement = 1 << 4, // A typed array element.
|
||||
DOMProperty = 1 << 5, // A DOM property
|
||||
AsmJSGlobalVar = 1 << 6, // An asm.js global var
|
||||
AsmJSHeap = 1 << 7, // An asm.js heap load
|
||||
FrameArgument = 1 << 6, // An argument kept on the stack frame
|
||||
AsmJSGlobalVar = 1 << 7, // An asm.js global var
|
||||
AsmJSHeap = 1 << 8, // An asm.js heap load
|
||||
Last = AsmJSHeap,
|
||||
Any = Last | (Last - 1),
|
||||
|
||||
NumCategories = 8,
|
||||
NumCategories = 9,
|
||||
|
||||
// Indicates load or store.
|
||||
Store_ = 1 << 31
|
||||
@ -7743,22 +7744,25 @@ class MArgumentsLength : public MNullaryInstruction
|
||||
};
|
||||
|
||||
// This MIR instruction is used to get an argument from the actual arguments.
|
||||
class MGetArgument
|
||||
class MGetFrameArgument
|
||||
: public MUnaryInstruction,
|
||||
public IntPolicy<0>
|
||||
{
|
||||
MGetArgument(MDefinition *idx)
|
||||
: MUnaryInstruction(idx)
|
||||
bool scriptHasSetArg_;
|
||||
|
||||
MGetFrameArgument(MDefinition *idx, bool scriptHasSetArg)
|
||||
: MUnaryInstruction(idx),
|
||||
scriptHasSetArg_(scriptHasSetArg)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(GetArgument)
|
||||
INSTRUCTION_HEADER(GetFrameArgument)
|
||||
|
||||
static MGetArgument *New(MDefinition *idx) {
|
||||
return new MGetArgument(idx);
|
||||
static MGetFrameArgument *New(MDefinition *idx, bool scriptHasSetArg) {
|
||||
return new MGetFrameArgument(idx, scriptHasSetArg);
|
||||
}
|
||||
|
||||
MDefinition *index() const {
|
||||
@ -7772,10 +7776,50 @@ class MGetArgument
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
// If the script doesn't have any JSOP_SETARG ops, then this instruction is never
|
||||
// aliased.
|
||||
if (scriptHasSetArg_)
|
||||
return AliasSet::Load(AliasSet::FrameArgument);
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
// This MIR instruction is used to set an argument value in the frame.
|
||||
class MSetFrameArgument
|
||||
: public MUnaryInstruction
|
||||
{
|
||||
uint32_t argno_;
|
||||
|
||||
MSetFrameArgument(uint32_t argno, MDefinition *value)
|
||||
: MUnaryInstruction(value),
|
||||
argno_(argno)
|
||||
{
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SetFrameArgument)
|
||||
|
||||
static MSetFrameArgument *New(uint32_t argno, MDefinition *value) {
|
||||
return new MSetFrameArgument(argno, value);
|
||||
}
|
||||
|
||||
uint32_t argno() const {
|
||||
return argno_;
|
||||
}
|
||||
|
||||
MDefinition *value() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
bool congruentTo(MDefinition *ins) const {
|
||||
return false;
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Store(AliasSet::FrameArgument);
|
||||
}
|
||||
};
|
||||
|
||||
class MRestCommon
|
||||
{
|
||||
unsigned numFormals_;
|
||||
|
@ -165,7 +165,8 @@ namespace jit {
|
||||
_(IteratorEnd) \
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(GetFrameArgument) \
|
||||
_(SetFrameArgument) \
|
||||
_(RunOncePrologue) \
|
||||
_(Rest) \
|
||||
_(Floor) \
|
||||
|
@ -248,7 +248,8 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
UNSAFE_OP(IteratorEnd)
|
||||
SAFE_OP(StringLength)
|
||||
SAFE_OP(ArgumentsLength)
|
||||
SAFE_OP(GetArgument)
|
||||
SAFE_OP(GetFrameArgument)
|
||||
UNSAFE_OP(SetFrameArgument)
|
||||
UNSAFE_OP(RunOncePrologue)
|
||||
CUSTOM_OP(Rest)
|
||||
SAFE_OP(RestPar)
|
||||
|
@ -663,6 +663,9 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
||||
bool argumentsHasVarBinding() const { return argsHasVarBinding_; }
|
||||
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
|
||||
void setArgumentsHasVarBinding();
|
||||
bool argumentsAliasesFormals() const {
|
||||
return argumentsHasVarBinding() && !strict;
|
||||
}
|
||||
|
||||
js::GeneratorKind generatorKind() const {
|
||||
return js::GeneratorKindFromBits(generatorKindBits_);
|
||||
|
Loading…
Reference in New Issue
Block a user