Backed out changeset 8aaffdf63d09 (bug 1920575) for causing bc failures on browser_si...
[gecko.git] / js / src / vm / BytecodeUtil.h
blob8272bb6a5cab8a8e0fc96851ff39094d01a7f0d6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_BytecodeUtil_h
8 #define vm_BytecodeUtil_h
11 * JS bytecode definitions.
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/EndianUtils.h"
18 #include <algorithm>
19 #include <stddef.h>
20 #include <stdint.h>
22 #include "jstypes.h"
23 #include "NamespaceImports.h"
25 #include "js/TypeDecls.h"
26 #include "js/Utility.h"
27 #include "js/Value.h"
28 #include "vm/BytecodeFormatFlags.h" // JOF_*
29 #include "vm/GeneratorResumeKind.h"
30 #include "vm/Opcodes.h"
31 #include "vm/SharedStencil.h" // js::GCThingIndex
32 #include "vm/ThrowMsgKind.h" // ThrowMsgKind, ThrowCondition
34 namespace js {
35 class JS_PUBLIC_API StringPrinter;
36 } // namespace js
38 /* Shorthand for type from format. */
40 static inline uint32_t JOF_TYPE(uint32_t fmt) { return fmt & JOF_TYPEMASK; }
43 * Immediate operand getters, setters, and bounds.
46 static MOZ_ALWAYS_INLINE uint8_t GET_UINT8(jsbytecode* pc) {
47 return uint8_t(pc[1]);
50 static MOZ_ALWAYS_INLINE void SET_UINT8(jsbytecode* pc, uint8_t u) {
51 pc[1] = jsbytecode(u);
54 /* Common uint16_t immediate format helpers. */
56 static inline jsbytecode UINT16_HI(uint16_t i) { return jsbytecode(i >> 8); }
58 static inline jsbytecode UINT16_LO(uint16_t i) { return jsbytecode(i); }
60 static MOZ_ALWAYS_INLINE uint16_t GET_UINT16(const jsbytecode* pc) {
61 uint16_t result;
62 mozilla::NativeEndian::copyAndSwapFromLittleEndian(&result, pc + 1, 1);
63 return result;
66 static MOZ_ALWAYS_INLINE void SET_UINT16(jsbytecode* pc, uint16_t i) {
67 mozilla::NativeEndian::copyAndSwapToLittleEndian(pc + 1, &i, 1);
70 static const unsigned UINT16_LIMIT = 1 << 16;
72 /* Helpers for accessing the offsets of jump opcodes. */
73 static const unsigned JUMP_OFFSET_LEN = 4;
74 static const int32_t JUMP_OFFSET_MIN = INT32_MIN;
75 static const int32_t JUMP_OFFSET_MAX = INT32_MAX;
77 static MOZ_ALWAYS_INLINE uint32_t GET_UINT24(const jsbytecode* pc) {
78 #if MOZ_LITTLE_ENDIAN()
79 // Do a single 32-bit load (for opcode and operand), then shift off the
80 // opcode.
81 uint32_t result;
82 memcpy(&result, pc, 4);
83 return result >> 8;
84 #else
85 return uint32_t((pc[3] << 16) | (pc[2] << 8) | pc[1]);
86 #endif
89 static MOZ_ALWAYS_INLINE void SET_UINT24(jsbytecode* pc, uint32_t i) {
90 MOZ_ASSERT(i < (1 << 24));
92 #if MOZ_LITTLE_ENDIAN()
93 memcpy(pc + 1, &i, 3);
94 #else
95 pc[1] = jsbytecode(i);
96 pc[2] = jsbytecode(i >> 8);
97 pc[3] = jsbytecode(i >> 16);
98 #endif
101 static MOZ_ALWAYS_INLINE int8_t GET_INT8(const jsbytecode* pc) {
102 return int8_t(pc[1]);
105 static MOZ_ALWAYS_INLINE uint32_t GET_UINT32(const jsbytecode* pc) {
106 uint32_t result;
107 mozilla::NativeEndian::copyAndSwapFromLittleEndian(&result, pc + 1, 1);
108 return result;
111 static MOZ_ALWAYS_INLINE void SET_UINT32(jsbytecode* pc, uint32_t u) {
112 mozilla::NativeEndian::copyAndSwapToLittleEndian(pc + 1, &u, 1);
115 static MOZ_ALWAYS_INLINE JS::Value GET_INLINE_VALUE(const jsbytecode* pc) {
116 uint64_t raw;
117 mozilla::NativeEndian::copyAndSwapFromLittleEndian(&raw, pc + 1, 1);
118 return JS::Value::fromRawBits(raw);
121 static MOZ_ALWAYS_INLINE void SET_INLINE_VALUE(jsbytecode* pc,
122 const JS::Value& v) {
123 uint64_t raw = v.asRawBits();
124 mozilla::NativeEndian::copyAndSwapToLittleEndian(pc + 1, &raw, 1);
127 static MOZ_ALWAYS_INLINE int32_t GET_INT32(const jsbytecode* pc) {
128 return static_cast<int32_t>(GET_UINT32(pc));
131 static MOZ_ALWAYS_INLINE void SET_INT32(jsbytecode* pc, int32_t i) {
132 SET_UINT32(pc, static_cast<uint32_t>(i));
135 static MOZ_ALWAYS_INLINE int32_t GET_JUMP_OFFSET(jsbytecode* pc) {
136 return GET_INT32(pc);
139 static MOZ_ALWAYS_INLINE void SET_JUMP_OFFSET(jsbytecode* pc, int32_t off) {
140 SET_INT32(pc, off);
143 static const unsigned GCTHING_INDEX_LEN = 4;
145 static MOZ_ALWAYS_INLINE js::GCThingIndex GET_GCTHING_INDEX(
146 const jsbytecode* pc) {
147 return js::GCThingIndex(GET_UINT32(pc));
150 static MOZ_ALWAYS_INLINE void SET_GCTHING_INDEX(jsbytecode* pc,
151 js::GCThingIndex index) {
152 SET_UINT32(pc, index.index);
155 // Index limit is determined by SrcNote::FourByteOffsetFlag, see
156 // frontend/BytecodeEmitter.h.
157 static const unsigned INDEX_LIMIT_LOG2 = 31;
158 static const uint32_t INDEX_LIMIT = uint32_t(1) << INDEX_LIMIT_LOG2;
160 static inline jsbytecode ARGC_HI(uint16_t argc) { return UINT16_HI(argc); }
162 static inline jsbytecode ARGC_LO(uint16_t argc) { return UINT16_LO(argc); }
164 static inline uint16_t GET_ARGC(const jsbytecode* pc) { return GET_UINT16(pc); }
166 static const unsigned ARGC_LIMIT = UINT16_LIMIT;
168 static inline uint16_t GET_ARGNO(const jsbytecode* pc) {
169 return GET_UINT16(pc);
172 static inline void SET_ARGNO(jsbytecode* pc, uint16_t argno) {
173 SET_UINT16(pc, argno);
176 static const unsigned ARGNO_LEN = 2;
177 static const unsigned ARGNO_LIMIT = UINT16_LIMIT;
179 static inline uint32_t GET_LOCALNO(const jsbytecode* pc) {
180 return GET_UINT24(pc);
183 static inline void SET_LOCALNO(jsbytecode* pc, uint32_t varno) {
184 SET_UINT24(pc, varno);
187 static const unsigned LOCALNO_LEN = 3;
188 static const unsigned LOCALNO_BITS = 24;
189 static const uint32_t LOCALNO_LIMIT = 1 << LOCALNO_BITS;
191 static inline uint32_t GET_RESUMEINDEX(const jsbytecode* pc) {
192 return GET_UINT24(pc);
195 static inline void SET_RESUMEINDEX(jsbytecode* pc, uint32_t resumeIndex) {
196 SET_UINT24(pc, resumeIndex);
199 static const unsigned ICINDEX_LEN = 4;
201 static inline uint32_t GET_ICINDEX(const jsbytecode* pc) {
202 return GET_UINT32(pc);
205 static inline void SET_ICINDEX(jsbytecode* pc, uint32_t icIndex) {
206 SET_UINT32(pc, icIndex);
209 static inline unsigned LoopHeadDepthHint(jsbytecode* pc) {
210 MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead);
211 return GET_UINT8(pc + 4);
214 static inline void SetLoopHeadDepthHint(jsbytecode* pc, unsigned loopDepth) {
215 MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead);
216 uint8_t data = std::min(loopDepth, unsigned(UINT8_MAX));
217 SET_UINT8(pc + 4, data);
220 static inline bool IsBackedgePC(jsbytecode* pc) {
221 switch (JSOp(*pc)) {
222 case JSOp::Goto:
223 case JSOp::JumpIfTrue:
224 return GET_JUMP_OFFSET(pc) < 0;
225 default:
226 return false;
230 static inline bool IsBackedgeForLoopHead(jsbytecode* pc, jsbytecode* loopHead) {
231 MOZ_ASSERT(JSOp(*loopHead) == JSOp::LoopHead);
232 return IsBackedgePC(pc) && pc + GET_JUMP_OFFSET(pc) == loopHead;
236 * Describes the 'hops' component of a JOF_ENVCOORD opcode.
238 * Note: this component is only 8 bits wide, limiting the maximum number of
239 * scopes between a use and def to roughly 255. This is a pretty small limit but
240 * note that SpiderMonkey's recursive descent parser can only parse about this
241 * many functions before hitting the C-stack recursion limit so this shouldn't
242 * be a significant limitation in practice.
245 static inline uint8_t GET_ENVCOORD_HOPS(jsbytecode* pc) {
246 return GET_UINT8(pc);
249 static inline void SET_ENVCOORD_HOPS(jsbytecode* pc, uint8_t hops) {
250 SET_UINT8(pc, hops);
253 static const unsigned ENVCOORD_HOPS_LEN = 1;
254 static const unsigned ENVCOORD_HOPS_BITS = 8;
255 static const unsigned ENVCOORD_HOPS_LIMIT = 1 << ENVCOORD_HOPS_BITS;
257 /* Describes the 'slot' component of a JOF_ENVCOORD opcode. */
258 static inline uint32_t GET_ENVCOORD_SLOT(const jsbytecode* pc) {
259 return GET_UINT24(pc);
262 static inline void SET_ENVCOORD_SLOT(jsbytecode* pc, uint32_t slot) {
263 SET_UINT24(pc, slot);
266 static const unsigned ENVCOORD_SLOT_LEN = 3;
267 static const unsigned ENVCOORD_SLOT_BITS = 24;
268 static const uint32_t ENVCOORD_SLOT_LIMIT = 1 << ENVCOORD_SLOT_BITS;
270 struct JSCodeSpec {
271 uint8_t length; /* length including opcode byte */
272 int8_t nuses; /* arity, -1 if variadic */
273 int8_t ndefs; /* number of stack results */
274 uint32_t format; /* immediate operand format */
277 namespace js {
279 extern const JSCodeSpec CodeSpecTable[];
281 inline const JSCodeSpec& CodeSpec(JSOp op) {
282 return CodeSpecTable[uint8_t(op)];
285 extern const char* const CodeNameTable[];
287 inline const char* CodeName(JSOp op) { return CodeNameTable[uint8_t(op)]; }
289 /* Shorthand for type from opcode. */
291 static inline uint32_t JOF_OPTYPE(JSOp op) {
292 return JOF_TYPE(CodeSpec(op).format);
295 static inline bool IsJumpOpcode(JSOp op) { return JOF_OPTYPE(op) == JOF_JUMP; }
297 static inline bool BytecodeFallsThrough(JSOp op) {
298 // Note:
299 // * JSOp::Yield/JSOp::Await is considered to fall through, like JSOp::Call.
300 switch (op) {
301 case JSOp::Goto:
302 case JSOp::Default:
303 case JSOp::Return:
304 case JSOp::RetRval:
305 case JSOp::FinalYieldRval:
306 case JSOp::Throw:
307 case JSOp::ThrowWithStack:
308 case JSOp::ThrowMsg:
309 case JSOp::ThrowSetConst:
310 case JSOp::TableSwitch:
311 return false;
312 default:
313 return true;
317 static inline bool BytecodeIsJumpTarget(JSOp op) {
318 switch (op) {
319 case JSOp::JumpTarget:
320 case JSOp::LoopHead:
321 case JSOp::AfterYield:
322 return true;
323 default:
324 return false;
328 // The JSOp argument is superflous, but we are using it to avoid a
329 // store forwarding Bug on some Android phones; see Bug 1833315
330 MOZ_ALWAYS_INLINE unsigned StackUses(JSOp op, jsbytecode* pc) {
331 MOZ_ASSERT(op == JSOp(*pc));
332 int nuses = CodeSpec(op).nuses;
333 if (nuses >= 0) {
334 return nuses;
337 MOZ_ASSERT(nuses == -1);
338 switch (op) {
339 case JSOp::PopN:
340 return GET_UINT16(pc);
341 case JSOp::New:
342 case JSOp::NewContent:
343 case JSOp::SuperCall:
344 return 2 + GET_ARGC(pc) + 1;
345 default:
346 /* stack: fun, this, [argc arguments] */
347 MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallContent ||
348 op == JSOp::CallIgnoresRv || op == JSOp::Eval ||
349 op == JSOp::CallIter || op == JSOp::CallContentIter ||
350 op == JSOp::StrictEval);
351 return 2 + GET_ARGC(pc);
355 MOZ_ALWAYS_INLINE unsigned StackDefs(JSOp op) {
356 int ndefs = CodeSpec(op).ndefs;
357 MOZ_ASSERT(ndefs >= 0);
358 return ndefs;
361 #if defined(DEBUG) || defined(JS_JITSPEW)
363 * Given bytecode address pc in script's main program code, compute the operand
364 * stack depth just before (JSOp) *pc executes. If *pc is not reachable, return
365 * false.
367 extern bool ReconstructStackDepth(JSContext* cx, JSScript* script,
368 jsbytecode* pc, uint32_t* depth,
369 bool* reachablePC);
370 #endif
372 } /* namespace js */
374 #define JSDVG_IGNORE_STACK 0
375 #define JSDVG_SEARCH_STACK 1
377 namespace js {
380 * Find the source expression that resulted in v, and return a newly allocated
381 * C-string containing it. Fall back on v's string conversion (fallback) if we
382 * can't find the bytecode that generated and pushed v on the operand stack.
384 * Search the current stack frame if spindex is JSDVG_SEARCH_STACK. Don't
385 * look for v on the stack if spindex is JSDVG_IGNORE_STACK. Otherwise,
386 * spindex is the negative index of v, measured from cx->fp->sp, or from a
387 * lower frame's sp if cx->fp is native.
389 * The optional argument skipStackHits can be used to skip a hit in the stack
390 * frame. This can be useful in self-hosted code that wants to report value
391 * errors containing decompiled values that are useful for the user, instead of
392 * values used internally by the self-hosted code.
394 * The caller must call JS_free on the result after a successful call.
396 UniqueChars DecompileValueGenerator(JSContext* cx, int spindex, HandleValue v,
397 HandleString fallback,
398 int skipStackHits = 0);
401 * Decompile the formal argument at formalIndex in the nearest non-builtin
402 * stack frame, falling back with converting v to source.
404 JSString* DecompileArgument(JSContext* cx, int formalIndex, HandleValue v);
406 static inline unsigned GetOpLength(JSOp op) {
407 MOZ_ASSERT(uint8_t(op) < JSOP_LIMIT);
408 MOZ_ASSERT(CodeSpec(op).length > 0);
409 return CodeSpec(op).length;
412 static inline unsigned GetBytecodeLength(const jsbytecode* pc) {
413 JSOp op = (JSOp)*pc;
414 return GetOpLength(op);
417 static inline bool BytecodeIsPopped(jsbytecode* pc) {
418 jsbytecode* next = pc + GetBytecodeLength(pc);
419 return JSOp(*next) == JSOp::Pop;
422 extern bool IsValidBytecodeOffset(JSContext* cx, JSScript* script,
423 size_t offset);
425 inline bool IsArgOp(JSOp op) { return JOF_OPTYPE(op) == JOF_QARG; }
427 inline bool IsLocalOp(JSOp op) { return JOF_OPTYPE(op) == JOF_LOCAL; }
429 inline bool IsAliasedVarOp(JSOp op) { return JOF_OPTYPE(op) == JOF_ENVCOORD; }
431 inline bool IsGlobalOp(JSOp op) { return CodeSpec(op).format & JOF_GNAME; }
433 inline bool IsPropertySetOp(JSOp op) {
434 return CodeSpec(op).format & JOF_PROPSET;
437 inline bool IsPropertyInitOp(JSOp op) {
438 return CodeSpec(op).format & JOF_PROPINIT;
441 inline bool IsLooseEqualityOp(JSOp op) {
442 return op == JSOp::Eq || op == JSOp::Ne;
445 inline bool IsStrictEqualityOp(JSOp op) {
446 return op == JSOp::StrictEq || op == JSOp::StrictNe;
449 inline bool IsEqualityOp(JSOp op) {
450 return IsLooseEqualityOp(op) || IsStrictEqualityOp(op);
453 inline bool IsRelationalOp(JSOp op) {
454 return op == JSOp::Lt || op == JSOp::Le || op == JSOp::Gt || op == JSOp::Ge;
457 inline bool IsCheckStrictOp(JSOp op) {
458 return CodeSpec(op).format & JOF_CHECKSTRICT;
461 #ifdef DEBUG
462 inline bool IsCheckSloppyOp(JSOp op) {
463 return CodeSpec(op).format & JOF_CHECKSLOPPY;
465 #endif
467 inline bool IsAtomOp(JSOp op) { return JOF_OPTYPE(op) == JOF_ATOM; }
469 inline bool IsGetPropOp(JSOp op) { return op == JSOp::GetProp; }
471 inline bool IsGetPropPC(const jsbytecode* pc) { return IsGetPropOp(JSOp(*pc)); }
473 inline bool IsHiddenInitOp(JSOp op) {
474 return op == JSOp::InitHiddenProp || op == JSOp::InitHiddenElem ||
475 op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter ||
476 op == JSOp::InitHiddenPropSetter || op == JSOp::InitHiddenElemSetter;
479 inline bool IsLockedInitOp(JSOp op) {
480 return op == JSOp::InitLockedProp || op == JSOp::InitLockedElem;
483 inline bool IsStrictSetPC(jsbytecode* pc) {
484 JSOp op = JSOp(*pc);
485 return op == JSOp::StrictSetProp || op == JSOp::StrictSetName ||
486 op == JSOp::StrictSetGName || op == JSOp::StrictSetElem;
489 inline bool IsSetPropOp(JSOp op) {
490 return op == JSOp::SetProp || op == JSOp::StrictSetProp ||
491 op == JSOp::SetName || op == JSOp::StrictSetName ||
492 op == JSOp::SetGName || op == JSOp::StrictSetGName;
495 inline bool IsSetPropPC(const jsbytecode* pc) { return IsSetPropOp(JSOp(*pc)); }
497 inline bool IsGetElemOp(JSOp op) { return op == JSOp::GetElem; }
499 inline bool IsGetElemPC(const jsbytecode* pc) { return IsGetElemOp(JSOp(*pc)); }
501 inline bool IsSetElemOp(JSOp op) {
502 return op == JSOp::SetElem || op == JSOp::StrictSetElem;
505 inline bool IsSetElemPC(const jsbytecode* pc) { return IsSetElemOp(JSOp(*pc)); }
507 inline bool IsInvokeOp(JSOp op) { return CodeSpec(op).format & JOF_INVOKE; }
509 inline bool IsInvokePC(jsbytecode* pc) { return IsInvokeOp(JSOp(*pc)); }
511 inline bool IsStrictEvalPC(jsbytecode* pc) {
512 JSOp op = JSOp(*pc);
513 return op == JSOp::StrictEval || op == JSOp::StrictSpreadEval;
516 inline bool IsConstructOp(JSOp op) {
517 return CodeSpec(op).format & JOF_CONSTRUCT;
519 inline bool IsConstructPC(const jsbytecode* pc) {
520 return IsConstructOp(JSOp(*pc));
523 inline bool IsSpreadOp(JSOp op) { return CodeSpec(op).format & JOF_SPREAD; }
525 inline bool IsSpreadPC(const jsbytecode* pc) { return IsSpreadOp(JSOp(*pc)); }
527 // Returns true if the specified opcode is for `typeof name` where `name` is
528 // single identifier.
529 inline bool IsTypeOfNameOp(JSOp op) {
530 return op == JSOp::Typeof || op == JSOp::TypeofEq;
533 inline bool OpUsesEnvironmentChain(JSOp op) {
534 return CodeSpec(op).format & JOF_USES_ENV;
537 static inline int32_t GetBytecodeInteger(jsbytecode* pc) {
538 switch (JSOp(*pc)) {
539 case JSOp::Zero:
540 return 0;
541 case JSOp::One:
542 return 1;
543 case JSOp::Uint16:
544 return GET_UINT16(pc);
545 case JSOp::Uint24:
546 return GET_UINT24(pc);
547 case JSOp::Int8:
548 return GET_INT8(pc);
549 case JSOp::Int32:
550 return GET_INT32(pc);
551 default:
552 MOZ_CRASH("Bad op");
556 inline bool BytecodeOpHasIC(JSOp op) { return CodeSpec(op).format & JOF_IC; }
558 inline void GetCheckPrivateFieldOperands(jsbytecode* pc,
559 ThrowCondition* throwCondition,
560 ThrowMsgKind* throwKind) {
561 static_assert(sizeof(ThrowCondition) == sizeof(uint8_t));
562 static_assert(sizeof(ThrowMsgKind) == sizeof(uint8_t));
564 MOZ_ASSERT(JSOp(*pc) == JSOp::CheckPrivateField);
565 uint8_t throwConditionByte = GET_UINT8(pc);
566 uint8_t throwKindByte = GET_UINT8(pc + 1);
568 *throwCondition = static_cast<ThrowCondition>(throwConditionByte);
569 *throwKind = static_cast<ThrowMsgKind>(throwKindByte);
571 MOZ_ASSERT(*throwCondition == ThrowCondition::ThrowHas ||
572 *throwCondition == ThrowCondition::ThrowHasNot ||
573 *throwCondition == ThrowCondition::OnlyCheckRhs);
575 MOZ_ASSERT(*throwKind == ThrowMsgKind::PrivateDoubleInit ||
576 *throwKind == ThrowMsgKind::PrivateBrandDoubleInit ||
577 *throwKind == ThrowMsgKind::MissingPrivateOnGet ||
578 *throwKind == ThrowMsgKind::MissingPrivateOnSet);
581 // Return true iff the combination of the ThrowCondition and hasOwn result
582 // will throw an exception.
583 static inline bool CheckPrivateFieldWillThrow(ThrowCondition condition,
584 bool hasOwn) {
585 if ((condition == ThrowCondition::ThrowHasNot && !hasOwn) ||
586 (condition == ThrowCondition::ThrowHas && hasOwn)) {
587 // Met a throw condition.
588 return true;
591 return false;
595 * Counts accumulated for a single opcode in a script. The counts tracked vary
596 * between opcodes, and this structure ensures that counts are accessed in a
597 * coherent fashion.
599 class PCCounts {
601 * Offset of the pc inside the script. This fields is used to lookup opcode
602 * which have annotations.
604 size_t pcOffset_;
607 * Record the number of execution of one instruction, or the number of
608 * throws executed.
610 uint64_t numExec_;
612 public:
613 explicit PCCounts(size_t off) : pcOffset_(off), numExec_(0) {}
615 size_t pcOffset() const { return pcOffset_; }
617 // Used for sorting and searching.
618 bool operator<(const PCCounts& rhs) const {
619 return pcOffset_ < rhs.pcOffset_;
622 uint64_t& numExec() { return numExec_; }
623 uint64_t numExec() const { return numExec_; }
625 static const char numExecName[];
628 static inline jsbytecode* GetNextPc(jsbytecode* pc) {
629 return pc + GetBytecodeLength(pc);
632 inline GeneratorResumeKind IntToResumeKind(int32_t value) {
633 MOZ_ASSERT(uint32_t(value) <= uint32_t(GeneratorResumeKind::Return));
634 return static_cast<GeneratorResumeKind>(value);
637 inline GeneratorResumeKind ResumeKindFromPC(jsbytecode* pc) {
638 MOZ_ASSERT(JSOp(*pc) == JSOp::ResumeKind);
639 return IntToResumeKind(GET_UINT8(pc));
642 #if defined(DEBUG) || defined(JS_JITSPEW)
644 enum class DisassembleSkeptically { No, Yes };
647 * Disassemblers, for debugging only.
649 [[nodiscard]] extern bool Disassemble(
650 JSContext* cx, JS::Handle<JSScript*> script, bool lines, StringPrinter* sp,
651 DisassembleSkeptically skeptically = DisassembleSkeptically::No);
653 unsigned Disassemble1(JSContext* cx, JS::Handle<JSScript*> script,
654 jsbytecode* pc, unsigned loc, bool lines,
655 StringPrinter* sp);
657 extern UniqueChars ToDisassemblySource(JSContext* cx, HandleValue v);
659 #endif
661 [[nodiscard]] extern bool DumpRealmPCCounts(JSContext* cx);
663 } // namespace js
665 #endif /* vm_BytecodeUtil_h */