mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Bug 1521491 part 4 - Store IC index in jump target ops. r=tcampbell
The interpreter will use this to set the frame's ICEntry* pointer at jump target ops and then it will just bump this pointer after each JOF_IC op. This way the interpreter can use Baseline ICs with minimal overhead compared to the Baseline JIT. Differential Revision: https://phabricator.services.mozilla.com/D17115 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
3e1d451b87
commit
501ac77053
@ -110,7 +110,8 @@ bool LoopControl::emitLoopHead(BytecodeEmitter* bce,
|
||||
}
|
||||
|
||||
head_ = {bce->offset()};
|
||||
if (!bce->emit1(JSOP_LOOPHEAD)) {
|
||||
ptrdiff_t off;
|
||||
if (!bce->emitJumpTargetOp(JSOP_LOOPHEAD, &off)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -130,11 +131,11 @@ bool LoopControl::emitLoopEntry(BytecodeEmitter* bce,
|
||||
|
||||
MOZ_ASSERT(loopDepth_ > 0);
|
||||
|
||||
uint8_t loopDepthAndFlags =
|
||||
PackLoopEntryDepthHintAndFlags(loopDepth_, canIonOsr_);
|
||||
if (!bce->emit2(JSOP_LOOPENTRY, loopDepthAndFlags)) {
|
||||
ptrdiff_t off;
|
||||
if (!bce->emitJumpTargetOp(JSOP_LOOPENTRY, &off)) {
|
||||
return false;
|
||||
}
|
||||
SetLoopEntryDepthHintAndFlags(bce->code(off), loopDepth_, canIonOsr_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc,
|
||||
tryNoteList(cx),
|
||||
scopeNoteList(cx),
|
||||
resumeOffsetList(cx),
|
||||
numICEntries(0),
|
||||
numYields(0),
|
||||
typesetCount(0),
|
||||
hasSingletons(false),
|
||||
@ -132,6 +133,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc,
|
||||
scriptStartOffsetSet(false),
|
||||
functionBodyEndPosSet(false) {
|
||||
MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
|
||||
|
||||
if (sc->isFunctionBox()) {
|
||||
// Functions have IC entries for type monitoring |this| and arguments.
|
||||
numICEntries = sc->asFunctionBox()->function()->nargs() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
|
||||
@ -204,6 +210,10 @@ bool BytecodeEmitter::emitCheck(JSOp op, ptrdiff_t delta, ptrdiff_t* offset) {
|
||||
}
|
||||
}
|
||||
|
||||
if (BytecodeOpHasIC(op)) {
|
||||
numICEntries++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -310,6 +320,23 @@ bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BytecodeEmitter::emitJumpTargetOp(JSOp op, ptrdiff_t* off) {
|
||||
MOZ_ASSERT(BytecodeIsJumpTarget(op));
|
||||
|
||||
size_t numEntries = numICEntries;
|
||||
if (MOZ_UNLIKELY(numEntries > UINT32_MAX)) {
|
||||
reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitN(op, CodeSpec[op].length - 1, off)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SET_ICINDEX(code(*off), numEntries);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
|
||||
ptrdiff_t off = offset();
|
||||
|
||||
@ -321,10 +348,9 @@ bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
|
||||
|
||||
target->offset = off;
|
||||
lastTarget.offset = off;
|
||||
if (!emit1(JSOP_JUMPTARGET)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
ptrdiff_t opOff;
|
||||
return emitJumpTargetOp(JSOP_JUMPTARGET, &opOff);
|
||||
}
|
||||
|
||||
bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
|
||||
|
@ -192,6 +192,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
|
||||
// code array).
|
||||
CGResumeOffsetList resumeOffsetList;
|
||||
|
||||
// Number of JOF_IC opcodes emitted.
|
||||
size_t numICEntries;
|
||||
|
||||
// Number of yield instructions emitted. Does not include JSOP_AWAIT.
|
||||
uint32_t numYields;
|
||||
|
||||
@ -544,6 +547,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
|
||||
MOZ_MUST_USE bool emitCheckDerivedClassConstructorReturn();
|
||||
|
||||
// Handle jump opcodes and jump targets.
|
||||
MOZ_MUST_USE bool emitJumpTargetOp(JSOp op, ptrdiff_t* off);
|
||||
MOZ_MUST_USE bool emitJumpTarget(JumpTarget* target);
|
||||
MOZ_MUST_USE bool emitJumpNoFallthrough(JSOp op, JumpList* jump);
|
||||
MOZ_MUST_USE bool emitJump(JSOp op, JumpList* jump);
|
||||
|
@ -2,7 +2,7 @@ g = newGlobal({newCompartment: true});
|
||||
hits = 0;
|
||||
Debugger(g).onDebuggerStatement = function(frame) {
|
||||
// Set a breakpoint at the JSOP_DEBUGAFTERYIELD op.
|
||||
frame.script.setBreakpoint(71, {hit: function() { hits++; }});
|
||||
frame.script.setBreakpoint(75, {hit: function() { hits++; }});
|
||||
}
|
||||
g.eval(`
|
||||
function* range() {
|
||||
|
@ -151,6 +151,11 @@ void ICEntry::trace(JSTracer* trc) {
|
||||
// Add ICEntries and fallback stubs for JOF_IC bytecode ops.
|
||||
for (jsbytecode* pc = script->code(); pc < pcEnd; pc = GetNextPc(pc)) {
|
||||
JSOp op = JSOp(*pc);
|
||||
|
||||
// Assert the frontend stored the correct IC index in jump target ops.
|
||||
MOZ_ASSERT_IF(BytecodeIsJumpTarget(op),
|
||||
GET_ICINDEX(pc) == icEntries.length());
|
||||
|
||||
if (!BytecodeOpHasIC(op)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1676,8 +1676,7 @@ ControlFlowGenerator::ControlStatus ControlFlowGenerator::processContinue(
|
||||
CFGState* found = nullptr;
|
||||
jsbytecode* target = pc + GetJumpOffset(pc);
|
||||
for (size_t i = loops_.length() - 1;; i--) {
|
||||
// +1 to skip JSOP_JUMPTARGET.
|
||||
if (loops_[i].continuepc == target + 1 ||
|
||||
if (loops_[i].continuepc == target + JSOP_JUMPTARGET_LENGTH ||
|
||||
EffectiveContinue(loops_[i].continuepc) == target) {
|
||||
found = &cfgStack_[loops_[i].cfgEntry];
|
||||
break;
|
||||
|
@ -1566,6 +1566,19 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_ICINDEX:
|
||||
if (!sp->jsprintf(" (ic: %u)", GET_ICINDEX(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_LOOPENTRY:
|
||||
if (!sp->jsprintf(" (ic: %u, data: %u,%u)", GET_ICINDEX(pc),
|
||||
LoopEntryCanIonOsr(pc), LoopEntryDepthHint(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_ARGC:
|
||||
case JOF_UINT16:
|
||||
i = (int)GET_UINT16(pc);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
@ -57,8 +59,10 @@ enum {
|
||||
JOF_REGEXP = 16, /* uint32_t regexp index */
|
||||
JOF_DOUBLE = 17, /* uint32_t index for double value */
|
||||
JOF_SCOPE = 18, /* uint32_t scope index */
|
||||
JOF_ICINDEX = 19, /* uint32_t IC index */
|
||||
JOF_LOOPENTRY = 20, /* JSOP_LOOPENTRY, combines JOF_ICINDEX and JOF_UINT8 */
|
||||
#ifdef ENABLE_BIGINT
|
||||
JOF_BIGINT = 19, /* uint32_t index for BigInt value */
|
||||
JOF_BIGINT = 21, /* uint32_t index for BigInt value */
|
||||
#endif
|
||||
JOF_TYPEMASK = 0x001f, /* mask for above immediate types */
|
||||
|
||||
@ -251,20 +255,30 @@ static inline void SET_RESUMEINDEX(jsbytecode* pc, uint32_t resumeIndex) {
|
||||
SET_UINT24(pc, resumeIndex);
|
||||
}
|
||||
|
||||
static inline uint32_t GET_ICINDEX(const jsbytecode* pc) {
|
||||
return GET_UINT32(pc);
|
||||
}
|
||||
|
||||
static inline void SET_ICINDEX(jsbytecode* pc, uint32_t icIndex) {
|
||||
SET_UINT32(pc, icIndex);
|
||||
}
|
||||
|
||||
static inline unsigned LoopEntryDepthHint(jsbytecode* pc) {
|
||||
MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
|
||||
return GET_UINT8(pc) & 0x7f;
|
||||
return GET_UINT8(pc + 4) & 0x7f;
|
||||
}
|
||||
|
||||
static inline bool LoopEntryCanIonOsr(jsbytecode* pc) {
|
||||
MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
|
||||
return GET_UINT8(pc) & 0x80;
|
||||
return GET_UINT8(pc + 4) & 0x80;
|
||||
}
|
||||
|
||||
static inline uint8_t PackLoopEntryDepthHintAndFlags(unsigned loopDepth,
|
||||
bool canIonOsr) {
|
||||
return (loopDepth < 0x80 ? uint8_t(loopDepth) : 0x7f) |
|
||||
(canIonOsr ? 0x80 : 0);
|
||||
static inline void SetLoopEntryDepthHintAndFlags(jsbytecode* pc,
|
||||
unsigned loopDepth,
|
||||
bool canIonOsr) {
|
||||
MOZ_ASSERT(*pc == JSOP_LOOPENTRY);
|
||||
uint8_t data = std::min(loopDepth, unsigned(0x7f)) | (canIonOsr ? 0x80 : 0);
|
||||
SET_UINT8(pc + 4, data);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1969,9 +1969,9 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
||||
|
||||
CASE(JSOP_JUMPTARGET)
|
||||
CASE(JSOP_LOOPHEAD) {
|
||||
MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
|
||||
MOZ_ASSERT(CodeSpec[*REGS.pc].length == JSOP_JUMPTARGET_LENGTH);
|
||||
COUNT_COVERAGE();
|
||||
ADVANCE_AND_DISPATCH(1);
|
||||
ADVANCE_AND_DISPATCH(JSOP_JUMPTARGET_LENGTH);
|
||||
}
|
||||
|
||||
CASE(JSOP_LABEL)
|
||||
|
@ -1119,13 +1119,14 @@
|
||||
* Another no-op.
|
||||
*
|
||||
* This opcode is the target of the backwards jump for some loop.
|
||||
* See JSOP_JUMPTARGET for the icIndex operand.
|
||||
*
|
||||
* Category: Statements
|
||||
* Type: Jumps
|
||||
* Operands:
|
||||
* Operands: uint32_t icIndex
|
||||
* Stack: =>
|
||||
*/ \
|
||||
MACRO(JSOP_LOOPHEAD, 109, "loophead", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
MACRO(JSOP_LOOPHEAD, 109, "loophead", NULL, 5, 0, 0, JOF_ICINDEX) \
|
||||
/*
|
||||
* Looks up name on the environment chain and pushes the environment which
|
||||
* contains the name onto the stack. If not found, pushes global lexical
|
||||
@ -2438,14 +2439,14 @@
|
||||
* loop depth. This value starts at 1 and is just a hint: deeply nested
|
||||
* loops all have the same value. The upper bit is set if Ion should be
|
||||
* able to OSR at this point, which is true unless there is non-loop state
|
||||
* on the stack.
|
||||
* on the stack. See JSOP_JUMPTARGET for the icIndex argument.
|
||||
*
|
||||
* Category: Statements
|
||||
* Type: Jumps
|
||||
* Operands: uint8_t BITFIELD
|
||||
* Operands: uint32_t icIndex, uint8_t BITFIELD
|
||||
* Stack: =>
|
||||
*/ \
|
||||
MACRO(JSOP_LOOPENTRY, 227, "loopentry", NULL, 2, 0, 0, JOF_UINT8|JOF_IC) \
|
||||
MACRO(JSOP_LOOPENTRY, 227, "loopentry", NULL, 6, 0, 0, JOF_LOOPENTRY|JOF_IC) \
|
||||
/*
|
||||
* Converts the value on the top of the stack to a String.
|
||||
*
|
||||
@ -2465,15 +2466,14 @@
|
||||
MACRO(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* This opcode is a no-op and it indicates the location of a jump
|
||||
* instruction target. Some other opcodes act as jump targets, such as
|
||||
* LOOPENTRY, as well as all which are matched by BytecodeIsJumpTarget
|
||||
* function.
|
||||
* instruction target. Some other opcodes act as jump targets as well, see
|
||||
* BytecodeIsJumpTarget. The IC index is used by the Baseline interpreter.
|
||||
*
|
||||
* Category: Other
|
||||
* Operands:
|
||||
* Operands: uint32_t icIndex
|
||||
* Stack: =>
|
||||
*/ \
|
||||
MACRO(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)\
|
||||
MACRO(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 5, 0, 0, JOF_ICINDEX) \
|
||||
/*
|
||||
* Like JSOP_CALL, but tells the function that the return value is ignored.
|
||||
* stack.
|
||||
|
Loading…
Reference in New Issue
Block a user