Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/vm/./../../../../js/src/vm/BytecodeUtil.cpp
Warning:line 1478, column 7
Value stored to 'pc2' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_vm2.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/vm -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/vm -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D USE_LIBZ_RS -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src -I /root/firefox-clang/js/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_js_src_vm2.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/*
6 * JS bytecode descriptors, disassemblers, and (expression) decompilers.
7 */
8
9#include "vm/BytecodeUtil-inl.h"
10
11#define __STDC_FORMAT_MACROS
12
13#include "mozilla/Maybe.h"
14#include "mozilla/ReverseIterator.h"
15#include "mozilla/Sprintf.h"
16
17#include <inttypes.h>
18#include <stdio.h>
19#include <string.h>
20
21#include "jsapi.h"
22#include "jstypes.h"
23
24#include "builtin/ModuleObject.h"
25#include "gc/PublicIterators.h"
26#include "jit/IonScript.h" // IonBlockCounts
27#include "js/CharacterEncoding.h"
28#include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin
29#include "js/experimental/CodeCoverage.h"
30#include "js/experimental/PCCountProfiling.h" // JS::{Start,Stop}PCCountProfiling, JS::PurgePCCounts, JS::GetPCCountScript{Count,Summary,Contents}
31#include "js/friend/DumpFunctions.h" // js::DumpPC, js::DumpScript
32#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
33#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
34#include "js/Printer.h"
35#include "js/Printf.h"
36#include "js/Symbol.h"
37#include "util/DifferentialTesting.h"
38#include "util/Identifier.h" // IsIdentifier
39#include "util/Memory.h"
40#include "util/Text.h"
41#include "vm/BuiltinObjectKind.h"
42#include "vm/BytecodeIterator.h" // for AllBytecodesIterable
43#include "vm/BytecodeLocation.h"
44#include "vm/CodeCoverage.h"
45#include "vm/ConstantCompareOperand.h"
46#include "vm/EnvironmentObject.h"
47#include "vm/FrameIter.h" // js::{,Script}FrameIter
48#include "vm/JSAtomUtils.h" // AtomToPrintableString, Atomize
49#include "vm/JSContext.h"
50#include "vm/JSFunction.h"
51#include "vm/JSObject.h"
52#include "vm/JSONPrinter.h"
53#include "vm/JSScript.h"
54#include "vm/Opcodes.h"
55#include "vm/Realm.h"
56#include "vm/Shape.h"
57#include "vm/ToSource.h" // js::ValueToSource
58#include "vm/TypeofEqOperand.h" // TypeofEqOperand
59
60#include "gc/GC-inl.h"
61#include "vm/BytecodeIterator-inl.h"
62#include "vm/JSContext-inl.h"
63#include "vm/JSScript-inl.h"
64#include "vm/Realm-inl.h"
65
66using namespace js;
67
68/*
69 * Index limit must stay within 32 bits.
70 */
71static_assert(sizeof(uint32_t) * CHAR_BIT8 >= INDEX_LIMIT_LOG2 + 1);
72
73const JSCodeSpec js::CodeSpecTable[] = {
74#define MAKE_CODESPEC(op, op_snake, token, length, nuses, ndefs, format) \
75 {length, nuses, ndefs, format},
76 FOR_EACH_OPCODE(MAKE_CODESPEC)MAKE_CODESPEC(Undefined, undefined, "", 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(Null, null, "null", 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(False, false_
, "false", 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(True, true_, "true"
, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(Int32, int32, __null, 5, 0
, 1, JOF_INT32) MAKE_CODESPEC(Zero, zero, "0", 1, 0, 1, JOF_BYTE
) MAKE_CODESPEC(One, one, "1", 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(Int8, int8, __null, 2, 0, 1, JOF_INT8) MAKE_CODESPEC(Uint16,
uint16, __null, 3, 0, 1, JOF_UINT16) MAKE_CODESPEC(Uint24, uint24
, __null, 4, 0, 1, JOF_UINT24) MAKE_CODESPEC(Double, double_,
__null, 9, 0, 1, JOF_DOUBLE) MAKE_CODESPEC(BigInt, big_int, __null
, 5, 0, 1, JOF_BIGINT) MAKE_CODESPEC(String, string, __null, 5
, 0, 1, JOF_STRING) MAKE_CODESPEC(Symbol, symbol, __null, 2, 0
, 1, JOF_UINT8) MAKE_CODESPEC(Void, void_, __null, 1, 1, 1, JOF_BYTE
) MAKE_CODESPEC(Typeof, typeof_, __null, 1, 1, 1, JOF_BYTE|JOF_IC
) MAKE_CODESPEC(TypeofExpr, typeof_expr, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) MAKE_CODESPEC(TypeofEq, typeof_eq, __null, 2, 1, 1, JOF_UINT8
|JOF_IC) MAKE_CODESPEC(Pos, pos, "+ ", 1, 1, 1, JOF_BYTE|JOF_IC
) MAKE_CODESPEC(Neg, neg, "- ", 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC
(BitNot, bit_not, "~", 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC
(Not, not_, "!", 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(BitOr
, bit_or, "|", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(BitXor
, bit_xor, "^", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(BitAnd
, bit_and, "&", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Eq
, eq, "==", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Ne, ne, "!="
, 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(StrictEq, strict_eq
, "===", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(StrictNe, strict_ne
, "!==", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(StrictConstantEq
, strict_constant_eq, __null, 3, 1, 1, JOF_UINT16) MAKE_CODESPEC
(StrictConstantNe, strict_constant_ne, __null, 3, 1, 1, JOF_UINT16
) MAKE_CODESPEC(Lt, lt, "<", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC
(Gt, gt, ">", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Le, le
, "<=", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Ge, ge, ">="
, 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Instanceof, instanceof
, "instanceof", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(In, in_
, "in", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Lsh, lsh, "<<"
, 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Rsh, rsh, ">>"
, 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Ursh, ursh, ">>>"
, 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Add, add, "+", 1, 2
, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Sub, sub, "-", 1, 2, 1, JOF_BYTE
|JOF_IC) MAKE_CODESPEC(Inc, inc, __null, 1, 1, 1, JOF_BYTE|JOF_IC
) MAKE_CODESPEC(Dec, dec, __null, 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC
(Mul, mul, "*", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Div, div
, "/", 1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Mod, mod, "%",
1, 2, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(Pow, pow, "**", 1, 2
, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(NopIsAssignOp, nop_is_assign_op
, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC(ToPropertyKey, to_property_key
, __null, 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(ToNumeric, to_numeric
, __null, 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(ToString, to_string
, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(IsNullOrUndefined,
is_null_or_undefined, __null, 1, 1, 2, JOF_BYTE) MAKE_CODESPEC
(GlobalThis, global_this, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(NonSyntacticGlobalThis, non_syntactic_global_this, __null, 1
, 0, 1, JOF_BYTE) MAKE_CODESPEC(NewTarget, new_target, __null
, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(DynamicImport, dynamic_import
, __null, 2, 2, 1, JOF_UINT8) MAKE_CODESPEC(ImportMeta, import_meta
, __null, 1, 0, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(NewInit, new_init
, __null, 2, 0, 1, JOF_UINT8|JOF_IC) MAKE_CODESPEC(NewObject,
new_object, __null, 5, 0, 1, JOF_SHAPE|JOF_IC) MAKE_CODESPEC
(Object, object, __null, 5, 0, 1, JOF_OBJECT) MAKE_CODESPEC(ObjWithProto
, obj_with_proto, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(InitProp
, init_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC) MAKE_CODESPEC
(InitHiddenProp, init_hidden_prop, __null, 5, 2, 1, JOF_ATOM|
JOF_PROPINIT|JOF_IC) MAKE_CODESPEC(InitLockedProp, init_locked_prop
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC) MAKE_CODESPEC
(InitElem, init_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|
JOF_IC) MAKE_CODESPEC(InitHiddenElem, init_hidden_elem, __null
, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC) MAKE_CODESPEC(InitLockedElem
, init_locked_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC
) MAKE_CODESPEC(InitPropGetter, init_prop_getter, __null, 5, 2
, 1, JOF_ATOM|JOF_PROPINIT) MAKE_CODESPEC(InitHiddenPropGetter
, init_hidden_prop_getter, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT
) MAKE_CODESPEC(InitElemGetter, init_elem_getter, __null, 1, 3
, 1, JOF_BYTE|JOF_PROPINIT) MAKE_CODESPEC(InitHiddenElemGetter
, init_hidden_elem_getter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT
) MAKE_CODESPEC(InitPropSetter, init_prop_setter, __null, 5, 2
, 1, JOF_ATOM|JOF_PROPINIT) MAKE_CODESPEC(InitHiddenPropSetter
, init_hidden_prop_setter, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT
) MAKE_CODESPEC(InitElemSetter, init_elem_setter, __null, 1, 3
, 1, JOF_BYTE|JOF_PROPINIT) MAKE_CODESPEC(InitHiddenElemSetter
, init_hidden_elem_setter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT
) MAKE_CODESPEC(GetProp, get_prop, __null, 5, 1, 1, JOF_ATOM|
JOF_IC) MAKE_CODESPEC(GetElem, get_elem, __null, 1, 2, 1, JOF_BYTE
|JOF_IC) MAKE_CODESPEC(SetProp, set_prop, __null, 5, 2, 1, JOF_ATOM
|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) MAKE_CODESPEC(StrictSetProp
, strict_set_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT
|JOF_IC) MAKE_CODESPEC(SetElem, set_elem, __null, 1, 3, 1, JOF_BYTE
|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) MAKE_CODESPEC(StrictSetElem
, strict_set_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSTRICT
|JOF_IC) MAKE_CODESPEC(DelProp, del_prop, __null, 5, 1, 1, JOF_ATOM
|JOF_CHECKSLOPPY) MAKE_CODESPEC(StrictDelProp, strict_del_prop
, __null, 5, 1, 1, JOF_ATOM|JOF_CHECKSTRICT) MAKE_CODESPEC(DelElem
, del_elem, __null, 1, 2, 1, JOF_BYTE|JOF_CHECKSLOPPY) MAKE_CODESPEC
(StrictDelElem, strict_del_elem, __null, 1, 2, 1, JOF_BYTE|JOF_CHECKSTRICT
) MAKE_CODESPEC(HasOwn, has_own, __null, 1, 2, 1, JOF_BYTE|JOF_IC
) MAKE_CODESPEC(CheckPrivateField, check_private_field, __null
, 3, 2, 3, JOF_TWO_UINT8|JOF_CHECKSTRICT|JOF_IC) MAKE_CODESPEC
(NewPrivateName, new_private_name, __null, 5, 0, 1, JOF_ATOM)
MAKE_CODESPEC(SuperBase, super_base, __null, 1, 1, 1, JOF_BYTE
) MAKE_CODESPEC(GetPropSuper, get_prop_super, __null, 5, 2, 1
, JOF_ATOM|JOF_IC) MAKE_CODESPEC(GetElemSuper, get_elem_super
, __null, 1, 3, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(SetPropSuper
, set_prop_super, __null, 5, 3, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY
) MAKE_CODESPEC(StrictSetPropSuper, strict_set_prop_super, __null
, 5, 3, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT) MAKE_CODESPEC
(SetElemSuper, set_elem_super, __null, 1, 4, 1, JOF_BYTE|JOF_PROPSET
|JOF_CHECKSLOPPY) MAKE_CODESPEC(StrictSetElemSuper, strict_set_elem_super
, __null, 1, 4, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSTRICT) MAKE_CODESPEC
(Iter, iter, __null, 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC(
MoreIter, more_iter, __null, 1, 1, 2, JOF_BYTE) MAKE_CODESPEC
(IsNoIter, is_no_iter, __null, 1, 1, 2, JOF_BYTE) MAKE_CODESPEC
(EndIter, end_iter, __null, 1, 2, 0, JOF_BYTE) MAKE_CODESPEC(
CloseIter, close_iter, __null, 2, 1, 0, JOF_UINT8|JOF_IC) MAKE_CODESPEC
(OptimizeGetIterator, optimize_get_iterator, __null, 1, 1, 1,
JOF_BYTE|JOF_IC) MAKE_CODESPEC(CheckIsObj, check_is_obj, __null
, 2, 1, 1, JOF_UINT8) MAKE_CODESPEC(CheckObjCoercible, check_obj_coercible
, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(ToAsyncIter, to_async_iter
, __null, 1, 2, 1, JOF_BYTE) MAKE_CODESPEC(MutateProto, mutate_proto
, __null, 1, 2, 1, JOF_BYTE) MAKE_CODESPEC(NewArray, new_array
, __null, 5, 0, 1, JOF_UINT32|JOF_IC) MAKE_CODESPEC(InitElemArray
, init_elem_array, __null, 5, 2, 1, JOF_UINT32|JOF_PROPINIT) MAKE_CODESPEC
(InitElemInc, init_elem_inc, __null, 1, 3, 2, JOF_BYTE|JOF_PROPINIT
|JOF_IC) MAKE_CODESPEC(Hole, hole, __null, 1, 0, 1, JOF_BYTE)
MAKE_CODESPEC(RegExp, reg_exp, __null, 5, 0, 1, JOF_REGEXP) MAKE_CODESPEC
(Lambda, lambda, __null, 5, 0, 1, JOF_OBJECT|JOF_USES_ENV|JOF_IC
) MAKE_CODESPEC(SetFunName, set_fun_name, __null, 2, 2, 1, JOF_UINT8
) MAKE_CODESPEC(InitHomeObject, init_home_object, __null, 1, 2
, 1, JOF_BYTE) MAKE_CODESPEC(CheckClassHeritage, check_class_heritage
, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(FunWithProto, fun_with_proto
, __null, 5, 1, 1, JOF_OBJECT|JOF_USES_ENV) MAKE_CODESPEC(BuiltinObject
, builtin_object, __null, 2, 0, 1, JOF_UINT8|JOF_IC) MAKE_CODESPEC
(Call, call, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) MAKE_CODESPEC
(CallContent, call_content, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_IC) MAKE_CODESPEC(CallIter, call_iter, __null, 3, -1, 1,
JOF_ARGC|JOF_INVOKE|JOF_IC) MAKE_CODESPEC(CallContentIter, call_content_iter
, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) MAKE_CODESPEC
(CallIgnoresRv, call_ignores_rv, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_IC) MAKE_CODESPEC(SpreadCall, spread_call, __null, 1, 3,
1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_IC) MAKE_CODESPEC(OptimizeSpreadCall
, optimize_spread_call, __null, 1, 1, 1, JOF_BYTE|JOF_IC) MAKE_CODESPEC
(Eval, eval, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CHECKSLOPPY
|JOF_IC) MAKE_CODESPEC(SpreadEval, spread_eval, __null, 1, 3,
1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSLOPPY|JOF_IC) MAKE_CODESPEC
(StrictEval, strict_eval, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_CHECKSTRICT|JOF_IC) MAKE_CODESPEC(StrictSpreadEval, strict_spread_eval
, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSTRICT
|JOF_IC) MAKE_CODESPEC(ImplicitThis, implicit_this, "", 1, 1,
1, JOF_BYTE) MAKE_CODESPEC(CallSiteObj, call_site_obj, __null
, 5, 0, 1, JOF_OBJECT) MAKE_CODESPEC(IsConstructing, is_constructing
, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(New, new_, __null,
3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) MAKE_CODESPEC
(NewContent, new_content, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_CONSTRUCT|JOF_IC) MAKE_CODESPEC(SuperCall, super_call, __null
, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) MAKE_CODESPEC
(SpreadNew, spread_new, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE|
JOF_CONSTRUCT|JOF_SPREAD|JOF_IC) MAKE_CODESPEC(SpreadSuperCall
, spread_super_call, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_CONSTRUCT
|JOF_SPREAD|JOF_IC) MAKE_CODESPEC(SuperFun, super_fun, __null
, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(CheckThisReinit, check_this_reinit
, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(Generator, generator
, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV) MAKE_CODESPEC(InitialYield
, initial_yield, __null, 4, 1, 2, JOF_RESUMEINDEX) MAKE_CODESPEC
(AfterYield, after_yield, __null, 5, 0, 0, JOF_ICINDEX) MAKE_CODESPEC
(FinalYieldRval, final_yield_rval, __null, 1, 1, 0, JOF_BYTE)
MAKE_CODESPEC(Yield, yield, __null, 4, 2, 2, JOF_RESUMEINDEX
) MAKE_CODESPEC(AsyncAwait, async_await, __null, 1, 2, 1, JOF_BYTE
) MAKE_CODESPEC(AsyncResolve, async_resolve, __null, 1, 2, 1,
JOF_BYTE) MAKE_CODESPEC(AsyncReject, async_reject, __null, 1
, 3, 1, JOF_BYTE) MAKE_CODESPEC(Await, await, __null, 4, 2, 2
, JOF_RESUMEINDEX) MAKE_CODESPEC(CanSkipAwait, can_skip_await
, __null, 1, 1, 2, JOF_BYTE) MAKE_CODESPEC(MaybeExtractAwaitValue
, maybe_extract_await_value, __null, 1, 2, 2, JOF_BYTE) MAKE_CODESPEC
(ResumeKind, resume_kind, __null, 2, 0, 1, JOF_UINT8) MAKE_CODESPEC
(Resume, resume, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE) MAKE_CODESPEC
(JumpTarget, jump_target, __null, 5, 0, 0, JOF_ICINDEX) MAKE_CODESPEC
(LoopHead, loop_head, __null, 6, 0, 0, JOF_LOOPHEAD) MAKE_CODESPEC
(Goto, goto_, __null, 5, 0, 0, JOF_JUMP) MAKE_CODESPEC(JumpIfFalse
, jump_if_false, __null, 5, 1, 0, JOF_JUMP|JOF_IC) MAKE_CODESPEC
(JumpIfTrue, jump_if_true, __null, 5, 1, 0, JOF_JUMP|JOF_IC) MAKE_CODESPEC
(And, and_, __null, 5, 1, 1, JOF_JUMP|JOF_IC) MAKE_CODESPEC(Or
, or_, __null, 5, 1, 1, JOF_JUMP|JOF_IC) MAKE_CODESPEC(Coalesce
, coalesce, __null, 5, 1, 1, JOF_JUMP) MAKE_CODESPEC(Case, case_
, __null, 5, 2, 1, JOF_JUMP) MAKE_CODESPEC(Default, default_,
__null, 5, 1, 0, JOF_JUMP) MAKE_CODESPEC(TableSwitch, table_switch
, __null, 16, 1, 0, JOF_TABLESWITCH) MAKE_CODESPEC(Return, return_
, __null, 1, 1, 0, JOF_BYTE) MAKE_CODESPEC(GetRval, get_rval,
__null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(SetRval, set_rval, __null
, 1, 1, 0, JOF_BYTE) MAKE_CODESPEC(RetRval, ret_rval, __null,
1, 0, 0, JOF_BYTE) MAKE_CODESPEC(CheckReturn, check_return, __null
, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC(Throw, throw_, __null, 1, 1
, 0, JOF_BYTE) MAKE_CODESPEC(ThrowWithStack, throw_with_stack
, __null, 1, 2, 0, JOF_BYTE) MAKE_CODESPEC(CreateSuppressedError
, create_suppressed_error, __null, 1, 2, 1, JOF_BYTE) MAKE_CODESPEC
(ThrowMsg, throw_msg, __null, 2, 0, 0, JOF_UINT8) MAKE_CODESPEC
(ThrowSetConst, throw_set_const, __null, 5, 0, 0, JOF_ATOM) MAKE_CODESPEC
(Try, try_, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC(TryDestructuring
, try_destructuring, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC
(Exception, exception, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(ExceptionAndStack, exception_and_stack, __null, 1, 0, 2, JOF_BYTE
) MAKE_CODESPEC(Finally, finally, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC
(Uninitialized, uninitialized, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(InitLexical, init_lexical, __null, 4, 1, 1, JOF_LOCAL) MAKE_CODESPEC
(InitGLexical, init_g_lexical, __null, 5, 1, 1, JOF_ATOM|JOF_PROPINIT
|JOF_GNAME|JOF_IC) MAKE_CODESPEC(InitAliasedLexical, init_aliased_lexical
, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPINIT) MAKE_CODESPEC(CheckLexical
, check_lexical, __null, 4, 1, 1, JOF_LOCAL) MAKE_CODESPEC(CheckAliasedLexical
, check_aliased_lexical, __null, 6, 1, 1, JOF_ENVCOORD) MAKE_CODESPEC
(CheckThis, check_this, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC
(BindUnqualifiedGName, bind_unqualified_g_name, __null, 5, 0,
1, JOF_ATOM|JOF_GNAME|JOF_IC) MAKE_CODESPEC(BindUnqualifiedName
, bind_unqualified_name, __null, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV
) MAKE_CODESPEC(BindName, bind_name, __null, 5, 0, 1, JOF_ATOM
|JOF_IC|JOF_USES_ENV) MAKE_CODESPEC(GetName, get_name, __null
, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) MAKE_CODESPEC(GetGName
, get_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME|JOF_IC) MAKE_CODESPEC
(GetArg, get_arg, __null, 3, 0, 1, JOF_QARG) MAKE_CODESPEC(GetFrameArg
, get_frame_arg, __null, 3, 0, 1, JOF_QARG) MAKE_CODESPEC(GetLocal
, get_local, __null, 4, 0, 1, JOF_LOCAL) MAKE_CODESPEC(ArgumentsLength
, arguments_length, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC(
GetActualArg, get_actual_arg, __null, 1, 1, 1, JOF_BYTE) MAKE_CODESPEC
(GetAliasedVar, get_aliased_var, __null, 6, 0, 1, JOF_ENVCOORD
|JOF_USES_ENV) MAKE_CODESPEC(GetAliasedDebugVar, get_aliased_debug_var
, __null, 6, 0, 1, JOF_DEBUGCOORD) MAKE_CODESPEC(GetImport, get_import
, __null, 5, 0, 1, JOF_ATOM|JOF_IC) MAKE_CODESPEC(GetBoundName
, get_bound_name, __null, 5, 1, 1, JOF_ATOM|JOF_IC) MAKE_CODESPEC
(GetIntrinsic, get_intrinsic, __null, 5, 0, 1, JOF_ATOM|JOF_IC
) MAKE_CODESPEC(Callee, callee, __null, 1, 0, 1, JOF_BYTE) MAKE_CODESPEC
(EnvCallee, env_callee, __null, 3, 0, 1, JOF_UINT16) MAKE_CODESPEC
(SetName, set_name, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY
|JOF_IC|JOF_USES_ENV) MAKE_CODESPEC(StrictSetName, strict_set_name
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC
|JOF_USES_ENV) MAKE_CODESPEC(SetGName, set_g_name, __null, 5,
2, 1, JOF_ATOM|JOF_PROPSET|JOF_GNAME|JOF_CHECKSLOPPY|JOF_IC)
MAKE_CODESPEC(StrictSetGName, strict_set_g_name, __null, 5, 2
, 1, JOF_ATOM|JOF_PROPSET|JOF_GNAME|JOF_CHECKSTRICT|JOF_IC) MAKE_CODESPEC
(SetArg, set_arg, __null, 3, 1, 1, JOF_QARG) MAKE_CODESPEC(SetLocal
, set_local, __null, 4, 1, 1, JOF_LOCAL) MAKE_CODESPEC(SetAliasedVar
, set_aliased_var, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPSET|
JOF_USES_ENV) MAKE_CODESPEC(SetIntrinsic, set_intrinsic, __null
, 5, 1, 1, JOF_ATOM) MAKE_CODESPEC(PushLexicalEnv, push_lexical_env
, __null, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) MAKE_CODESPEC(PopLexicalEnv
, pop_lexical_env, __null, 1, 0, 0, JOF_BYTE|JOF_USES_ENV) MAKE_CODESPEC
(DebugLeaveLexicalEnv, debug_leave_lexical_env, __null, 1, 0,
0, JOF_BYTE) MAKE_CODESPEC(RecreateLexicalEnv, recreate_lexical_env
, __null, 5, 0, 0, JOF_SCOPE) MAKE_CODESPEC(FreshenLexicalEnv
, freshen_lexical_env, __null, 5, 0, 0, JOF_SCOPE) MAKE_CODESPEC
(PushClassBodyEnv, push_class_body_env, __null, 5, 0, 0, JOF_SCOPE
) MAKE_CODESPEC(PushVarEnv, push_var_env, __null, 5, 0, 0, JOF_SCOPE
|JOF_USES_ENV) MAKE_CODESPEC(EnterWith, enter_with, __null, 5
, 1, 0, JOF_SCOPE) MAKE_CODESPEC(LeaveWith, leave_with, __null
, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC(AddDisposable, add_disposable
, __null, 2, 3, 0, JOF_UINT8|JOF_USES_ENV) MAKE_CODESPEC(TakeDisposeCapability
, take_dispose_capability, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV
) MAKE_CODESPEC(BindVar, bind_var, __null, 1, 0, 1, JOF_BYTE|
JOF_USES_ENV) MAKE_CODESPEC(GlobalOrEvalDeclInstantiation, global_or_eval_decl_instantiation
, __null, 5, 0, 0, JOF_GCTHING|JOF_USES_ENV) MAKE_CODESPEC(DelName
, del_name, __null, 5, 0, 1, JOF_ATOM|JOF_CHECKSLOPPY|JOF_USES_ENV
) MAKE_CODESPEC(Arguments, arguments, __null, 1, 0, 1, JOF_BYTE
|JOF_USES_ENV) MAKE_CODESPEC(Rest, rest, __null, 1, 0, 1, JOF_BYTE
|JOF_IC) MAKE_CODESPEC(FunctionThis, function_this, __null, 1
, 0, 1, JOF_BYTE) MAKE_CODESPEC(Pop, pop, __null, 1, 1, 0, JOF_BYTE
) MAKE_CODESPEC(PopN, pop_n, __null, 3, -1, 0, JOF_UINT16) MAKE_CODESPEC
(Dup, dup, __null, 1, 1, 2, JOF_BYTE) MAKE_CODESPEC(Dup2, dup2
, __null, 1, 2, 4, JOF_BYTE) MAKE_CODESPEC(DupAt, dup_at, __null
, 4, 0, 1, JOF_UINT24) MAKE_CODESPEC(Swap, swap, __null, 1, 2
, 2, JOF_BYTE) MAKE_CODESPEC(Pick, pick, __null, 2, 0, 0, JOF_UINT8
) MAKE_CODESPEC(Unpick, unpick, __null, 2, 0, 0, JOF_UINT8) MAKE_CODESPEC
(Nop, nop, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC(Lineno, lineno
, __null, 5, 0, 0, JOF_UINT32) MAKE_CODESPEC(NopDestructuring
, nop_destructuring, __null, 1, 0, 0, JOF_BYTE) MAKE_CODESPEC
(DebugCheckSelfHosted, debug_check_self_hosted, __null, 1, 1,
1, JOF_BYTE) MAKE_CODESPEC(Debugger, debugger, __null, 1, 0,
0, JOF_BYTE)
77#undef MAKE_CODESPEC
78};
79
80/*
81 * Each element of the array is either a source literal associated with JS
82 * bytecode or null.
83 */
84static const char* const CodeToken[] = {
85#define TOKEN(op, op_snake, token, ...) token,
86 FOR_EACH_OPCODE(TOKEN)TOKEN(Undefined, undefined, "", 1, 0, 1, JOF_BYTE) TOKEN(Null
, null, "null", 1, 0, 1, JOF_BYTE) TOKEN(False, false_, "false"
, 1, 0, 1, JOF_BYTE) TOKEN(True, true_, "true", 1, 0, 1, JOF_BYTE
) TOKEN(Int32, int32, __null, 5, 0, 1, JOF_INT32) TOKEN(Zero,
zero, "0", 1, 0, 1, JOF_BYTE) TOKEN(One, one, "1", 1, 0, 1, JOF_BYTE
) TOKEN(Int8, int8, __null, 2, 0, 1, JOF_INT8) TOKEN(Uint16, uint16
, __null, 3, 0, 1, JOF_UINT16) TOKEN(Uint24, uint24, __null, 4
, 0, 1, JOF_UINT24) TOKEN(Double, double_, __null, 9, 0, 1, JOF_DOUBLE
) TOKEN(BigInt, big_int, __null, 5, 0, 1, JOF_BIGINT) TOKEN(String
, string, __null, 5, 0, 1, JOF_STRING) TOKEN(Symbol, symbol, __null
, 2, 0, 1, JOF_UINT8) TOKEN(Void, void_, __null, 1, 1, 1, JOF_BYTE
) TOKEN(Typeof, typeof_, __null, 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN
(TypeofExpr, typeof_expr, __null, 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN
(TypeofEq, typeof_eq, __null, 2, 1, 1, JOF_UINT8|JOF_IC) TOKEN
(Pos, pos, "+ ", 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN(Neg, neg, "- "
, 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN(BitNot, bit_not, "~", 1, 1,
1, JOF_BYTE|JOF_IC) TOKEN(Not, not_, "!", 1, 1, 1, JOF_BYTE|
JOF_IC) TOKEN(BitOr, bit_or, "|", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN
(BitXor, bit_xor, "^", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(BitAnd
, bit_and, "&", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Eq, eq, "=="
, 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Ne, ne, "!=", 1, 2, 1, JOF_BYTE
|JOF_IC) TOKEN(StrictEq, strict_eq, "===", 1, 2, 1, JOF_BYTE|
JOF_IC) TOKEN(StrictNe, strict_ne, "!==", 1, 2, 1, JOF_BYTE|JOF_IC
) TOKEN(StrictConstantEq, strict_constant_eq, __null, 3, 1, 1
, JOF_UINT16) TOKEN(StrictConstantNe, strict_constant_ne, __null
, 3, 1, 1, JOF_UINT16) TOKEN(Lt, lt, "<", 1, 2, 1, JOF_BYTE
|JOF_IC) TOKEN(Gt, gt, ">", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN
(Le, le, "<=", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Ge, ge, ">="
, 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Instanceof, instanceof, "instanceof"
, 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(In, in_, "in", 1, 2, 1, JOF_BYTE
|JOF_IC) TOKEN(Lsh, lsh, "<<", 1, 2, 1, JOF_BYTE|JOF_IC
) TOKEN(Rsh, rsh, ">>", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN
(Ursh, ursh, ">>>", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(
Add, add, "+", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Sub, sub, "-",
1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Inc, inc, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) TOKEN(Dec, dec, __null, 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN
(Mul, mul, "*", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Div, div, "/"
, 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(Mod, mod, "%", 1, 2, 1, JOF_BYTE
|JOF_IC) TOKEN(Pow, pow, "**", 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN
(NopIsAssignOp, nop_is_assign_op, __null, 1, 0, 0, JOF_BYTE) TOKEN
(ToPropertyKey, to_property_key, __null, 1, 1, 1, JOF_BYTE|JOF_IC
) TOKEN(ToNumeric, to_numeric, __null, 1, 1, 1, JOF_BYTE|JOF_IC
) TOKEN(ToString, to_string, __null, 1, 1, 1, JOF_BYTE) TOKEN
(IsNullOrUndefined, is_null_or_undefined, __null, 1, 1, 2, JOF_BYTE
) TOKEN(GlobalThis, global_this, __null, 1, 0, 1, JOF_BYTE) TOKEN
(NonSyntacticGlobalThis, non_syntactic_global_this, __null, 1
, 0, 1, JOF_BYTE) TOKEN(NewTarget, new_target, __null, 1, 0, 1
, JOF_BYTE) TOKEN(DynamicImport, dynamic_import, __null, 2, 2
, 1, JOF_UINT8) TOKEN(ImportMeta, import_meta, __null, 1, 0, 1
, JOF_BYTE|JOF_IC) TOKEN(NewInit, new_init, __null, 2, 0, 1, JOF_UINT8
|JOF_IC) TOKEN(NewObject, new_object, __null, 5, 0, 1, JOF_SHAPE
|JOF_IC) TOKEN(Object, object, __null, 5, 0, 1, JOF_OBJECT) TOKEN
(ObjWithProto, obj_with_proto, __null, 1, 1, 1, JOF_BYTE) TOKEN
(InitProp, init_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|
JOF_IC) TOKEN(InitHiddenProp, init_hidden_prop, __null, 5, 2,
1, JOF_ATOM|JOF_PROPINIT|JOF_IC) TOKEN(InitLockedProp, init_locked_prop
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC) TOKEN(InitElem
, init_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC) TOKEN
(InitHiddenElem, init_hidden_elem, __null, 1, 3, 1, JOF_BYTE|
JOF_PROPINIT|JOF_IC) TOKEN(InitLockedElem, init_locked_elem, __null
, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC) TOKEN(InitPropGetter
, init_prop_getter, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT) TOKEN
(InitHiddenPropGetter, init_hidden_prop_getter, __null, 5, 2,
1, JOF_ATOM|JOF_PROPINIT) TOKEN(InitElemGetter, init_elem_getter
, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT) TOKEN(InitHiddenElemGetter
, init_hidden_elem_getter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT
) TOKEN(InitPropSetter, init_prop_setter, __null, 5, 2, 1, JOF_ATOM
|JOF_PROPINIT) TOKEN(InitHiddenPropSetter, init_hidden_prop_setter
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT) TOKEN(InitElemSetter
, init_elem_setter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT) TOKEN
(InitHiddenElemSetter, init_hidden_elem_setter, __null, 1, 3,
1, JOF_BYTE|JOF_PROPINIT) TOKEN(GetProp, get_prop, __null, 5
, 1, 1, JOF_ATOM|JOF_IC) TOKEN(GetElem, get_elem, __null, 1, 2
, 1, JOF_BYTE|JOF_IC) TOKEN(SetProp, set_prop, __null, 5, 2, 1
, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) TOKEN(StrictSetProp
, strict_set_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT
|JOF_IC) TOKEN(SetElem, set_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPSET
|JOF_CHECKSLOPPY|JOF_IC) TOKEN(StrictSetElem, strict_set_elem
, __null, 1, 3, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC
) TOKEN(DelProp, del_prop, __null, 5, 1, 1, JOF_ATOM|JOF_CHECKSLOPPY
) TOKEN(StrictDelProp, strict_del_prop, __null, 5, 1, 1, JOF_ATOM
|JOF_CHECKSTRICT) TOKEN(DelElem, del_elem, __null, 1, 2, 1, JOF_BYTE
|JOF_CHECKSLOPPY) TOKEN(StrictDelElem, strict_del_elem, __null
, 1, 2, 1, JOF_BYTE|JOF_CHECKSTRICT) TOKEN(HasOwn, has_own, __null
, 1, 2, 1, JOF_BYTE|JOF_IC) TOKEN(CheckPrivateField, check_private_field
, __null, 3, 2, 3, JOF_TWO_UINT8|JOF_CHECKSTRICT|JOF_IC) TOKEN
(NewPrivateName, new_private_name, __null, 5, 0, 1, JOF_ATOM)
TOKEN(SuperBase, super_base, __null, 1, 1, 1, JOF_BYTE) TOKEN
(GetPropSuper, get_prop_super, __null, 5, 2, 1, JOF_ATOM|JOF_IC
) TOKEN(GetElemSuper, get_elem_super, __null, 1, 3, 1, JOF_BYTE
|JOF_IC) TOKEN(SetPropSuper, set_prop_super, __null, 5, 3, 1,
JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY) TOKEN(StrictSetPropSuper
, strict_set_prop_super, __null, 5, 3, 1, JOF_ATOM|JOF_PROPSET
|JOF_CHECKSTRICT) TOKEN(SetElemSuper, set_elem_super, __null,
1, 4, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSLOPPY) TOKEN(StrictSetElemSuper
, strict_set_elem_super, __null, 1, 4, 1, JOF_BYTE|JOF_PROPSET
|JOF_CHECKSTRICT) TOKEN(Iter, iter, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) TOKEN(MoreIter, more_iter, __null, 1, 1, 2, JOF_BYTE
) TOKEN(IsNoIter, is_no_iter, __null, 1, 1, 2, JOF_BYTE) TOKEN
(EndIter, end_iter, __null, 1, 2, 0, JOF_BYTE) TOKEN(CloseIter
, close_iter, __null, 2, 1, 0, JOF_UINT8|JOF_IC) TOKEN(OptimizeGetIterator
, optimize_get_iterator, __null, 1, 1, 1, JOF_BYTE|JOF_IC) TOKEN
(CheckIsObj, check_is_obj, __null, 2, 1, 1, JOF_UINT8) TOKEN(
CheckObjCoercible, check_obj_coercible, __null, 1, 1, 1, JOF_BYTE
) TOKEN(ToAsyncIter, to_async_iter, __null, 1, 2, 1, JOF_BYTE
) TOKEN(MutateProto, mutate_proto, __null, 1, 2, 1, JOF_BYTE)
TOKEN(NewArray, new_array, __null, 5, 0, 1, JOF_UINT32|JOF_IC
) TOKEN(InitElemArray, init_elem_array, __null, 5, 2, 1, JOF_UINT32
|JOF_PROPINIT) TOKEN(InitElemInc, init_elem_inc, __null, 1, 3
, 2, JOF_BYTE|JOF_PROPINIT|JOF_IC) TOKEN(Hole, hole, __null, 1
, 0, 1, JOF_BYTE) TOKEN(RegExp, reg_exp, __null, 5, 0, 1, JOF_REGEXP
) TOKEN(Lambda, lambda, __null, 5, 0, 1, JOF_OBJECT|JOF_USES_ENV
|JOF_IC) TOKEN(SetFunName, set_fun_name, __null, 2, 2, 1, JOF_UINT8
) TOKEN(InitHomeObject, init_home_object, __null, 1, 2, 1, JOF_BYTE
) TOKEN(CheckClassHeritage, check_class_heritage, __null, 1, 1
, 1, JOF_BYTE) TOKEN(FunWithProto, fun_with_proto, __null, 5,
1, 1, JOF_OBJECT|JOF_USES_ENV) TOKEN(BuiltinObject, builtin_object
, __null, 2, 0, 1, JOF_UINT8|JOF_IC) TOKEN(Call, call, __null
, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) TOKEN(CallContent, call_content
, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) TOKEN(CallIter
, call_iter, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) TOKEN
(CallContentIter, call_content_iter, __null, 3, -1, 1, JOF_ARGC
|JOF_INVOKE|JOF_IC) TOKEN(CallIgnoresRv, call_ignores_rv, __null
, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) TOKEN(SpreadCall, spread_call
, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_IC) TOKEN
(OptimizeSpreadCall, optimize_spread_call, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) TOKEN(Eval, eval, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_CHECKSLOPPY|JOF_IC) TOKEN(SpreadEval, spread_eval, __null
, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSLOPPY|JOF_IC
) TOKEN(StrictEval, strict_eval, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_CHECKSTRICT|JOF_IC) TOKEN(StrictSpreadEval, strict_spread_eval
, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSTRICT
|JOF_IC) TOKEN(ImplicitThis, implicit_this, "", 1, 1, 1, JOF_BYTE
) TOKEN(CallSiteObj, call_site_obj, __null, 5, 0, 1, JOF_OBJECT
) TOKEN(IsConstructing, is_constructing, __null, 1, 0, 1, JOF_BYTE
) TOKEN(New, new_, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT
|JOF_IC) TOKEN(NewContent, new_content, __null, 3, -1, 1, JOF_ARGC
|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) TOKEN(SuperCall, super_call
, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC)
TOKEN(SpreadNew, spread_new, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE
|JOF_CONSTRUCT|JOF_SPREAD|JOF_IC) TOKEN(SpreadSuperCall, spread_super_call
, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_CONSTRUCT|JOF_SPREAD
|JOF_IC) TOKEN(SuperFun, super_fun, __null, 1, 1, 1, JOF_BYTE
) TOKEN(CheckThisReinit, check_this_reinit, __null, 1, 1, 1, JOF_BYTE
) TOKEN(Generator, generator, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV
) TOKEN(InitialYield, initial_yield, __null, 4, 1, 2, JOF_RESUMEINDEX
) TOKEN(AfterYield, after_yield, __null, 5, 0, 0, JOF_ICINDEX
) TOKEN(FinalYieldRval, final_yield_rval, __null, 1, 1, 0, JOF_BYTE
) TOKEN(Yield, yield, __null, 4, 2, 2, JOF_RESUMEINDEX) TOKEN
(AsyncAwait, async_await, __null, 1, 2, 1, JOF_BYTE) TOKEN(AsyncResolve
, async_resolve, __null, 1, 2, 1, JOF_BYTE) TOKEN(AsyncReject
, async_reject, __null, 1, 3, 1, JOF_BYTE) TOKEN(Await, await
, __null, 4, 2, 2, JOF_RESUMEINDEX) TOKEN(CanSkipAwait, can_skip_await
, __null, 1, 1, 2, JOF_BYTE) TOKEN(MaybeExtractAwaitValue, maybe_extract_await_value
, __null, 1, 2, 2, JOF_BYTE) TOKEN(ResumeKind, resume_kind, __null
, 2, 0, 1, JOF_UINT8) TOKEN(Resume, resume, __null, 1, 3, 1, JOF_BYTE
|JOF_INVOKE) TOKEN(JumpTarget, jump_target, __null, 5, 0, 0, JOF_ICINDEX
) TOKEN(LoopHead, loop_head, __null, 6, 0, 0, JOF_LOOPHEAD) TOKEN
(Goto, goto_, __null, 5, 0, 0, JOF_JUMP) TOKEN(JumpIfFalse, jump_if_false
, __null, 5, 1, 0, JOF_JUMP|JOF_IC) TOKEN(JumpIfTrue, jump_if_true
, __null, 5, 1, 0, JOF_JUMP|JOF_IC) TOKEN(And, and_, __null, 5
, 1, 1, JOF_JUMP|JOF_IC) TOKEN(Or, or_, __null, 5, 1, 1, JOF_JUMP
|JOF_IC) TOKEN(Coalesce, coalesce, __null, 5, 1, 1, JOF_JUMP)
TOKEN(Case, case_, __null, 5, 2, 1, JOF_JUMP) TOKEN(Default,
default_, __null, 5, 1, 0, JOF_JUMP) TOKEN(TableSwitch, table_switch
, __null, 16, 1, 0, JOF_TABLESWITCH) TOKEN(Return, return_, __null
, 1, 1, 0, JOF_BYTE) TOKEN(GetRval, get_rval, __null, 1, 0, 1
, JOF_BYTE) TOKEN(SetRval, set_rval, __null, 1, 1, 0, JOF_BYTE
) TOKEN(RetRval, ret_rval, __null, 1, 0, 0, JOF_BYTE) TOKEN(CheckReturn
, check_return, __null, 1, 1, 1, JOF_BYTE) TOKEN(Throw, throw_
, __null, 1, 1, 0, JOF_BYTE) TOKEN(ThrowWithStack, throw_with_stack
, __null, 1, 2, 0, JOF_BYTE) TOKEN(CreateSuppressedError, create_suppressed_error
, __null, 1, 2, 1, JOF_BYTE) TOKEN(ThrowMsg, throw_msg, __null
, 2, 0, 0, JOF_UINT8) TOKEN(ThrowSetConst, throw_set_const, __null
, 5, 0, 0, JOF_ATOM) TOKEN(Try, try_, __null, 1, 0, 0, JOF_BYTE
) TOKEN(TryDestructuring, try_destructuring, __null, 1, 0, 0,
JOF_BYTE) TOKEN(Exception, exception, __null, 1, 0, 1, JOF_BYTE
) TOKEN(ExceptionAndStack, exception_and_stack, __null, 1, 0,
2, JOF_BYTE) TOKEN(Finally, finally, __null, 1, 0, 0, JOF_BYTE
) TOKEN(Uninitialized, uninitialized, __null, 1, 0, 1, JOF_BYTE
) TOKEN(InitLexical, init_lexical, __null, 4, 1, 1, JOF_LOCAL
) TOKEN(InitGLexical, init_g_lexical, __null, 5, 1, 1, JOF_ATOM
|JOF_PROPINIT|JOF_GNAME|JOF_IC) TOKEN(InitAliasedLexical, init_aliased_lexical
, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPINIT) TOKEN(CheckLexical
, check_lexical, __null, 4, 1, 1, JOF_LOCAL) TOKEN(CheckAliasedLexical
, check_aliased_lexical, __null, 6, 1, 1, JOF_ENVCOORD) TOKEN
(CheckThis, check_this, __null, 1, 1, 1, JOF_BYTE) TOKEN(BindUnqualifiedGName
, bind_unqualified_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME
|JOF_IC) TOKEN(BindUnqualifiedName, bind_unqualified_name, __null
, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) TOKEN(BindName, bind_name
, __null, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) TOKEN(GetName
, get_name, __null, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) TOKEN
(GetGName, get_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME|JOF_IC
) TOKEN(GetArg, get_arg, __null, 3, 0, 1, JOF_QARG) TOKEN(GetFrameArg
, get_frame_arg, __null, 3, 0, 1, JOF_QARG) TOKEN(GetLocal, get_local
, __null, 4, 0, 1, JOF_LOCAL) TOKEN(ArgumentsLength, arguments_length
, __null, 1, 0, 1, JOF_BYTE) TOKEN(GetActualArg, get_actual_arg
, __null, 1, 1, 1, JOF_BYTE) TOKEN(GetAliasedVar, get_aliased_var
, __null, 6, 0, 1, JOF_ENVCOORD|JOF_USES_ENV) TOKEN(GetAliasedDebugVar
, get_aliased_debug_var, __null, 6, 0, 1, JOF_DEBUGCOORD) TOKEN
(GetImport, get_import, __null, 5, 0, 1, JOF_ATOM|JOF_IC) TOKEN
(GetBoundName, get_bound_name, __null, 5, 1, 1, JOF_ATOM|JOF_IC
) TOKEN(GetIntrinsic, get_intrinsic, __null, 5, 0, 1, JOF_ATOM
|JOF_IC) TOKEN(Callee, callee, __null, 1, 0, 1, JOF_BYTE) TOKEN
(EnvCallee, env_callee, __null, 3, 0, 1, JOF_UINT16) TOKEN(SetName
, set_name, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY
|JOF_IC|JOF_USES_ENV) TOKEN(StrictSetName, strict_set_name, __null
, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC|JOF_USES_ENV
) TOKEN(SetGName, set_g_name, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET
|JOF_GNAME|JOF_CHECKSLOPPY|JOF_IC) TOKEN(StrictSetGName, strict_set_g_name
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_GNAME|JOF_CHECKSTRICT
|JOF_IC) TOKEN(SetArg, set_arg, __null, 3, 1, 1, JOF_QARG) TOKEN
(SetLocal, set_local, __null, 4, 1, 1, JOF_LOCAL) TOKEN(SetAliasedVar
, set_aliased_var, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPSET|
JOF_USES_ENV) TOKEN(SetIntrinsic, set_intrinsic, __null, 5, 1
, 1, JOF_ATOM) TOKEN(PushLexicalEnv, push_lexical_env, __null
, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) TOKEN(PopLexicalEnv, pop_lexical_env
, __null, 1, 0, 0, JOF_BYTE|JOF_USES_ENV) TOKEN(DebugLeaveLexicalEnv
, debug_leave_lexical_env, __null, 1, 0, 0, JOF_BYTE) TOKEN(RecreateLexicalEnv
, recreate_lexical_env, __null, 5, 0, 0, JOF_SCOPE) TOKEN(FreshenLexicalEnv
, freshen_lexical_env, __null, 5, 0, 0, JOF_SCOPE) TOKEN(PushClassBodyEnv
, push_class_body_env, __null, 5, 0, 0, JOF_SCOPE) TOKEN(PushVarEnv
, push_var_env, __null, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) TOKEN
(EnterWith, enter_with, __null, 5, 1, 0, JOF_SCOPE) TOKEN(LeaveWith
, leave_with, __null, 1, 0, 0, JOF_BYTE) TOKEN(AddDisposable,
add_disposable, __null, 2, 3, 0, JOF_UINT8|JOF_USES_ENV) TOKEN
(TakeDisposeCapability, take_dispose_capability, __null, 1, 0
, 1, JOF_BYTE|JOF_USES_ENV) TOKEN(BindVar, bind_var, __null, 1
, 0, 1, JOF_BYTE|JOF_USES_ENV) TOKEN(GlobalOrEvalDeclInstantiation
, global_or_eval_decl_instantiation, __null, 5, 0, 0, JOF_GCTHING
|JOF_USES_ENV) TOKEN(DelName, del_name, __null, 5, 0, 1, JOF_ATOM
|JOF_CHECKSLOPPY|JOF_USES_ENV) TOKEN(Arguments, arguments, __null
, 1, 0, 1, JOF_BYTE|JOF_USES_ENV) TOKEN(Rest, rest, __null, 1
, 0, 1, JOF_BYTE|JOF_IC) TOKEN(FunctionThis, function_this, __null
, 1, 0, 1, JOF_BYTE) TOKEN(Pop, pop, __null, 1, 1, 0, JOF_BYTE
) TOKEN(PopN, pop_n, __null, 3, -1, 0, JOF_UINT16) TOKEN(Dup,
dup, __null, 1, 1, 2, JOF_BYTE) TOKEN(Dup2, dup2, __null, 1,
2, 4, JOF_BYTE) TOKEN(DupAt, dup_at, __null, 4, 0, 1, JOF_UINT24
) TOKEN(Swap, swap, __null, 1, 2, 2, JOF_BYTE) TOKEN(Pick, pick
, __null, 2, 0, 0, JOF_UINT8) TOKEN(Unpick, unpick, __null, 2
, 0, 0, JOF_UINT8) TOKEN(Nop, nop, __null, 1, 0, 0, JOF_BYTE)
TOKEN(Lineno, lineno, __null, 5, 0, 0, JOF_UINT32) TOKEN(NopDestructuring
, nop_destructuring, __null, 1, 0, 0, JOF_BYTE) TOKEN(DebugCheckSelfHosted
, debug_check_self_hosted, __null, 1, 1, 1, JOF_BYTE) TOKEN(Debugger
, debugger, __null, 1, 0, 0, JOF_BYTE)
87#undef TOKEN
88};
89
90/*
91 * Array of JS bytecode names used by PC count JSON, DEBUG-only Disassemble
92 * and JIT debug spew.
93 */
94const char* const js::CodeNameTable[] = {
95#define OPNAME(op, ...) #op,
96 FOR_EACH_OPCODE(OPNAME)OPNAME(Undefined, undefined, "", 1, 0, 1, JOF_BYTE) OPNAME(Null
, null, "null", 1, 0, 1, JOF_BYTE) OPNAME(False, false_, "false"
, 1, 0, 1, JOF_BYTE) OPNAME(True, true_, "true", 1, 0, 1, JOF_BYTE
) OPNAME(Int32, int32, __null, 5, 0, 1, JOF_INT32) OPNAME(Zero
, zero, "0", 1, 0, 1, JOF_BYTE) OPNAME(One, one, "1", 1, 0, 1
, JOF_BYTE) OPNAME(Int8, int8, __null, 2, 0, 1, JOF_INT8) OPNAME
(Uint16, uint16, __null, 3, 0, 1, JOF_UINT16) OPNAME(Uint24, uint24
, __null, 4, 0, 1, JOF_UINT24) OPNAME(Double, double_, __null
, 9, 0, 1, JOF_DOUBLE) OPNAME(BigInt, big_int, __null, 5, 0, 1
, JOF_BIGINT) OPNAME(String, string, __null, 5, 0, 1, JOF_STRING
) OPNAME(Symbol, symbol, __null, 2, 0, 1, JOF_UINT8) OPNAME(Void
, void_, __null, 1, 1, 1, JOF_BYTE) OPNAME(Typeof, typeof_, __null
, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(TypeofExpr, typeof_expr, __null
, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(TypeofEq, typeof_eq, __null
, 2, 1, 1, JOF_UINT8|JOF_IC) OPNAME(Pos, pos, "+ ", 1, 1, 1, JOF_BYTE
|JOF_IC) OPNAME(Neg, neg, "- ", 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME
(BitNot, bit_not, "~", 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(Not, not_
, "!", 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(BitOr, bit_or, "|", 1
, 2, 1, JOF_BYTE|JOF_IC) OPNAME(BitXor, bit_xor, "^", 1, 2, 1
, JOF_BYTE|JOF_IC) OPNAME(BitAnd, bit_and, "&", 1, 2, 1, JOF_BYTE
|JOF_IC) OPNAME(Eq, eq, "==", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME
(Ne, ne, "!=", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(StrictEq, strict_eq
, "===", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(StrictNe, strict_ne
, "!==", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(StrictConstantEq, strict_constant_eq
, __null, 3, 1, 1, JOF_UINT16) OPNAME(StrictConstantNe, strict_constant_ne
, __null, 3, 1, 1, JOF_UINT16) OPNAME(Lt, lt, "<", 1, 2, 1
, JOF_BYTE|JOF_IC) OPNAME(Gt, gt, ">", 1, 2, 1, JOF_BYTE|JOF_IC
) OPNAME(Le, le, "<=", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Ge
, ge, ">=", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Instanceof, instanceof
, "instanceof", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(In, in_, "in"
, 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Lsh, lsh, "<<", 1, 2
, 1, JOF_BYTE|JOF_IC) OPNAME(Rsh, rsh, ">>", 1, 2, 1, JOF_BYTE
|JOF_IC) OPNAME(Ursh, ursh, ">>>", 1, 2, 1, JOF_BYTE
|JOF_IC) OPNAME(Add, add, "+", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME
(Sub, sub, "-", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Inc, inc, __null
, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(Dec, dec, __null, 1, 1, 1,
JOF_BYTE|JOF_IC) OPNAME(Mul, mul, "*", 1, 2, 1, JOF_BYTE|JOF_IC
) OPNAME(Div, div, "/", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Mod,
mod, "%", 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(Pow, pow, "**", 1
, 2, 1, JOF_BYTE|JOF_IC) OPNAME(NopIsAssignOp, nop_is_assign_op
, __null, 1, 0, 0, JOF_BYTE) OPNAME(ToPropertyKey, to_property_key
, __null, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(ToNumeric, to_numeric
, __null, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME(ToString, to_string
, __null, 1, 1, 1, JOF_BYTE) OPNAME(IsNullOrUndefined, is_null_or_undefined
, __null, 1, 1, 2, JOF_BYTE) OPNAME(GlobalThis, global_this, __null
, 1, 0, 1, JOF_BYTE) OPNAME(NonSyntacticGlobalThis, non_syntactic_global_this
, __null, 1, 0, 1, JOF_BYTE) OPNAME(NewTarget, new_target, __null
, 1, 0, 1, JOF_BYTE) OPNAME(DynamicImport, dynamic_import, __null
, 2, 2, 1, JOF_UINT8) OPNAME(ImportMeta, import_meta, __null,
1, 0, 1, JOF_BYTE|JOF_IC) OPNAME(NewInit, new_init, __null, 2
, 0, 1, JOF_UINT8|JOF_IC) OPNAME(NewObject, new_object, __null
, 5, 0, 1, JOF_SHAPE|JOF_IC) OPNAME(Object, object, __null, 5
, 0, 1, JOF_OBJECT) OPNAME(ObjWithProto, obj_with_proto, __null
, 1, 1, 1, JOF_BYTE) OPNAME(InitProp, init_prop, __null, 5, 2
, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC) OPNAME(InitHiddenProp, init_hidden_prop
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC) OPNAME(InitLockedProp
, init_locked_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT|JOF_IC
) OPNAME(InitElem, init_elem, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT
|JOF_IC) OPNAME(InitHiddenElem, init_hidden_elem, __null, 1, 3
, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC) OPNAME(InitLockedElem, init_locked_elem
, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT|JOF_IC) OPNAME(InitPropGetter
, init_prop_getter, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT) OPNAME
(InitHiddenPropGetter, init_hidden_prop_getter, __null, 5, 2,
1, JOF_ATOM|JOF_PROPINIT) OPNAME(InitElemGetter, init_elem_getter
, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT) OPNAME(InitHiddenElemGetter
, init_hidden_elem_getter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT
) OPNAME(InitPropSetter, init_prop_setter, __null, 5, 2, 1, JOF_ATOM
|JOF_PROPINIT) OPNAME(InitHiddenPropSetter, init_hidden_prop_setter
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPINIT) OPNAME(InitElemSetter
, init_elem_setter, __null, 1, 3, 1, JOF_BYTE|JOF_PROPINIT) OPNAME
(InitHiddenElemSetter, init_hidden_elem_setter, __null, 1, 3,
1, JOF_BYTE|JOF_PROPINIT) OPNAME(GetProp, get_prop, __null, 5
, 1, 1, JOF_ATOM|JOF_IC) OPNAME(GetElem, get_elem, __null, 1,
2, 1, JOF_BYTE|JOF_IC) OPNAME(SetProp, set_prop, __null, 5, 2
, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) OPNAME(StrictSetProp
, strict_set_prop, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT
|JOF_IC) OPNAME(SetElem, set_elem, __null, 1, 3, 1, JOF_BYTE|
JOF_PROPSET|JOF_CHECKSLOPPY|JOF_IC) OPNAME(StrictSetElem, strict_set_elem
, __null, 1, 3, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC
) OPNAME(DelProp, del_prop, __null, 5, 1, 1, JOF_ATOM|JOF_CHECKSLOPPY
) OPNAME(StrictDelProp, strict_del_prop, __null, 5, 1, 1, JOF_ATOM
|JOF_CHECKSTRICT) OPNAME(DelElem, del_elem, __null, 1, 2, 1, JOF_BYTE
|JOF_CHECKSLOPPY) OPNAME(StrictDelElem, strict_del_elem, __null
, 1, 2, 1, JOF_BYTE|JOF_CHECKSTRICT) OPNAME(HasOwn, has_own, __null
, 1, 2, 1, JOF_BYTE|JOF_IC) OPNAME(CheckPrivateField, check_private_field
, __null, 3, 2, 3, JOF_TWO_UINT8|JOF_CHECKSTRICT|JOF_IC) OPNAME
(NewPrivateName, new_private_name, __null, 5, 0, 1, JOF_ATOM)
OPNAME(SuperBase, super_base, __null, 1, 1, 1, JOF_BYTE) OPNAME
(GetPropSuper, get_prop_super, __null, 5, 2, 1, JOF_ATOM|JOF_IC
) OPNAME(GetElemSuper, get_elem_super, __null, 1, 3, 1, JOF_BYTE
|JOF_IC) OPNAME(SetPropSuper, set_prop_super, __null, 5, 3, 1
, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY) OPNAME(StrictSetPropSuper
, strict_set_prop_super, __null, 5, 3, 1, JOF_ATOM|JOF_PROPSET
|JOF_CHECKSTRICT) OPNAME(SetElemSuper, set_elem_super, __null
, 1, 4, 1, JOF_BYTE|JOF_PROPSET|JOF_CHECKSLOPPY) OPNAME(StrictSetElemSuper
, strict_set_elem_super, __null, 1, 4, 1, JOF_BYTE|JOF_PROPSET
|JOF_CHECKSTRICT) OPNAME(Iter, iter, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) OPNAME(MoreIter, more_iter, __null, 1, 1, 2, JOF_BYTE
) OPNAME(IsNoIter, is_no_iter, __null, 1, 1, 2, JOF_BYTE) OPNAME
(EndIter, end_iter, __null, 1, 2, 0, JOF_BYTE) OPNAME(CloseIter
, close_iter, __null, 2, 1, 0, JOF_UINT8|JOF_IC) OPNAME(OptimizeGetIterator
, optimize_get_iterator, __null, 1, 1, 1, JOF_BYTE|JOF_IC) OPNAME
(CheckIsObj, check_is_obj, __null, 2, 1, 1, JOF_UINT8) OPNAME
(CheckObjCoercible, check_obj_coercible, __null, 1, 1, 1, JOF_BYTE
) OPNAME(ToAsyncIter, to_async_iter, __null, 1, 2, 1, JOF_BYTE
) OPNAME(MutateProto, mutate_proto, __null, 1, 2, 1, JOF_BYTE
) OPNAME(NewArray, new_array, __null, 5, 0, 1, JOF_UINT32|JOF_IC
) OPNAME(InitElemArray, init_elem_array, __null, 5, 2, 1, JOF_UINT32
|JOF_PROPINIT) OPNAME(InitElemInc, init_elem_inc, __null, 1, 3
, 2, JOF_BYTE|JOF_PROPINIT|JOF_IC) OPNAME(Hole, hole, __null,
1, 0, 1, JOF_BYTE) OPNAME(RegExp, reg_exp, __null, 5, 0, 1, JOF_REGEXP
) OPNAME(Lambda, lambda, __null, 5, 0, 1, JOF_OBJECT|JOF_USES_ENV
|JOF_IC) OPNAME(SetFunName, set_fun_name, __null, 2, 2, 1, JOF_UINT8
) OPNAME(InitHomeObject, init_home_object, __null, 1, 2, 1, JOF_BYTE
) OPNAME(CheckClassHeritage, check_class_heritage, __null, 1,
1, 1, JOF_BYTE) OPNAME(FunWithProto, fun_with_proto, __null,
5, 1, 1, JOF_OBJECT|JOF_USES_ENV) OPNAME(BuiltinObject, builtin_object
, __null, 2, 0, 1, JOF_UINT8|JOF_IC) OPNAME(Call, call, __null
, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) OPNAME(CallContent, call_content
, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) OPNAME(CallIter
, call_iter, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) OPNAME
(CallContentIter, call_content_iter, __null, 3, -1, 1, JOF_ARGC
|JOF_INVOKE|JOF_IC) OPNAME(CallIgnoresRv, call_ignores_rv, __null
, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_IC) OPNAME(SpreadCall, spread_call
, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_IC) OPNAME
(OptimizeSpreadCall, optimize_spread_call, __null, 1, 1, 1, JOF_BYTE
|JOF_IC) OPNAME(Eval, eval, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE
|JOF_CHECKSLOPPY|JOF_IC) OPNAME(SpreadEval, spread_eval, __null
, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSLOPPY|JOF_IC
) OPNAME(StrictEval, strict_eval, __null, 3, -1, 1, JOF_ARGC|
JOF_INVOKE|JOF_CHECKSTRICT|JOF_IC) OPNAME(StrictSpreadEval, strict_spread_eval
, __null, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_SPREAD|JOF_CHECKSTRICT
|JOF_IC) OPNAME(ImplicitThis, implicit_this, "", 1, 1, 1, JOF_BYTE
) OPNAME(CallSiteObj, call_site_obj, __null, 5, 0, 1, JOF_OBJECT
) OPNAME(IsConstructing, is_constructing, __null, 1, 0, 1, JOF_BYTE
) OPNAME(New, new_, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT
|JOF_IC) OPNAME(NewContent, new_content, __null, 3, -1, 1, JOF_ARGC
|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC) OPNAME(SuperCall, super_call
, __null, 3, -1, 1, JOF_ARGC|JOF_INVOKE|JOF_CONSTRUCT|JOF_IC)
OPNAME(SpreadNew, spread_new, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE
|JOF_CONSTRUCT|JOF_SPREAD|JOF_IC) OPNAME(SpreadSuperCall, spread_super_call
, __null, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_CONSTRUCT|JOF_SPREAD
|JOF_IC) OPNAME(SuperFun, super_fun, __null, 1, 1, 1, JOF_BYTE
) OPNAME(CheckThisReinit, check_this_reinit, __null, 1, 1, 1,
JOF_BYTE) OPNAME(Generator, generator, __null, 1, 0, 1, JOF_BYTE
|JOF_USES_ENV) OPNAME(InitialYield, initial_yield, __null, 4,
1, 2, JOF_RESUMEINDEX) OPNAME(AfterYield, after_yield, __null
, 5, 0, 0, JOF_ICINDEX) OPNAME(FinalYieldRval, final_yield_rval
, __null, 1, 1, 0, JOF_BYTE) OPNAME(Yield, yield, __null, 4, 2
, 2, JOF_RESUMEINDEX) OPNAME(AsyncAwait, async_await, __null,
1, 2, 1, JOF_BYTE) OPNAME(AsyncResolve, async_resolve, __null
, 1, 2, 1, JOF_BYTE) OPNAME(AsyncReject, async_reject, __null
, 1, 3, 1, JOF_BYTE) OPNAME(Await, await, __null, 4, 2, 2, JOF_RESUMEINDEX
) OPNAME(CanSkipAwait, can_skip_await, __null, 1, 1, 2, JOF_BYTE
) OPNAME(MaybeExtractAwaitValue, maybe_extract_await_value, __null
, 1, 2, 2, JOF_BYTE) OPNAME(ResumeKind, resume_kind, __null, 2
, 0, 1, JOF_UINT8) OPNAME(Resume, resume, __null, 1, 3, 1, JOF_BYTE
|JOF_INVOKE) OPNAME(JumpTarget, jump_target, __null, 5, 0, 0,
JOF_ICINDEX) OPNAME(LoopHead, loop_head, __null, 6, 0, 0, JOF_LOOPHEAD
) OPNAME(Goto, goto_, __null, 5, 0, 0, JOF_JUMP) OPNAME(JumpIfFalse
, jump_if_false, __null, 5, 1, 0, JOF_JUMP|JOF_IC) OPNAME(JumpIfTrue
, jump_if_true, __null, 5, 1, 0, JOF_JUMP|JOF_IC) OPNAME(And,
and_, __null, 5, 1, 1, JOF_JUMP|JOF_IC) OPNAME(Or, or_, __null
, 5, 1, 1, JOF_JUMP|JOF_IC) OPNAME(Coalesce, coalesce, __null
, 5, 1, 1, JOF_JUMP) OPNAME(Case, case_, __null, 5, 2, 1, JOF_JUMP
) OPNAME(Default, default_, __null, 5, 1, 0, JOF_JUMP) OPNAME
(TableSwitch, table_switch, __null, 16, 1, 0, JOF_TABLESWITCH
) OPNAME(Return, return_, __null, 1, 1, 0, JOF_BYTE) OPNAME(GetRval
, get_rval, __null, 1, 0, 1, JOF_BYTE) OPNAME(SetRval, set_rval
, __null, 1, 1, 0, JOF_BYTE) OPNAME(RetRval, ret_rval, __null
, 1, 0, 0, JOF_BYTE) OPNAME(CheckReturn, check_return, __null
, 1, 1, 1, JOF_BYTE) OPNAME(Throw, throw_, __null, 1, 1, 0, JOF_BYTE
) OPNAME(ThrowWithStack, throw_with_stack, __null, 1, 2, 0, JOF_BYTE
) OPNAME(CreateSuppressedError, create_suppressed_error, __null
, 1, 2, 1, JOF_BYTE) OPNAME(ThrowMsg, throw_msg, __null, 2, 0
, 0, JOF_UINT8) OPNAME(ThrowSetConst, throw_set_const, __null
, 5, 0, 0, JOF_ATOM) OPNAME(Try, try_, __null, 1, 0, 0, JOF_BYTE
) OPNAME(TryDestructuring, try_destructuring, __null, 1, 0, 0
, JOF_BYTE) OPNAME(Exception, exception, __null, 1, 0, 1, JOF_BYTE
) OPNAME(ExceptionAndStack, exception_and_stack, __null, 1, 0
, 2, JOF_BYTE) OPNAME(Finally, finally, __null, 1, 0, 0, JOF_BYTE
) OPNAME(Uninitialized, uninitialized, __null, 1, 0, 1, JOF_BYTE
) OPNAME(InitLexical, init_lexical, __null, 4, 1, 1, JOF_LOCAL
) OPNAME(InitGLexical, init_g_lexical, __null, 5, 1, 1, JOF_ATOM
|JOF_PROPINIT|JOF_GNAME|JOF_IC) OPNAME(InitAliasedLexical, init_aliased_lexical
, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPINIT) OPNAME(CheckLexical
, check_lexical, __null, 4, 1, 1, JOF_LOCAL) OPNAME(CheckAliasedLexical
, check_aliased_lexical, __null, 6, 1, 1, JOF_ENVCOORD) OPNAME
(CheckThis, check_this, __null, 1, 1, 1, JOF_BYTE) OPNAME(BindUnqualifiedGName
, bind_unqualified_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME
|JOF_IC) OPNAME(BindUnqualifiedName, bind_unqualified_name, __null
, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) OPNAME(BindName, bind_name
, __null, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) OPNAME(GetName
, get_name, __null, 5, 0, 1, JOF_ATOM|JOF_IC|JOF_USES_ENV) OPNAME
(GetGName, get_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME|JOF_IC
) OPNAME(GetArg, get_arg, __null, 3, 0, 1, JOF_QARG) OPNAME(GetFrameArg
, get_frame_arg, __null, 3, 0, 1, JOF_QARG) OPNAME(GetLocal, get_local
, __null, 4, 0, 1, JOF_LOCAL) OPNAME(ArgumentsLength, arguments_length
, __null, 1, 0, 1, JOF_BYTE) OPNAME(GetActualArg, get_actual_arg
, __null, 1, 1, 1, JOF_BYTE) OPNAME(GetAliasedVar, get_aliased_var
, __null, 6, 0, 1, JOF_ENVCOORD|JOF_USES_ENV) OPNAME(GetAliasedDebugVar
, get_aliased_debug_var, __null, 6, 0, 1, JOF_DEBUGCOORD) OPNAME
(GetImport, get_import, __null, 5, 0, 1, JOF_ATOM|JOF_IC) OPNAME
(GetBoundName, get_bound_name, __null, 5, 1, 1, JOF_ATOM|JOF_IC
) OPNAME(GetIntrinsic, get_intrinsic, __null, 5, 0, 1, JOF_ATOM
|JOF_IC) OPNAME(Callee, callee, __null, 1, 0, 1, JOF_BYTE) OPNAME
(EnvCallee, env_callee, __null, 3, 0, 1, JOF_UINT16) OPNAME(SetName
, set_name, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSLOPPY
|JOF_IC|JOF_USES_ENV) OPNAME(StrictSetName, strict_set_name, __null
, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_CHECKSTRICT|JOF_IC|JOF_USES_ENV
) OPNAME(SetGName, set_g_name, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET
|JOF_GNAME|JOF_CHECKSLOPPY|JOF_IC) OPNAME(StrictSetGName, strict_set_g_name
, __null, 5, 2, 1, JOF_ATOM|JOF_PROPSET|JOF_GNAME|JOF_CHECKSTRICT
|JOF_IC) OPNAME(SetArg, set_arg, __null, 3, 1, 1, JOF_QARG) OPNAME
(SetLocal, set_local, __null, 4, 1, 1, JOF_LOCAL) OPNAME(SetAliasedVar
, set_aliased_var, __null, 6, 1, 1, JOF_ENVCOORD|JOF_PROPSET|
JOF_USES_ENV) OPNAME(SetIntrinsic, set_intrinsic, __null, 5, 1
, 1, JOF_ATOM) OPNAME(PushLexicalEnv, push_lexical_env, __null
, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) OPNAME(PopLexicalEnv, pop_lexical_env
, __null, 1, 0, 0, JOF_BYTE|JOF_USES_ENV) OPNAME(DebugLeaveLexicalEnv
, debug_leave_lexical_env, __null, 1, 0, 0, JOF_BYTE) OPNAME(
RecreateLexicalEnv, recreate_lexical_env, __null, 5, 0, 0, JOF_SCOPE
) OPNAME(FreshenLexicalEnv, freshen_lexical_env, __null, 5, 0
, 0, JOF_SCOPE) OPNAME(PushClassBodyEnv, push_class_body_env,
__null, 5, 0, 0, JOF_SCOPE) OPNAME(PushVarEnv, push_var_env,
__null, 5, 0, 0, JOF_SCOPE|JOF_USES_ENV) OPNAME(EnterWith, enter_with
, __null, 5, 1, 0, JOF_SCOPE) OPNAME(LeaveWith, leave_with, __null
, 1, 0, 0, JOF_BYTE) OPNAME(AddDisposable, add_disposable, __null
, 2, 3, 0, JOF_UINT8|JOF_USES_ENV) OPNAME(TakeDisposeCapability
, take_dispose_capability, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV
) OPNAME(BindVar, bind_var, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV
) OPNAME(GlobalOrEvalDeclInstantiation, global_or_eval_decl_instantiation
, __null, 5, 0, 0, JOF_GCTHING|JOF_USES_ENV) OPNAME(DelName, del_name
, __null, 5, 0, 1, JOF_ATOM|JOF_CHECKSLOPPY|JOF_USES_ENV) OPNAME
(Arguments, arguments, __null, 1, 0, 1, JOF_BYTE|JOF_USES_ENV
) OPNAME(Rest, rest, __null, 1, 0, 1, JOF_BYTE|JOF_IC) OPNAME
(FunctionThis, function_this, __null, 1, 0, 1, JOF_BYTE) OPNAME
(Pop, pop, __null, 1, 1, 0, JOF_BYTE) OPNAME(PopN, pop_n, __null
, 3, -1, 0, JOF_UINT16) OPNAME(Dup, dup, __null, 1, 1, 2, JOF_BYTE
) OPNAME(Dup2, dup2, __null, 1, 2, 4, JOF_BYTE) OPNAME(DupAt,
dup_at, __null, 4, 0, 1, JOF_UINT24) OPNAME(Swap, swap, __null
, 1, 2, 2, JOF_BYTE) OPNAME(Pick, pick, __null, 2, 0, 0, JOF_UINT8
) OPNAME(Unpick, unpick, __null, 2, 0, 0, JOF_UINT8) OPNAME(Nop
, nop, __null, 1, 0, 0, JOF_BYTE) OPNAME(Lineno, lineno, __null
, 5, 0, 0, JOF_UINT32) OPNAME(NopDestructuring, nop_destructuring
, __null, 1, 0, 0, JOF_BYTE) OPNAME(DebugCheckSelfHosted, debug_check_self_hosted
, __null, 1, 1, 1, JOF_BYTE) OPNAME(Debugger, debugger, __null
, 1, 0, 0, JOF_BYTE)
97#undef OPNAME
98};
99
100/************************************************************************/
101
102static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
103 UniqueChars* res);
104
105/* static */ const char PCCounts::numExecName[] = "interp";
106
107[[nodiscard]] static bool DumpIonScriptCounts(StringPrinter* sp,
108 HandleScript script,
109 jit::IonScriptCounts* ionCounts) {
110 sp->printf("IonScript [%zu blocks]:\n", ionCounts->numBlocks());
111
112 for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
113 const jit::IonBlockCounts& block = ionCounts->block(i);
114 unsigned lineNumber = 0;
115 JS::LimitedColumnNumberOneOrigin columnNumber;
116 lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()),
117 &columnNumber);
118 sp->printf("BB #%" PRIu32"u" " [%05u,%u,%u]", block.id(), block.offset(),
119 lineNumber, columnNumber.oneOriginValue());
120 if (block.description()) {
121 sp->printf(" [inlined %s]", block.description());
122 }
123 for (size_t j = 0; j < block.numSuccessors(); j++) {
124 sp->printf(" -> #%" PRIu32"u", block.successor(j));
125 }
126 sp->printf(" :: %" PRIu64"l" "u" " hits\n", block.hitCount());
127 sp->printf("%s\n", block.code());
128 }
129
130 return true;
131}
132
133[[nodiscard]] static bool DumpPCCounts(JSContext* cx, HandleScript script,
134 StringPrinter* sp) {
135 // In some edge cases Disassemble1 can end up invoking JS code, so ensure
136 // script counts haven't been discarded.
137 if (!script->hasScriptCounts()) {
138 return true;
139 }
140
141#ifdef DEBUG1
142 jsbytecode* pc = script->code();
143 while (pc < script->codeEnd()) {
144 jsbytecode* next = GetNextPc(pc);
145
146 if (!Disassemble1(cx, script, pc, script->pcToOffset(pc), true, sp)) {
147 return false;
148 }
149
150 sp->put(" {");
151 if (script->hasScriptCounts()) {
152 PCCounts* counts = script->maybeGetPCCounts(pc);
153 if (double val = counts ? counts->numExec() : 0.0) {
154 sp->printf("\"%s\": %.0f", PCCounts::numExecName, val);
155 }
156 }
157 sp->put("}\n");
158
159 pc = next;
160 }
161#endif
162
163 if (!script->hasScriptCounts()) {
164 return true;
165 }
166
167 jit::IonScriptCounts* ionCounts = script->getIonCounts();
168 while (ionCounts) {
169 if (!DumpIonScriptCounts(sp, script, ionCounts)) {
170 return false;
171 }
172
173 ionCounts = ionCounts->previous();
174 }
175
176 return true;
177}
178
179bool js::DumpRealmPCCounts(JSContext* cx) {
180 Rooted<GCVector<JSScript*>> scripts(cx, GCVector<JSScript*>(cx));
181 for (auto base = cx->zone()->cellIter<BaseScript>(); !base.done();
182 base.next()) {
183 if (base->realm() != cx->realm()) {
184 continue;
185 }
186 MOZ_ASSERT_IF(base->hasScriptCounts(), base->hasBytecode())do { if (base->hasScriptCounts()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(base->hasBytecode
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(base->hasBytecode()))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("base->hasBytecode()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 186); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->hasBytecode()"
")"); do { MOZ_CrashSequence(__null, 186); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
187 if (base->hasScriptCounts()) {
188 if (!scripts.append(base->asJSScript())) {
189 return false;
190 }
191 }
192 }
193
194 for (uint32_t i = 0; i < scripts.length(); i++) {
195 HandleScript script = scripts[i];
196 Sprinter sprinter(cx);
197 if (!sprinter.init()) {
198 return false;
199 }
200
201 const char* filename = script->filename();
202 if (!filename) {
203 filename = "(unknown)";
204 }
205 fprintf(stdoutstdout, "--- SCRIPT %s:%u ---\n", filename, script->lineno());
206 if (!DumpPCCounts(cx, script, &sprinter)) {
207 return false;
208 }
209 JS::UniqueChars out = sprinter.release();
210 if (!out) {
211 return false;
212 }
213 fputs(out.get(), stdoutstdout);
214 fprintf(stdoutstdout, "--- END SCRIPT %s:%u ---\n", filename, script->lineno());
215 }
216
217 return true;
218}
219
220/////////////////////////////////////////////////////////////////////
221// Bytecode Parser
222/////////////////////////////////////////////////////////////////////
223
224// Stores the information about the stack slot, where the value comes from.
225// Elements of BytecodeParser::Bytecode.{offsetStack,offsetStackAfter} arrays.
226class OffsetAndDefIndex {
227 // The offset of the PC that pushed the value for this slot.
228 uint32_t offset_;
229
230 // The index in `ndefs` for the PC (0-origin)
231 uint8_t defIndex_;
232
233 enum : uint8_t {
234 Normal = 0,
235
236 // Ignored this value in the expression decompilation.
237 // Used by JSOp::NopDestructuring. See BytecodeParser::simulateOp.
238 Ignored,
239
240 // The value in this slot comes from 2 or more paths.
241 // offset_ and defIndex_ holds the information for the path that
242 // reaches here first.
243 Merged,
244 } type_;
245
246 public:
247 uint32_t offset() const {
248 MOZ_ASSERT(!isSpecial())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSpecial())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSpecial()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!isSpecial()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isSpecial()"
")"); do { MOZ_CrashSequence(__null, 248); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
249 return offset_;
250 };
251 uint32_t specialOffset() const {
252 MOZ_ASSERT(isSpecial())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSpecial())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSpecial()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("isSpecial()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 252); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSpecial()"
")"); do { MOZ_CrashSequence(__null, 252); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
253 return offset_;
254 };
255
256 uint8_t defIndex() const {
257 MOZ_ASSERT(!isSpecial())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSpecial())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSpecial()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!isSpecial()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isSpecial()"
")"); do { MOZ_CrashSequence(__null, 257); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
258 return defIndex_;
259 }
260 uint8_t specialDefIndex() const {
261 MOZ_ASSERT(isSpecial())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSpecial())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSpecial()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("isSpecial()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isSpecial()"
")"); do { MOZ_CrashSequence(__null, 261); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
262 return defIndex_;
263 }
264
265 bool isSpecial() const { return type_ != Normal; }
266 bool isMerged() const { return type_ == Merged; }
267 bool isIgnored() const { return type_ == Ignored; }
268
269 void set(uint32_t aOffset, uint8_t aDefIndex) {
270 offset_ = aOffset;
271 defIndex_ = aDefIndex;
272 type_ = Normal;
273 }
274
275 // Keep offset_ and defIndex_ values for stack dump.
276 void setMerged() { type_ = Merged; }
277 void setIgnored() { type_ = Ignored; }
278
279 bool operator==(const OffsetAndDefIndex& rhs) const {
280 return offset_ == rhs.offset_ && defIndex_ == rhs.defIndex_;
281 }
282
283 bool operator!=(const OffsetAndDefIndex& rhs) const {
284 return !(*this == rhs);
285 }
286};
287
288namespace {
289
290class BytecodeParser {
291 public:
292 enum class JumpKind {
293 Simple,
294 SwitchCase,
295 SwitchDefault,
296 TryCatch,
297 TryFinally
298 };
299
300 private:
301 class Bytecode {
302 public:
303 explicit Bytecode(const LifoAllocPolicy<Fallible>& alloc)
304 : parsed(false),
305 stackDepth(0),
306 offsetStack(nullptr)
307#if defined(DEBUG1) || defined(JS_JITSPEW1)
308 ,
309 stackDepthAfter(0),
310 offsetStackAfter(nullptr),
311 jumpOrigins(alloc)
312#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
313 {
314 }
315
316 // Whether this instruction has been analyzed to get its output defines
317 // and stack.
318 bool parsed;
319
320 // Stack depth before this opcode.
321 uint32_t stackDepth;
322
323 // Pointer to array of |stackDepth| offsets. An element at position N
324 // in the array is the offset of the opcode that defined the
325 // corresponding stack slot. The top of the stack is at position
326 // |stackDepth - 1|.
327 OffsetAndDefIndex* offsetStack;
328
329#if defined(DEBUG1) || defined(JS_JITSPEW1)
330 // stack depth after this opcode.
331 uint32_t stackDepthAfter;
332
333 // Pointer to array of |stackDepthAfter| offsets.
334 OffsetAndDefIndex* offsetStackAfter;
335
336 struct JumpInfo {
337 uint32_t from;
338 JumpKind kind;
339
340 JumpInfo(uint32_t from_, JumpKind kind_) : from(from_), kind(kind_) {}
341 };
342
343 // A list of offsets of the bytecode that jumps to this bytecode,
344 // exclusing previous bytecode.
345 Vector<JumpInfo, 0, LifoAllocPolicy<Fallible>> jumpOrigins;
346#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
347
348 bool captureOffsetStack(LifoAlloc& alloc, const OffsetAndDefIndex* stack,
349 uint32_t depth) {
350 stackDepth = depth;
351 if (stackDepth) {
352 offsetStack = alloc.newArray<OffsetAndDefIndex>(stackDepth);
353 if (!offsetStack) {
354 return false;
355 }
356 for (uint32_t n = 0; n < stackDepth; n++) {
357 offsetStack[n] = stack[n];
358 }
359 }
360 return true;
361 }
362
363#if defined(DEBUG1) || defined(JS_JITSPEW1)
364 bool captureOffsetStackAfter(LifoAlloc& alloc,
365 const OffsetAndDefIndex* stack,
366 uint32_t depth) {
367 stackDepthAfter = depth;
368 if (stackDepthAfter) {
369 offsetStackAfter = alloc.newArray<OffsetAndDefIndex>(stackDepthAfter);
370 if (!offsetStackAfter) {
371 return false;
372 }
373 for (uint32_t n = 0; n < stackDepthAfter; n++) {
374 offsetStackAfter[n] = stack[n];
375 }
376 }
377 return true;
378 }
379
380 bool addJump(uint32_t from, JumpKind kind) {
381 return jumpOrigins.append(JumpInfo(from, kind));
382 }
383#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
384
385 // When control-flow merges, intersect the stacks, marking slots that
386 // are defined by different offsets and/or defIndices merged.
387 // This is sufficient for forward control-flow. It doesn't grok loops
388 // -- for that you would have to iterate to a fixed point -- but there
389 // shouldn't be operands on the stack at a loop back-edge anyway.
390 void mergeOffsetStack(const OffsetAndDefIndex* stack, uint32_t depth) {
391 MOZ_ASSERT(depth == stackDepth)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(depth == stackDepth)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(depth == stackDepth))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("depth == stackDepth"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 391); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "depth == stackDepth" ")"); do { MOZ_CrashSequence
(__null, 391); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
392 for (uint32_t n = 0; n < stackDepth; n++) {
393 if (stack[n].isIgnored()) {
394 continue;
395 }
396 if (offsetStack[n].isIgnored()) {
397 offsetStack[n] = stack[n];
398 }
399 if (offsetStack[n] != stack[n]) {
400 offsetStack[n].setMerged();
401 }
402 }
403 }
404 };
405
406 JSContext* cx_;
407 LifoAlloc& alloc_;
408 RootedScript script_;
409
410 Bytecode** codeArray_;
411
412#if defined(DEBUG1) || defined(JS_JITSPEW1)
413 // Dedicated mode for stack dump.
414 // Capture stack after each opcode, and also enable special handling for
415 // some opcodes to make stack transition clearer.
416 bool isStackDump = false;
417#endif
418
419 public:
420 BytecodeParser(JSContext* cx, LifoAlloc& alloc, JSScript* script)
421 : cx_(cx), alloc_(alloc), script_(cx, script), codeArray_(nullptr) {}
422
423 bool parse();
424
425#if defined(DEBUG1) || defined(JS_JITSPEW1)
426 bool isReachable(const jsbytecode* pc) const { return maybeCode(pc); }
427#endif
428
429 uint32_t stackDepthAtPC(uint32_t offset) const {
430 // Sometimes the code generator in debug mode asks about the stack depth
431 // of unreachable code (bug 932180 comment 22). Assume that unreachable
432 // code has no operands on the stack.
433 return getCode(offset).stackDepth;
434 }
435 uint32_t stackDepthAtPC(const jsbytecode* pc) const {
436 return stackDepthAtPC(script_->pcToOffset(pc));
437 }
438
439#if defined(DEBUG1) || defined(JS_JITSPEW1)
440 uint32_t stackDepthAfterPC(uint32_t offset) const {
441 return getCode(offset).stackDepthAfter;
442 }
443 uint32_t stackDepthAfterPC(const jsbytecode* pc) const {
444 return stackDepthAfterPC(script_->pcToOffset(pc));
445 }
446#endif
447
448 const OffsetAndDefIndex& offsetForStackOperand(uint32_t offset,
449 int operand) const {
450 Bytecode& code = getCode(offset);
451 if (operand < 0) {
452 operand += code.stackDepth;
453 MOZ_ASSERT(operand >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(operand >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(operand >= 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("operand >= 0"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 453); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "operand >= 0" ")"); do { MOZ_CrashSequence
(__null, 453); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
454 }
455 MOZ_ASSERT(uint32_t(operand) < code.stackDepth)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uint32_t(operand) < code.stackDepth)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(uint32_t(operand) < code.stackDepth))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("uint32_t(operand) < code.stackDepth"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 455); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "uint32_t(operand) < code.stackDepth" ")"
); do { MOZ_CrashSequence(__null, 455); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
456 return code.offsetStack[operand];
457 }
458 jsbytecode* pcForStackOperand(jsbytecode* pc, int operand,
459 uint8_t* defIndex) const {
460 size_t offset = script_->pcToOffset(pc);
461 const OffsetAndDefIndex& offsetAndDefIndex =
462 offsetForStackOperand(offset, operand);
463 if (offsetAndDefIndex.isSpecial()) {
464 return nullptr;
465 }
466 *defIndex = offsetAndDefIndex.defIndex();
467 return script_->offsetToPC(offsetAndDefIndex.offset());
468 }
469
470#if defined(DEBUG1) || defined(JS_JITSPEW1)
471 const OffsetAndDefIndex& offsetForStackOperandAfterPC(uint32_t offset,
472 int operand) const {
473 Bytecode& code = getCode(offset);
474 if (operand < 0) {
475 operand += code.stackDepthAfter;
476 MOZ_ASSERT(operand >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(operand >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(operand >= 0))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("operand >= 0"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 476); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "operand >= 0" ")"); do { MOZ_CrashSequence
(__null, 476); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
477 }
478 MOZ_ASSERT(uint32_t(operand) < code.stackDepthAfter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uint32_t(operand) < code.stackDepthAfter)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(uint32_t(operand) < code.stackDepthAfter))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("uint32_t(operand) < code.stackDepthAfter"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 478); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "uint32_t(operand) < code.stackDepthAfter"
")"); do { MOZ_CrashSequence(__null, 478); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
479 return code.offsetStackAfter[operand];
480 }
481
482 template <typename Callback>
483 bool forEachJumpOrigins(jsbytecode* pc, Callback callback) const {
484 Bytecode& code = getCode(script_->pcToOffset(pc));
485
486 for (Bytecode::JumpInfo& info : code.jumpOrigins) {
487 if (!callback(script_->offsetToPC(info.from), info.kind)) {
488 return false;
489 }
490 }
491
492 return true;
493 }
494
495 void setStackDump() { isStackDump = true; }
496#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
497
498 private:
499 LifoAlloc& alloc() { return alloc_; }
500
501 void reportOOM() { ReportOutOfMemory(cx_); }
502
503 uint32_t maximumStackDepth() const {
504 return script_->nslots() - script_->nfixed();
505 }
506
507 Bytecode& getCode(uint32_t offset) const {
508 MOZ_ASSERT(offset < script_->length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(offset < script_->length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(offset < script_->length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("offset < script_->length()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset < script_->length()"
")"); do { MOZ_CrashSequence(__null, 508); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
509 MOZ_ASSERT(codeArray_[offset])do { static_assert( mozilla::detail::AssertionConditionType<
decltype(codeArray_[offset])>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(codeArray_[offset]))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("codeArray_[offset]"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 509); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "codeArray_[offset]" ")"); do { MOZ_CrashSequence
(__null, 509); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
510 return *codeArray_[offset];
511 }
512
513 Bytecode* maybeCode(uint32_t offset) const {
514 MOZ_ASSERT(offset < script_->length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(offset < script_->length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(offset < script_->length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("offset < script_->length()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 514); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset < script_->length()"
")"); do { MOZ_CrashSequence(__null, 514); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
515 return codeArray_[offset];
516 }
517
518#if defined(DEBUG1) || defined(JS_JITSPEW1)
519 Bytecode* maybeCode(const jsbytecode* pc) const {
520 return maybeCode(script_->pcToOffset(pc));
521 }
522#endif
523
524 uint32_t simulateOp(JSOp op, uint32_t offset, OffsetAndDefIndex* offsetStack,
525 uint32_t stackDepth);
526
527 inline bool recordBytecode(uint32_t offset,
528 const OffsetAndDefIndex* offsetStack,
529 uint32_t stackDepth);
530
531 inline bool addJump(uint32_t offset, uint32_t stackDepth,
532 const OffsetAndDefIndex* offsetStack, jsbytecode* pc,
533 JumpKind kind);
534};
535
536} // anonymous namespace
537
538uint32_t BytecodeParser::simulateOp(JSOp op, uint32_t offset,
539 OffsetAndDefIndex* offsetStack,
540 uint32_t stackDepth) {
541 jsbytecode* pc = script_->offsetToPC(offset);
542 uint32_t nuses = GetUseCount(pc);
543 uint32_t ndefs = GetDefCount(pc);
544
545 MOZ_RELEASE_ASSERT(stackDepth >= nuses)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stackDepth >= nuses)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stackDepth >= nuses))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("stackDepth >= nuses"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 545); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "stackDepth >= nuses" ")"); do {
MOZ_CrashSequence(__null, 545); __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
546 stackDepth -= nuses;
547 MOZ_RELEASE_ASSERT(stackDepth + ndefs <= maximumStackDepth())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stackDepth + ndefs <= maximumStackDepth())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(stackDepth + ndefs <= maximumStackDepth()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("stackDepth + ndefs <= maximumStackDepth()"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 547); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "stackDepth + ndefs <= maximumStackDepth()"
")"); do { MOZ_CrashSequence(__null, 547); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
548
549#ifdef DEBUG1
550 if (isStackDump) {
551 // Opcodes that modifies the object but keeps it on the stack while
552 // initialization should be listed here instead of switch below.
553 // For error message, they shouldn't be shown as the original object
554 // after adding properties.
555 // For stack dump, keeping the input is better.
556 switch (op) {
557 case JSOp::InitHiddenProp:
558 case JSOp::InitHiddenPropGetter:
559 case JSOp::InitHiddenPropSetter:
560 case JSOp::InitLockedProp:
561 case JSOp::InitProp:
562 case JSOp::InitPropGetter:
563 case JSOp::InitPropSetter:
564 case JSOp::MutateProto:
565 case JSOp::SetFunName:
566 // Keep the second value.
567 MOZ_ASSERT(nuses == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 2" ")"
); do { MOZ_CrashSequence(__null, 567); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
568 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 568); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 568); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
569 goto end;
570
571 case JSOp::InitElem:
572 case JSOp::InitElemGetter:
573 case JSOp::InitElemSetter:
574 case JSOp::InitHiddenElem:
575 case JSOp::InitHiddenElemGetter:
576 case JSOp::InitHiddenElemSetter:
577 case JSOp::InitLockedElem:
578 // Keep the third value.
579 MOZ_ASSERT(nuses == 3)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 3)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 3))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 3", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 579); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 3" ")"
); do { MOZ_CrashSequence(__null, 579); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
580 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 580); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
581 goto end;
582
583 default:
584 break;
585 }
586 }
587#endif /* DEBUG */
588
589 // Mark the current offset as defining its values on the offset stack,
590 // unless it just reshuffles the stack. In that case we want to preserve
591 // the opcode that generated the original value.
592 switch (op) {
593 default:
594 for (uint32_t n = 0; n != ndefs; ++n) {
595 offsetStack[stackDepth + n].set(offset, n);
596 }
597 break;
598
599 case JSOp::NopDestructuring:
600 // Poison the last offset to not obfuscate the error message.
601 offsetStack[stackDepth - 1].setIgnored();
602 break;
603
604 case JSOp::Case:
605 // Keep the switch value.
606 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 606); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
607 break;
608
609 case JSOp::Dup:
610 MOZ_ASSERT(ndefs == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 2" ")"
); do { MOZ_CrashSequence(__null, 610); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
611 offsetStack[stackDepth + 1] = offsetStack[stackDepth];
612 break;
613
614 case JSOp::Dup2:
615 MOZ_ASSERT(ndefs == 4)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 4)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 4))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 4", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 615); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 4" ")"
); do { MOZ_CrashSequence(__null, 615); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
616 offsetStack[stackDepth + 2] = offsetStack[stackDepth];
617 offsetStack[stackDepth + 3] = offsetStack[stackDepth + 1];
618 break;
619
620 case JSOp::DupAt: {
621 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 621); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 621); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
622 unsigned n = GET_UINT24(pc);
623 MOZ_ASSERT(n < stackDepth)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(n < stackDepth)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(n < stackDepth))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("n < stackDepth"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 623); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "n < stackDepth" ")"); do { MOZ_CrashSequence
(__null, 623); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
624 offsetStack[stackDepth] = offsetStack[stackDepth - 1 - n];
625 break;
626 }
627
628 case JSOp::Swap: {
629 MOZ_ASSERT(ndefs == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 2" ")"
); do { MOZ_CrashSequence(__null, 629); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
630 OffsetAndDefIndex tmp = offsetStack[stackDepth + 1];
631 offsetStack[stackDepth + 1] = offsetStack[stackDepth];
632 offsetStack[stackDepth] = tmp;
633 break;
634 }
635
636 case JSOp::Pick: {
637 unsigned n = GET_UINT8(pc);
638 MOZ_ASSERT(ndefs == n + 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == n + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == n + 1))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("ndefs == n + 1"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 638); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ndefs == n + 1" ")"); do { MOZ_CrashSequence
(__null, 638); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
639 uint32_t top = stackDepth + n;
640 OffsetAndDefIndex tmp = offsetStack[stackDepth];
641 for (uint32_t i = stackDepth; i < top; i++) {
642 offsetStack[i] = offsetStack[i + 1];
643 }
644 offsetStack[top] = tmp;
645 break;
646 }
647
648 case JSOp::Unpick: {
649 unsigned n = GET_UINT8(pc);
650 MOZ_ASSERT(ndefs == n + 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == n + 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == n + 1))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("ndefs == n + 1"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 650); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ndefs == n + 1" ")"); do { MOZ_CrashSequence
(__null, 650); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
651 uint32_t top = stackDepth + n;
652 OffsetAndDefIndex tmp = offsetStack[top];
653 for (uint32_t i = top; i > stackDepth; i--) {
654 offsetStack[i] = offsetStack[i - 1];
655 }
656 offsetStack[stackDepth] = tmp;
657 break;
658 }
659
660 case JSOp::And:
661 case JSOp::CheckIsObj:
662 case JSOp::CheckObjCoercible:
663 case JSOp::CheckThis:
664 case JSOp::CheckThisReinit:
665 case JSOp::CheckClassHeritage:
666 case JSOp::DebugCheckSelfHosted:
667 case JSOp::InitGLexical:
668 case JSOp::InitLexical:
669 case JSOp::Or:
670 case JSOp::Coalesce:
671 case JSOp::SetAliasedVar:
672 case JSOp::SetArg:
673 case JSOp::SetIntrinsic:
674 case JSOp::SetLocal:
675 case JSOp::InitAliasedLexical:
676 case JSOp::CheckLexical:
677 case JSOp::CheckAliasedLexical:
678 // Keep the top value.
679 MOZ_ASSERT(nuses == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 1" ")"
); do { MOZ_CrashSequence(__null, 679); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
680 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 680); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
681 break;
682
683 case JSOp::InitHomeObject:
684 // Pop the top value, keep the other value.
685 MOZ_ASSERT(nuses == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 685); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 2" ")"
); do { MOZ_CrashSequence(__null, 685); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
686 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 686); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
687 break;
688
689 case JSOp::SetGName:
690 case JSOp::SetName:
691 case JSOp::SetProp:
692 case JSOp::StrictSetGName:
693 case JSOp::StrictSetName:
694 case JSOp::StrictSetProp:
695 // Keep the top value, removing other 1 value.
696 MOZ_ASSERT(nuses == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 2" ")"
); do { MOZ_CrashSequence(__null, 696); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
697 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 697); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 697); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
698 offsetStack[stackDepth] = offsetStack[stackDepth + 1];
699 break;
700
701 case JSOp::SetPropSuper:
702 case JSOp::StrictSetPropSuper:
703 // Keep the top value, removing other 2 values.
704 MOZ_ASSERT(nuses == 3)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 3)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 3))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 3", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 3" ")"
); do { MOZ_CrashSequence(__null, 704); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
705 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 705); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
706 offsetStack[stackDepth] = offsetStack[stackDepth + 2];
707 break;
708
709 case JSOp::SetElemSuper:
710 case JSOp::StrictSetElemSuper:
711 // Keep the top value, removing other 3 values.
712 MOZ_ASSERT(nuses == 4)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 4)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 4))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 4", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 712); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 4" ")"
); do { MOZ_CrashSequence(__null, 712); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
713 MOZ_ASSERT(ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 1" ")"
); do { MOZ_CrashSequence(__null, 713); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
714 offsetStack[stackDepth] = offsetStack[stackDepth + 3];
715 break;
716
717 case JSOp::IsNoIter:
718 case JSOp::IsNullOrUndefined:
719 case JSOp::MoreIter:
720 case JSOp::CanSkipAwait:
721 // Keep the top value and push one more value.
722 MOZ_ASSERT(nuses == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 1))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 1", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 722); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 1" ")"
); do { MOZ_CrashSequence(__null, 722); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
723 MOZ_ASSERT(ndefs == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 723); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 2" ")"
); do { MOZ_CrashSequence(__null, 723); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
724 offsetStack[stackDepth + 1].set(offset, 1);
725 break;
726
727 case JSOp::MaybeExtractAwaitValue:
728 // Keep the top value and replace the second to top value.
729 MOZ_ASSERT(nuses == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 729); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 2" ")"
); do { MOZ_CrashSequence(__null, 729); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
730 MOZ_ASSERT(ndefs == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 730); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 2" ")"
); do { MOZ_CrashSequence(__null, 730); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
731 offsetStack[stackDepth].set(offset, 0);
732 break;
733
734 case JSOp::CheckPrivateField:
735 // Keep the top two values, and push one new value.
736 MOZ_ASSERT(nuses == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nuses == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nuses == 2))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("nuses == 2", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nuses == 2" ")"
); do { MOZ_CrashSequence(__null, 736); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
737 MOZ_ASSERT(ndefs == 3)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ndefs == 3)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ndefs == 3))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("ndefs == 3", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ndefs == 3" ")"
); do { MOZ_CrashSequence(__null, 737); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
738 offsetStack[stackDepth + 2].set(offset, 2);
739 break;
740 }
741
742#ifdef DEBUG1
743end:
744#endif /* DEBUG */
745
746 stackDepth += ndefs;
747 return stackDepth;
748}
749
750bool BytecodeParser::recordBytecode(uint32_t offset,
751 const OffsetAndDefIndex* offsetStack,
752 uint32_t stackDepth) {
753 MOZ_RELEASE_ASSERT(offset < script_->length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(offset < script_->length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(offset < script_->length
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("offset < script_->length()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 753); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "offset < script_->length()"
")"); do { MOZ_CrashSequence(__null, 753); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
754 MOZ_RELEASE_ASSERT(stackDepth <= maximumStackDepth())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stackDepth <= maximumStackDepth())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stackDepth <= maximumStackDepth
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("stackDepth <= maximumStackDepth()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 754); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "stackDepth <= maximumStackDepth()"
")"); do { MOZ_CrashSequence(__null, 754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
755
756 Bytecode*& code = codeArray_[offset];
757 if (!code) {
758 code = alloc().new_<Bytecode>(alloc());
759 if (!code || !code->captureOffsetStack(alloc(), offsetStack, stackDepth)) {
760 reportOOM();
761 return false;
762 }
763 } else {
764 code->mergeOffsetStack(offsetStack, stackDepth);
765 }
766
767 return true;
768}
769
770bool BytecodeParser::addJump(uint32_t offset, uint32_t stackDepth,
771 const OffsetAndDefIndex* offsetStack,
772 jsbytecode* pc, JumpKind kind) {
773 if (!recordBytecode(offset, offsetStack, stackDepth)) {
774 return false;
775 }
776
777#ifdef DEBUG1
778 uint32_t currentOffset = script_->pcToOffset(pc);
779 if (isStackDump) {
780 if (!codeArray_[offset]->addJump(currentOffset, kind)) {
781 reportOOM();
782 return false;
783 }
784 }
785
786 // If this is a backedge, assert we parsed the target JSOp::LoopHead.
787 MOZ_ASSERT_IF(offset < currentOffset, codeArray_[offset]->parsed)do { if (offset < currentOffset) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(codeArray_[offset
]->parsed)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(codeArray_[offset]->parsed))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("codeArray_[offset]->parsed"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 787); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "codeArray_[offset]->parsed" ")"); do { MOZ_CrashSequence
(__null, 787); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
;
788#endif /* DEBUG */
789
790 return true;
791}
792
793bool BytecodeParser::parse() {
794 MOZ_ASSERT(!codeArray_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!codeArray_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!codeArray_))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!codeArray_", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!codeArray_"
")"); do { MOZ_CrashSequence(__null, 794); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
795
796 uint32_t length = script_->length();
797 codeArray_ = alloc().newArray<Bytecode*>(length);
798
799 if (!codeArray_) {
800 reportOOM();
801 return false;
802 }
803
804 mozilla::PodZero(codeArray_, length);
805
806 // Fill in stack depth and definitions at initial bytecode.
807 Bytecode* startcode = alloc().new_<Bytecode>(alloc());
808 if (!startcode) {
809 reportOOM();
810 return false;
811 }
812
813 // Fill in stack depth and definitions at initial bytecode.
814 OffsetAndDefIndex* offsetStack =
815 alloc().newArray<OffsetAndDefIndex>(maximumStackDepth());
816 if (maximumStackDepth() && !offsetStack) {
817 reportOOM();
818 return false;
819 }
820
821 startcode->stackDepth = 0;
822 codeArray_[0] = startcode;
823
824 for (uint32_t offset = 0, nextOffset = 0; offset < length;
825 offset = nextOffset) {
826 Bytecode* code = maybeCode(offset);
827 jsbytecode* pc = script_->offsetToPC(offset);
828
829 // Next bytecode to analyze.
830 nextOffset = offset + GetBytecodeLength(pc);
831
832 MOZ_RELEASE_ASSERT(*pc < JSOP_LIMIT)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*pc < JSOP_LIMIT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*pc < JSOP_LIMIT))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("*pc < JSOP_LIMIT"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 832); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "*pc < JSOP_LIMIT" ")"); do { MOZ_CrashSequence
(__null, 832); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
833 JSOp op = JSOp(*pc);
834
835 if (!code) {
836 // Haven't found a path by which this bytecode is reachable.
837 continue;
838 }
839
840 // On a jump target, we reload the offsetStack saved for the current
841 // bytecode, as it contains either the original offset stack, or the
842 // merged offset stack.
843 if (BytecodeIsJumpTarget(op)) {
844 for (uint32_t n = 0; n < code->stackDepth; ++n) {
845 offsetStack[n] = code->offsetStack[n];
846 }
847 }
848
849 if (code->parsed) {
850 // No need to reparse.
851 continue;
852 }
853
854 code->parsed = true;
855
856 uint32_t stackDepth = simulateOp(op, offset, offsetStack, code->stackDepth);
857
858#if defined(DEBUG1) || defined(JS_JITSPEW1)
859 if (isStackDump) {
860 if (!code->captureOffsetStackAfter(alloc(), offsetStack, stackDepth)) {
861 reportOOM();
862 return false;
863 }
864 }
865#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
866
867 switch (op) {
868 case JSOp::TableSwitch: {
869 uint32_t defaultOffset = offset + GET_JUMP_OFFSET(pc);
870 jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
871 int32_t low = GET_JUMP_OFFSET(pc2);
872 pc2 += JUMP_OFFSET_LEN;
873 int32_t high = GET_JUMP_OFFSET(pc2);
874 pc2 += JUMP_OFFSET_LEN;
875
876 if (!addJump(defaultOffset, stackDepth, offsetStack, pc,
877 JumpKind::SwitchDefault)) {
878 return false;
879 }
880
881 uint32_t ncases = high - low + 1;
882
883 for (uint32_t i = 0; i < ncases; i++) {
884 uint32_t targetOffset = script_->tableSwitchCaseOffset(pc, i);
885 if (targetOffset != defaultOffset) {
886 if (!addJump(targetOffset, stackDepth, offsetStack, pc,
887 JumpKind::SwitchCase)) {
888 return false;
889 }
890 }
891 }
892 break;
893 }
894
895 case JSOp::Try: {
896 // Everything between a try and corresponding catch or finally is
897 // conditional. Note that there is no problem with code which is skipped
898 // by a thrown exception but is not caught by a later handler in the
899 // same function: no more code will execute, and it does not matter what
900 // is defined.
901 for (const TryNote& tn : script_->trynotes()) {
902 if (tn.start == offset + JSOpLength_Try) {
903 uint32_t catchOffset = tn.start + tn.length;
904 if (tn.kind() == TryNoteKind::Catch) {
905 if (!addJump(catchOffset, stackDepth, offsetStack, pc,
906 JumpKind::TryCatch)) {
907 return false;
908 }
909 } else if (tn.kind() == TryNoteKind::Finally) {
910 // Three additional values will be on the stack at the beginning
911 // of the finally block: the exception/resume index, the exception
912 // stack, and the |throwing| value. For the benefit of the
913 // decompiler, point them at this Try.
914 offsetStack[stackDepth].set(offset, 0);
915 offsetStack[stackDepth + 1].set(offset, 1);
916 offsetStack[stackDepth + 2].set(offset, 2);
917 if (!addJump(catchOffset, stackDepth + 3, offsetStack, pc,
918 JumpKind::TryFinally)) {
919 return false;
920 }
921 }
922 }
923 }
924 break;
925 }
926
927 default:
928 break;
929 }
930
931 // Check basic jump opcodes, which may or may not have a fallthrough.
932 if (IsJumpOpcode(op)) {
933 // Case instructions do not push the lvalue back when branching.
934 uint32_t newStackDepth = stackDepth;
935 if (op == JSOp::Case) {
936 newStackDepth--;
937 }
938
939 uint32_t targetOffset = offset + GET_JUMP_OFFSET(pc);
940 if (!addJump(targetOffset, newStackDepth, offsetStack, pc,
941 JumpKind::Simple)) {
942 return false;
943 }
944 }
945
946 // Handle any fallthrough from this opcode.
947 if (BytecodeFallsThrough(op)) {
948 if (!recordBytecode(nextOffset, offsetStack, stackDepth)) {
949 return false;
950 }
951 }
952 }
953
954 return true;
955}
956
957#if defined(DEBUG1) || defined(JS_JITSPEW1)
958
959bool js::ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc,
960 uint32_t* depth, bool* reachablePC) {
961 LifoAllocScope allocScope(&cx->tempLifoAlloc());
962 BytecodeParser parser(cx, allocScope.alloc(), script);
963 if (!parser.parse()) {
964 return false;
965 }
966
967 *reachablePC = parser.isReachable(pc);
968
969 if (*reachablePC) {
970 *depth = parser.stackDepthAtPC(pc);
971 }
972
973 return true;
974}
975
976static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
977 unsigned loc, bool lines,
978 const BytecodeParser* parser, StringPrinter* sp);
979
980/*
981 * If pc != nullptr, include a prefix indicating whether the PC is at the
982 * current line. If showAll is true, include the entry stack depth.
983 */
984[[nodiscard]] static bool DisassembleAtPC(
985 JSContext* cx, JSScript* scriptArg, bool lines, const jsbytecode* pc,
986 bool showAll, StringPrinter* sp,
987 DisassembleSkeptically skeptically = DisassembleSkeptically::No) {
988 LifoAllocScope allocScope(&cx->tempLifoAlloc());
989 RootedScript script(cx, scriptArg);
990 mozilla::Maybe<BytecodeParser> parser;
991
992 if (skeptically == DisassembleSkeptically::No) {
993 parser.emplace(cx, allocScope.alloc(), script);
994 parser->setStackDump();
995 if (!parser->parse()) {
996 return false;
997 }
998 }
999
1000 if (showAll) {
1001 sp->printf("%s:%u\n", script->filename(), unsigned(script->lineno()));
1002 }
1003
1004 if (pc != nullptr) {
1005 sp->put(" ");
1006 }
1007 if (showAll) {
1008 sp->put("sn stack ");
1009 }
1010 sp->put("loc ");
1011 if (lines) {
1012 sp->put("line");
1013 }
1014 sp->put(" op\n");
1015
1016 if (pc != nullptr) {
1017 sp->put(" ");
1018 }
1019 if (showAll) {
1020 sp->put("-- ----- ");
1021 }
1022 sp->put("----- ");
1023 if (lines) {
1024 sp->put("----");
1025 }
1026 sp->put(" --\n");
1027
1028 jsbytecode* next = script->code();
1029 jsbytecode* end = script->codeEnd();
1030 while (next < end) {
1031 if (next == script->main()) {
1032 sp->put("main:\n");
1033 }
1034 if (pc != nullptr) {
1035 sp->put(pc == next ? "--> " : " ");
1036 }
1037 if (showAll) {
1038 if (parser && parser->isReachable(next)) {
1039 sp->printf("%05u ", parser->stackDepthAtPC(next));
1040 } else {
1041 sp->put(" ");
1042 }
1043 }
1044 unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next),
1045 lines, parser.ptrOr(nullptr), sp);
1046 if (!len) {
1047 return false;
1048 }
1049
1050 next += len;
1051 }
1052
1053 return true;
1054}
1055
1056bool js::Disassemble(JSContext* cx, HandleScript script, bool lines,
1057 StringPrinter* sp, DisassembleSkeptically skeptically) {
1058 return DisassembleAtPC(cx, script, lines, nullptr, false, sp, skeptically);
1059}
1060
1061JS_PUBLIC_API bool js::DumpPC(JSContext* cx, FILE* fp) {
1062 gc::AutoSuppressGC suppressGC(cx);
1063 Sprinter sprinter(cx);
1064 if (!sprinter.init()) {
1065 return false;
1066 }
1067 ScriptFrameIter iter(cx);
1068 if (iter.done()) {
1069 fprintf(fp, "Empty stack.\n");
1070 return true;
1071 }
1072 RootedScript script(cx, iter.script());
1073 bool ok = DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
1074 JS::UniqueChars out = sprinter.release();
1075 if (!out) {
1076 return false;
1077 }
1078 fprintf(fp, "%s", out.get());
1079 return ok;
1080}
1081
1082JS_PUBLIC_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg,
1083 FILE* fp) {
1084 gc::AutoSuppressGC suppressGC(cx);
1085 Sprinter sprinter(cx);
1086 if (!sprinter.init()) {
1087 return false;
1088 }
1089 RootedScript script(cx, scriptArg);
1090 bool ok = Disassemble(cx, script, true, &sprinter);
1091 JS::UniqueChars out = sprinter.release();
1092 if (!out) {
1093 return false;
1094 }
1095 fprintf(fp, "%s", out.get());
1096 return ok;
1097}
1098
1099UniqueChars js::ToDisassemblySource(JSContext* cx, HandleValue v) {
1100 if (v.isString()) {
1101 return QuoteString(cx, v.toString(), '"');
1102 }
1103
1104 if (JS::RuntimeHeapIsBusy()) {
1105 return DuplicateString(cx, "<value>");
1106 }
1107
1108 if (v.isObject()) {
1109 JSObject& obj = v.toObject();
1110
1111 if (obj.is<JSFunction>()) {
1112 RootedFunction fun(cx, &obj.as<JSFunction>());
1113 JSString* str = JS_DecompileFunction(cx, fun);
1114 if (!str) {
1115 return nullptr;
1116 }
1117 return QuoteString(cx, str);
1118 }
1119
1120 if (obj.is<RegExpObject>()) {
1121 Rooted<RegExpObject*> reobj(cx, &obj.as<RegExpObject>());
1122 JSString* source = RegExpObject::toString(cx, reobj);
1123 if (!source) {
1124 return nullptr;
1125 }
1126 return QuoteString(cx, source);
1127 }
1128 }
1129
1130 JSString* str = ValueToSource(cx, v);
1131 if (!str) {
1132 return nullptr;
1133 }
1134 return QuoteString(cx, str);
1135}
1136
1137static bool ToDisassemblySource(JSContext* cx, Handle<Scope*> scope,
1138 UniqueChars* bytes) {
1139 UniqueChars source = JS_smprintf("%s {", ScopeKindString(scope->kind()));
1140 if (!source) {
1141 ReportOutOfMemory(cx);
1142 return false;
1143 }
1144
1145 for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
1146 UniqueChars nameBytes = AtomToPrintableString(cx, bi.name());
1147 if (!nameBytes) {
1148 return false;
1149 }
1150
1151 source = JS_sprintf_append(std::move(source), "%s: ", nameBytes.get());
1152 if (!source) {
1153 ReportOutOfMemory(cx);
1154 return false;
1155 }
1156
1157 BindingLocation loc = bi.location();
1158 switch (loc.kind()) {
1159 case BindingLocation::Kind::Global:
1160 source = JS_sprintf_append(std::move(source), "global");
1161 break;
1162
1163 case BindingLocation::Kind::Frame:
1164 source =
1165 JS_sprintf_append(std::move(source), "frame slot %u", loc.slot());
1166 break;
1167
1168 case BindingLocation::Kind::Environment:
1169 source =
1170 JS_sprintf_append(std::move(source), "env slot %u", loc.slot());
1171 break;
1172
1173 case BindingLocation::Kind::Argument:
1174 source =
1175 JS_sprintf_append(std::move(source), "arg slot %u", loc.slot());
1176 break;
1177
1178 case BindingLocation::Kind::NamedLambdaCallee:
1179 source = JS_sprintf_append(std::move(source), "named lambda callee");
1180 break;
1181
1182 case BindingLocation::Kind::Import:
1183 source = JS_sprintf_append(std::move(source), "import");
1184 break;
1185 }
1186
1187 if (!source) {
1188 ReportOutOfMemory(cx);
1189 return false;
1190 }
1191
1192 if (!bi.isLast()) {
1193 source = JS_sprintf_append(std::move(source), ", ");
1194 if (!source) {
1195 ReportOutOfMemory(cx);
1196 return false;
1197 }
1198 }
1199 }
1200
1201 source = JS_sprintf_append(std::move(source), "}");
1202 if (!source) {
1203 ReportOutOfMemory(cx);
1204 return false;
1205 }
1206
1207 *bytes = std::move(source);
1208 return true;
1209}
1210
1211static bool DumpJumpOrigins(HandleScript script, jsbytecode* pc,
1212 const BytecodeParser* parser, StringPrinter* sp) {
1213 bool called = false;
1214 auto callback = [&script, &sp, &called](jsbytecode* pc,
1215 BytecodeParser::JumpKind kind) {
1216 if (!called) {
1217 called = true;
1218 sp->put("\n# ");
1219 } else {
1220 sp->put(", ");
1221 }
1222
1223 switch (kind) {
1224 case BytecodeParser::JumpKind::Simple:
1225 break;
1226
1227 case BytecodeParser::JumpKind::SwitchCase:
1228 sp->put("switch-case ");
1229 break;
1230
1231 case BytecodeParser::JumpKind::SwitchDefault:
1232 sp->put("switch-default ");
1233 break;
1234
1235 case BytecodeParser::JumpKind::TryCatch:
1236 sp->put("try-catch ");
1237 break;
1238
1239 case BytecodeParser::JumpKind::TryFinally:
1240 sp->put("try-finally ");
1241 break;
1242 }
1243
1244 sp->printf("from %s @ %05u", CodeName(JSOp(*pc)),
1245 unsigned(script->pcToOffset(pc)));
1246
1247 return true;
1248 };
1249 if (!parser->forEachJumpOrigins(pc, callback)) {
1250 return false;
1251 }
1252 if (called) {
1253 sp->put("\n");
1254 }
1255
1256 return true;
1257}
1258
1259static bool DecompileAtPCForStackDump(
1260 JSContext* cx, HandleScript script,
1261 const OffsetAndDefIndex& offsetAndDefIndex, StringPrinter* sp);
1262
1263static bool PrintShapeProperties(JSContext* cx, StringPrinter* sp,
1264 SharedShape* shape) {
1265 // Add all property keys to a vector to allow printing them in property
1266 // definition order.
1267 Vector<PropertyKey> props(cx);
1268 for (SharedShapePropertyIter<NoGC> iter(shape); !iter.done(); iter++) {
1269 if (!props.append(iter->key())) {
1270 return false;
1271 }
1272 }
1273
1274 sp->put("{");
1275
1276 for (size_t i = props.length(); i > 0; i--) {
1277 PropertyKey key = props[i - 1];
1278 RootedValue keyv(cx, IdToValue(key));
1279 JSString* str = ToString<NoGC>(cx, keyv);
1280 if (!str) {
1281 ReportOutOfMemory(cx);
1282 return false;
1283 }
1284 sp->putString(cx, str);
1285 if (i > 1) {
1286 sp->put(", ");
1287 }
1288 }
1289
1290 sp->put("}");
1291 return true;
1292}
1293
1294static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
1295 unsigned loc, bool lines,
1296 const BytecodeParser* parser, StringPrinter* sp) {
1297 if (parser && parser->isReachable(pc)) {
1298 if (!DumpJumpOrigins(script, pc, parser, sp)) {
1299 return 0;
1300 }
1301 }
1302
1303 size_t before = sp->length();
1304 bool stackDumped = false;
1305 auto dumpStack = [&cx, &script, &pc, &parser, &sp, &before, &stackDumped]() {
1306 if (!parser) {
1307 return true;
1308 }
1309 if (stackDumped) {
1310 return true;
1311 }
1312 stackDumped = true;
1313
1314 size_t after = sp->length();
1315 MOZ_ASSERT(after >= before)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(after >= before)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(after >= before))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("after >= before"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 1315); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "after >= before" ")"); do { MOZ_CrashSequence
(__null, 1315); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1316
1317 static const size_t stack_column = 40;
1318 for (size_t i = after - before; i < stack_column - 1; i++) {
1319 sp->put(" ");
1320 }
1321
1322 sp->put(" # ");
1323
1324 if (!parser->isReachable(pc)) {
1325 sp->put("!!! UNREACHABLE !!!");
1326 } else {
1327 uint32_t depth = parser->stackDepthAfterPC(pc);
1328
1329 for (uint32_t i = 0; i < depth; i++) {
1330 if (i) {
1331 sp->put(" ");
1332 }
1333
1334 const OffsetAndDefIndex& offsetAndDefIndex =
1335 parser->offsetForStackOperandAfterPC(script->pcToOffset(pc), i);
1336 // This will decompile the stack for the same PC many times.
1337 // We'll avoid optimizing it since this is a testing function
1338 // and it won't be worth managing cached expression here.
1339 if (!DecompileAtPCForStackDump(cx, script, offsetAndDefIndex, sp)) {
1340 return false;
1341 }
1342 }
1343 }
1344
1345 return true;
1346 };
1347
1348 if (*pc >= JSOP_LIMIT) {
1349 char numBuf1[12], numBuf2[12];
1350 SprintfLiteral(numBuf1, "%d", int(*pc));
1351 SprintfLiteral(numBuf2, "%d", JSOP_LIMIT);
1352 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1353 JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2);
1354 return 0;
1355 }
1356 JSOp op = JSOp(*pc);
1357 const JSCodeSpec& cs = CodeSpec(op);
1358 const unsigned len = cs.length;
1359 sp->printf("%05u:", loc);
1360 if (lines) {
1361 sp->printf("%4u", PCToLineNumber(script, pc));
1362 }
1363 sp->printf(" %s", CodeName(op));
1364
1365 int i;
1366 switch (JOF_TYPE(cs.format)) {
1367 case JOF_BYTE:
1368 break;
1369
1370 case JOF_JUMP: {
1371 ptrdiff_t off = GET_JUMP_OFFSET(pc);
1372 sp->printf(" %u (%+d)", unsigned(loc + int(off)), int(off));
1373 break;
1374 }
1375
1376 case JOF_SCOPE: {
1377 Rooted<Scope*> scope(cx, script->getScope(pc));
1378 UniqueChars bytes;
1379 if (!ToDisassemblySource(cx, scope, &bytes)) {
1380 return 0;
1381 }
1382 sp->printf(" %s", bytes.get());
1383 break;
1384 }
1385
1386 case JOF_ENVCOORD: {
1387 RootedValue v(cx, StringValue(EnvironmentCoordinateNameSlow(script, pc)));
1388 UniqueChars bytes = ToDisassemblySource(cx, v);
1389 if (!bytes) {
1390 return 0;
1391 }
1392 EnvironmentCoordinate ec(pc);
1393 sp->printf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(),
1394 ec.slot());
1395 break;
1396 }
1397 case JOF_DEBUGCOORD: {
1398 EnvironmentCoordinate ec(pc);
1399 sp->printf("(hops = %u, slot = %u)", ec.hops(), ec.slot());
1400 break;
1401 }
1402 case JOF_ATOM: {
1403 RootedValue v(cx, StringValue(script->getAtom(pc)));
1404 UniqueChars bytes = ToDisassemblySource(cx, v);
1405 if (!bytes) {
1406 return 0;
1407 }
1408 sp->printf(" %s", bytes.get());
1409 break;
1410 }
1411 case JOF_STRING: {
1412 RootedValue v(cx, StringValue(script->getString(pc)));
1413 UniqueChars bytes = ToDisassemblySource(cx, v);
1414 if (!bytes) {
1415 return 0;
1416 }
1417 sp->printf(" %s", bytes.get());
1418 break;
1419 }
1420
1421 case JOF_DOUBLE: {
1422 double d = GET_INLINE_VALUE(pc).toDouble();
1423 sp->printf(" %lf", d);
1424 break;
1425 }
1426
1427 case JOF_BIGINT: {
1428 RootedValue v(cx, BigIntValue(script->getBigInt(pc)));
1429 UniqueChars bytes = ToDisassemblySource(cx, v);
1430 if (!bytes) {
1431 return 0;
1432 }
1433 sp->printf(" %s", bytes.get());
1434 break;
1435 }
1436
1437 case JOF_OBJECT: {
1438 JSObject* obj = script->getObject(pc);
1439 {
1440 RootedValue v(cx, ObjectValue(*obj));
1441 UniqueChars bytes = ToDisassemblySource(cx, v);
1442 if (!bytes) {
1443 return 0;
1444 }
1445 sp->printf(" %s", bytes.get());
1446 }
1447 break;
1448 }
1449
1450 case JOF_SHAPE: {
1451 SharedShape* shape = script->getShape(pc);
1452 sp->put(" ");
1453 if (!PrintShapeProperties(cx, sp, shape)) {
1454 return 0;
1455 }
1456 break;
1457 }
1458
1459 case JOF_REGEXP: {
1460 js::RegExpObject* obj = script->getRegExp(pc);
1461 RootedValue v(cx, ObjectValue(*obj));
1462 UniqueChars bytes = ToDisassemblySource(cx, v);
1463 if (!bytes) {
1464 return 0;
1465 }
1466 sp->printf(" %s", bytes.get());
1467 break;
1468 }
1469
1470 case JOF_TABLESWITCH: {
1471 int32_t i, low, high;
1472
1473 ptrdiff_t off = GET_JUMP_OFFSET(pc);
1474 jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
1475 low = GET_JUMP_OFFSET(pc2);
1476 pc2 += JUMP_OFFSET_LEN;
1477 high = GET_JUMP_OFFSET(pc2);
1478 pc2 += JUMP_OFFSET_LEN;
Value stored to 'pc2' is never read
1479 sp->printf(" defaultOffset %d low %d high %d", int(off), low, high);
1480
1481 // Display stack dump before diplaying the offsets for each case.
1482 if (!dumpStack()) {
1483 return 0;
1484 }
1485
1486 for (i = low; i <= high; i++) {
1487 off =
1488 script->tableSwitchCaseOffset(pc, i - low) - script->pcToOffset(pc);
1489 sp->printf("\n\t%d: %d", i, int(off));
1490 }
1491 break;
1492 }
1493
1494 case JOF_QARG:
1495 sp->printf(" %u", GET_ARGNO(pc));
1496 break;
1497
1498 case JOF_LOCAL:
1499 sp->printf(" %u", GET_LOCALNO(pc));
1500 break;
1501
1502 case JOF_GCTHING:
1503 sp->printf(" %u", unsigned(GET_GCTHING_INDEX(pc)));
1504 break;
1505
1506 case JOF_UINT32:
1507 sp->printf(" %u", GET_UINT32(pc));
1508 break;
1509
1510 case JOF_ICINDEX:
1511 sp->printf(" (ic: %u)", GET_ICINDEX(pc));
1512 break;
1513
1514 case JOF_LOOPHEAD:
1515 sp->printf(" (ic: %u, depthHint: %u)", GET_ICINDEX(pc),
1516 LoopHeadDepthHint(pc));
1517 break;
1518
1519 case JOF_TWO_UINT8: {
1520 int one = (int)GET_UINT8(pc);
1521 int two = (int)GET_UINT8(pc + 1);
1522
1523 sp->printf(" %d", one);
1524 sp->printf(" %d", two);
1525 break;
1526 }
1527
1528 case JOF_ARGC:
1529 case JOF_UINT16:
1530 i = (int)GET_UINT16(pc);
1531 goto print_int;
1532
1533 case JOF_RESUMEINDEX:
1534 case JOF_UINT24:
1535 MOZ_ASSERT(len == 4)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(len == 4)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(len == 4))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("len == 4", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 1535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "len == 4" ")"
); do { MOZ_CrashSequence(__null, 1535); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1536 i = (int)GET_UINT24(pc);
1537 goto print_int;
1538
1539 case JOF_UINT8:
1540 i = GET_UINT8(pc);
1541 goto print_int;
1542
1543 case JOF_INT8:
1544 i = GET_INT8(pc);
1545 goto print_int;
1546
1547 case JOF_INT32:
1548 MOZ_ASSERT(op == JSOp::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::Int32))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::Int32"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 1548); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "op == JSOp::Int32" ")"); do { MOZ_CrashSequence
(__null, 1548); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1549 i = GET_INT32(pc);
1550 print_int:
1551 sp->printf(" %d", i);
1552 break;
1553
1554 default: {
1555 char numBuf[12];
1556 SprintfLiteral(numBuf, "%x", cs.format);
1557 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1558 JSMSG_UNKNOWN_FORMAT, numBuf);
1559 return 0;
1560 }
1561 }
1562
1563 if (!dumpStack()) {
1564 return 0;
1565 }
1566
1567 sp->put("\n");
1568 return len;
1569}
1570
1571unsigned js::Disassemble1(JSContext* cx, JS::Handle<JSScript*> script,
1572 jsbytecode* pc, unsigned loc, bool lines,
1573 StringPrinter* sp) {
1574 return Disassemble1(cx, script, pc, loc, lines, nullptr, sp);
1575}
1576
1577#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
1578
1579namespace {
1580/*
1581 * The expression decompiler is invoked by error handling code to produce a
1582 * string representation of the erroring expression. As it's only a debugging
1583 * tool, it only supports basic expressions. For anything complicated, it simply
1584 * puts "(intermediate value)" into the error result.
1585 *
1586 * Here's the basic algorithm:
1587 *
1588 * 1. Find the stack location of the value whose expression we wish to
1589 * decompile. The error handler can explicitly pass this as an
1590 * argument. Otherwise, we search backwards down the stack for the offending
1591 * value.
1592 *
1593 * 2. Instantiate and run a BytecodeParser for the current frame. This creates a
1594 * stack of pcs parallel to the interpreter stack; given an interpreter stack
1595 * location, the corresponding pc stack location contains the opcode that pushed
1596 * the value in the interpreter. Now, with the result of step 1, we have the
1597 * opcode responsible for pushing the value we want to decompile.
1598 *
1599 * 3. Pass the opcode to decompilePC. decompilePC is the main decompiler
1600 * routine, responsible for a string representation of the expression that
1601 * generated a certain stack location. decompilePC looks at one opcode and
1602 * returns the JS source equivalent of that opcode.
1603 *
1604 * 4. Expressions can, of course, contain subexpressions. For example, the
1605 * literals "4" and "5" are subexpressions of the addition operator in "4 +
1606 * 5". If we need to decompile a subexpression, we call decompilePC (step 2)
1607 * recursively on the operands' pcs. The result is a depth-first traversal of
1608 * the expression tree.
1609 *
1610 */
1611struct ExpressionDecompiler {
1612 JSContext* cx;
1613 RootedScript script;
1614 const BytecodeParser& parser;
1615 Sprinter sprinter;
1616
1617#if defined(DEBUG1) || defined(JS_JITSPEW1)
1618 // Dedicated mode for stack dump.
1619 // Generates an expression for stack dump, including internal state,
1620 // and also disables special handling for self-hosted code.
1621 bool isStackDump;
1622#endif
1623
1624 ExpressionDecompiler(JSContext* cx, JSScript* script,
1625 const BytecodeParser& parser)
1626 : cx(cx),
1627 script(cx, script),
1628 parser(parser),
1629 sprinter(cx)
1630#if defined(DEBUG1) || defined(JS_JITSPEW1)
1631 ,
1632 isStackDump(false)
1633#endif
1634 {
1635 }
1636 bool init();
1637 bool decompilePCForStackOperand(jsbytecode* pc, int i);
1638 bool decompilePC(jsbytecode* pc, uint8_t defIndex);
1639 bool decompilePC(const OffsetAndDefIndex& offsetAndDefIndex);
1640 JSAtom* getArg(unsigned slot);
1641 JSAtom* loadAtom(jsbytecode* pc);
1642 JSString* loadString(jsbytecode* pc);
1643 bool quote(JSString* s, char quote);
1644 bool write(const char* s);
1645 bool write(JSString* str);
1646 bool write(ConstantCompareOperand* operand);
1647 UniqueChars getOutput();
1648#if defined(DEBUG1) || defined(JS_JITSPEW1)
1649 void setStackDump() { isStackDump = true; }
1650#endif
1651};
1652
1653bool ExpressionDecompiler::decompilePCForStackOperand(jsbytecode* pc, int i) {
1654 return decompilePC(parser.offsetForStackOperand(script->pcToOffset(pc), i));
1655}
1656
1657bool ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex) {
1658 MOZ_ASSERT(script->containsPC(pc))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(script->containsPC(pc))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(script->containsPC(pc))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("script->containsPC(pc)"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 1658); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "script->containsPC(pc)" ")"); do { MOZ_CrashSequence
(__null, 1658); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1659
1660 // The decompiler is invoked from error-reporting code. To avoid reporting a
1661 // nested over-recursion error we fall back to the generic placeholder.
1662 AutoCheckRecursionLimit recursion(cx);
1663 if (!recursion.checkDontReport(cx)) {
1664 return write("(intermediate value)");
1665 }
1666
1667 JSOp op = (JSOp)*pc;
1668
1669 if (const char* token = CodeToken[uint8_t(op)]) {
1670 MOZ_ASSERT(defIndex == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 0",
"./../../../../js/src/vm/BytecodeUtil.cpp", 1670); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 0" ")"); do { MOZ_CrashSequence
(__null, 1670); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1671 MOZ_ASSERT(CodeSpec(op).ndefs == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CodeSpec(op).ndefs == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(CodeSpec(op).ndefs == 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("CodeSpec(op).ndefs == 1"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 1671); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "CodeSpec(op).ndefs == 1" ")"); do { MOZ_CrashSequence
(__null, 1671); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1672
1673 // Handle simple cases of binary and unary operators.
1674 switch (CodeSpec(op).nuses) {
1675 case 2: {
1676 const char* extra = "";
1677
1678 MOZ_ASSERT(pc + 1 < script->codeEnd(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pc + 1 < script->codeEnd())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pc + 1 < script->codeEnd
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pc + 1 < script->codeEnd()" " (" "binary opcode shouldn't be the last opcode in the script"
")", "./../../../../js/src/vm/BytecodeUtil.cpp", 1679); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "pc + 1 < script->codeEnd()" ") (" "binary opcode shouldn't be the last opcode in the script"
")"); do { MOZ_CrashSequence(__null, 1679); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1679 "binary opcode shouldn't be the last opcode in the script")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pc + 1 < script->codeEnd())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pc + 1 < script->codeEnd
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("pc + 1 < script->codeEnd()" " (" "binary opcode shouldn't be the last opcode in the script"
")", "./../../../../js/src/vm/BytecodeUtil.cpp", 1679); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "pc + 1 < script->codeEnd()" ") (" "binary opcode shouldn't be the last opcode in the script"
")"); do { MOZ_CrashSequence(__null, 1679); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1680 if (CodeSpec(op).length == 1 &&
1681 (JSOp)(*(pc + 1)) == JSOp::NopIsAssignOp) {
1682 extra = "=";
1683 }
1684
1685 return write("(") && decompilePCForStackOperand(pc, -2) && write(" ") &&
1686 write(token) && write(extra) && write(" ") &&
1687 decompilePCForStackOperand(pc, -1) && write(")");
1688 break;
1689 }
1690 case 1:
1691 return write("(") && write(token) &&
1692 decompilePCForStackOperand(pc, -1) && write(")");
1693 default:
1694 break;
1695 }
1696 }
1697
1698 switch (op) {
1699 case JSOp::DelName:
1700 return write("(delete ") && write(loadAtom(pc)) && write(")");
1701
1702 case JSOp::GetGName:
1703 case JSOp::GetName:
1704 case JSOp::GetIntrinsic:
1705 return write(loadAtom(pc));
1706 case JSOp::GetArg: {
1707 unsigned slot = GET_ARGNO(pc);
1708
1709 // For self-hosted scripts that are called from non-self-hosted code,
1710 // decompiling the parameter name in the self-hosted script is
1711 // unhelpful. Decompile the argument name instead.
1712 if (script->selfHosted()
1713#ifdef DEBUG1
1714 // For stack dump, argument name is not necessary.
1715 && !isStackDump
1716#endif /* DEBUG */
1717 ) {
1718 UniqueChars result;
1719 if (!DecompileArgumentFromStack(cx, slot, &result)) {
1720 return false;
1721 }
1722
1723 // Note that decompiling the argument in the parent frame might
1724 // not succeed.
1725 if (result) {
1726 return write(result.get());
1727 }
1728
1729 // If it fails, do not return parameter name and let the caller
1730 // fallback.
1731 return write("(intermediate value)");
1732 }
1733
1734 JSAtom* atom = getArg(slot);
1735 if (!atom) {
1736 return false;
1737 }
1738 return write(atom);
1739 }
1740 case JSOp::GetLocal: {
1741 JSAtom* atom = FrameSlotName(script, pc);
1742 MOZ_ASSERT(atom)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(atom)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(atom))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("atom", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 1742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "atom" ")");
do { MOZ_CrashSequence(__null, 1742); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1743 return write(atom);
1744 }
1745 case JSOp::GetAliasedVar: {
1746 JSAtom* atom = EnvironmentCoordinateNameSlow(script, pc);
1747 MOZ_ASSERT(atom)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(atom)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(atom))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("atom", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 1747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "atom" ")");
do { MOZ_CrashSequence(__null, 1747); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1748 return write(atom);
1749 }
1750
1751 case JSOp::DelProp:
1752 case JSOp::StrictDelProp:
1753 case JSOp::GetProp:
1754 case JSOp::GetBoundName: {
1755 bool hasDelete = op == JSOp::DelProp || op == JSOp::StrictDelProp;
1756 Rooted<JSAtom*> prop(cx, loadAtom(pc));
1757 MOZ_ASSERT(prop)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prop)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(prop))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("prop", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 1757); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prop" ")");
do { MOZ_CrashSequence(__null, 1757); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1758 return (hasDelete ? write("(delete ") : true) &&
1759 decompilePCForStackOperand(pc, -1) &&
1760 (IsIdentifier(prop)
1761 ? write(".") && quote(prop, '\0')
1762 : write("[") && quote(prop, '\'') && write("]")) &&
1763 (hasDelete ? write(")") : true);
1764 }
1765 case JSOp::GetPropSuper: {
1766 Rooted<JSAtom*> prop(cx, loadAtom(pc));
1767 return write("super.") && quote(prop, '\0');
1768 }
1769 case JSOp::SetElem:
1770 case JSOp::StrictSetElem:
1771 // NOTE: We don't show the right hand side of the operation because
1772 // it's used in error messages like: "a[0] is not readable".
1773 //
1774 // We could though.
1775 return decompilePCForStackOperand(pc, -3) && write("[") &&
1776 decompilePCForStackOperand(pc, -2) && write("]");
1777
1778 case JSOp::DelElem:
1779 case JSOp::StrictDelElem:
1780 case JSOp::GetElem: {
1781 bool hasDelete = (op == JSOp::DelElem || op == JSOp::StrictDelElem);
1782 return (hasDelete ? write("(delete ") : true) &&
1783 decompilePCForStackOperand(pc, -2) && write("[") &&
1784 decompilePCForStackOperand(pc, -1) && write("]") &&
1785 (hasDelete ? write(")") : true);
1786 }
1787
1788 case JSOp::GetElemSuper:
1789 return write("super[") && decompilePCForStackOperand(pc, -2) &&
1790 write("]");
1791 case JSOp::Null:
1792 return write("null");
1793 case JSOp::True:
1794 return write("true");
1795 case JSOp::False:
1796 return write("false");
1797 case JSOp::Zero:
1798 case JSOp::One:
1799 case JSOp::Int8:
1800 case JSOp::Uint16:
1801 case JSOp::Uint24:
1802 case JSOp::Int32:
1803 sprinter.printf("%d", GetBytecodeInteger(pc));
1804 return true;
1805 case JSOp::String:
1806 return quote(loadString(pc), '"');
1807 case JSOp::Symbol: {
1808 unsigned i = uint8_t(pc[1]);
1809 MOZ_ASSERT(i < JS::WellKnownSymbolLimit)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(i < JS::WellKnownSymbolLimit)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(i < JS::WellKnownSymbolLimit
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"i < JS::WellKnownSymbolLimit", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 1809); AnnotateMozCrashReason("MOZ_ASSERT" "(" "i < JS::WellKnownSymbolLimit"
")"); do { MOZ_CrashSequence(__null, 1809); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1810 if (i < JS::WellKnownSymbolLimit) {
1811 return write(cx->names().wellKnownSymbolDescriptions()[i]);
1812 }
1813 break;
1814 }
1815 case JSOp::Undefined:
1816 return write("undefined");
1817 case JSOp::GlobalThis:
1818 case JSOp::NonSyntacticGlobalThis:
1819 // |this| could convert to a very long object initialiser, so cite it by
1820 // its keyword name.
1821 return write("this");
1822 case JSOp::NewTarget:
1823 return write("new.target");
1824 case JSOp::ImportMeta:
1825 return write("import.meta");
1826 case JSOp::Call:
1827 case JSOp::CallContent:
1828 case JSOp::CallIgnoresRv:
1829 case JSOp::CallIter:
1830 case JSOp::CallContentIter: {
1831 uint16_t argc = GET_ARGC(pc);
1832 return decompilePCForStackOperand(pc, -int32_t(argc + 2)) &&
1833 write(argc ? "(...)" : "()");
1834 }
1835 case JSOp::SpreadCall:
1836 return decompilePCForStackOperand(pc, -3) && write("(...)");
1837 case JSOp::NewArray:
1838 return write("[]");
1839 case JSOp::RegExp: {
1840 Rooted<RegExpObject*> obj(cx, &script->getObject(pc)->as<RegExpObject>());
1841 JSString* str = RegExpObject::toString(cx, obj);
1842 if (!str) {
1843 return false;
1844 }
1845 return write(str);
1846 }
1847 case JSOp::Object: {
1848 JSObject* obj = script->getObject(pc);
1849 RootedValue objv(cx, ObjectValue(*obj));
1850 JSString* str = ValueToSource(cx, objv);
1851 if (!str) {
1852 return false;
1853 }
1854 return write(str);
1855 }
1856 case JSOp::Void:
1857 return write("(void ") && decompilePCForStackOperand(pc, -1) &&
1858 write(")");
1859
1860 case JSOp::SuperCall:
1861 if (GET_ARGC(pc) == 0) {
1862 return write("super()");
1863 }
1864 [[fallthrough]];
1865 case JSOp::SpreadSuperCall:
1866 return write("super(...)");
1867 case JSOp::SuperFun:
1868 return write("super");
1869
1870 case JSOp::Eval:
1871 case JSOp::SpreadEval:
1872 case JSOp::StrictEval:
1873 case JSOp::StrictSpreadEval:
1874 return write("eval(...)");
1875
1876 case JSOp::New:
1877 case JSOp::NewContent: {
1878 uint16_t argc = GET_ARGC(pc);
1879 return write("(new ") &&
1880 decompilePCForStackOperand(pc, -int32_t(argc + 3)) &&
1881 write(argc ? "(...))" : "())");
1882 }
1883
1884 case JSOp::SpreadNew:
1885 return write("(new ") && decompilePCForStackOperand(pc, -4) &&
1886 write("(...))");
1887
1888 case JSOp::DynamicImport:
1889 return write(GET_UINT8(pc) == uint8_t(ImportPhase::Source)
1890 ? "import.source(...)"
1891 : "import(...)");
1892
1893 case JSOp::Typeof:
1894 case JSOp::TypeofExpr:
1895 return write("(typeof ") && decompilePCForStackOperand(pc, -1) &&
1896 write(")");
1897
1898 case JSOp::TypeofEq: {
1899 auto operand = TypeofEqOperand::fromRawValue(GET_UINT8(pc));
1900 JSType type = operand.type();
1901 JSOp compareOp = operand.compareOp();
1902
1903 return write("(typeof ") && decompilePCForStackOperand(pc, -1) &&
1904 write(compareOp == JSOp::Ne ? " != \"" : " == \"") &&
1905 write(JSTypeToString(type)) && write("\")");
1906 }
1907
1908 case JSOp::StrictConstantEq:
1909 case JSOp::StrictConstantNe: {
1910 auto operand = ConstantCompareOperand::fromRawValue(GET_UINT16(pc));
1911 return write("(") && decompilePCForStackOperand(pc, -1) && write(" ") &&
1912 write(op == JSOp::StrictConstantEq ? "===" : "!==") &&
1913 write(" ") && write(&operand) && write(")");
1914 }
1915
1916 case JSOp::InitElemArray:
1917 return write("[...]");
1918
1919 case JSOp::InitElemInc:
1920 if (defIndex == 0) {
1921 return write("[...]");
1922 }
1923 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 1923); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 1923); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1924#ifdef DEBUG1
1925 // INDEX won't be be exposed to error message.
1926 if (isStackDump) {
1927 return write("INDEX");
1928 }
1929#endif
1930 break;
1931
1932 case JSOp::ToNumeric:
1933 return write("(tonumeric ") && decompilePCForStackOperand(pc, -1) &&
1934 write(")");
1935
1936 case JSOp::Inc:
1937 return write("(inc ") && decompilePCForStackOperand(pc, -1) && write(")");
1938
1939 case JSOp::Dec:
1940 return write("(dec ") && decompilePCForStackOperand(pc, -1) && write(")");
1941
1942 case JSOp::BigInt:
1943#if defined(DEBUG1) || defined(JS_JITSPEW1)
1944 // BigInt::dumpLiteral() only available in this configuration.
1945 script->getBigInt(pc)->dumpLiteral(sprinter);
1946 return true;
1947#else
1948 return write("[bigint]");
1949#endif
1950
1951 case JSOp::BuiltinObject: {
1952 auto kind = BuiltinObjectKind(GET_UINT8(pc));
1953 return write(BuiltinObjectName(kind));
1954 }
1955
1956 default:
1957 break;
1958 }
1959
1960#ifdef DEBUG1
1961 if (isStackDump) {
1962 // Special decompilation for stack dump.
1963 switch (op) {
1964 case JSOp::Arguments:
1965 return write("arguments");
1966
1967 case JSOp::ArgumentsLength:
1968 return write("arguments.length");
1969
1970 case JSOp::GetFrameArg:
1971 sprinter.printf("arguments[%u]", GET_ARGNO(pc));
1972 return true;
1973
1974 case JSOp::GetActualArg:
1975 return write("arguments[") && decompilePCForStackOperand(pc, -1) &&
1976 write("]");
1977
1978 case JSOp::BindUnqualifiedGName:
1979 return write("GLOBAL");
1980
1981 case JSOp::BindName:
1982 case JSOp::BindUnqualifiedName:
1983 case JSOp::BindVar:
1984 return write("ENV");
1985
1986 case JSOp::Callee:
1987 return write("CALLEE");
1988
1989 case JSOp::EnvCallee:
1990 return write("ENVCALLEE");
1991
1992 case JSOp::CallSiteObj:
1993 return write("OBJ");
1994
1995 case JSOp::Double:
1996 sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
1997 return true;
1998
1999 case JSOp::Exception:
2000 return write("EXCEPTION");
2001
2002 case JSOp::ExceptionAndStack:
2003 if (defIndex == 0) {
2004 return write("EXCEPTION");
2005 }
2006 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2006); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2006); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2007 return write("STACK");
2008
2009 case JSOp::Try:
2010 // Used for the values live on entry to the finally block.
2011 // See TryNoteKind::Finally above.
2012 if (defIndex == 0) {
2013 return write("PC");
2014 }
2015 if (defIndex == 1) {
2016 return write("STACK");
2017 }
2018 MOZ_ASSERT(defIndex == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 2))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 2",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2018); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 2" ")"); do { MOZ_CrashSequence
(__null, 2018); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2019 return write("THROWING");
2020
2021 case JSOp::FunctionThis:
2022 case JSOp::ImplicitThis:
2023 return write("THIS");
2024
2025 case JSOp::FunWithProto:
2026 return write("FUN");
2027
2028 case JSOp::Generator:
2029 return write("GENERATOR");
2030
2031 case JSOp::GetImport:
2032 return write("VAL");
2033
2034 case JSOp::GetRval:
2035 return write("RVAL");
2036
2037 case JSOp::Hole:
2038 return write("HOLE");
2039
2040 case JSOp::IsNoIter:
2041 // For stack dump, defIndex == 0 is not used.
2042 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2042); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2042); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2043 return write("ISNOITER");
2044
2045 case JSOp::IsConstructing:
2046 return write("JS_IS_CONSTRUCTING");
2047
2048 case JSOp::IsNullOrUndefined:
2049 return write("IS_NULL_OR_UNDEF");
2050
2051 case JSOp::Iter:
2052 return write("ITER");
2053
2054 case JSOp::Lambda:
2055 return write("FUN");
2056
2057 case JSOp::ToAsyncIter:
2058 return write("ASYNCITER");
2059
2060 case JSOp::MoreIter:
2061 // For stack dump, defIndex == 0 is not used.
2062 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2062); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2062); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2063 return write("MOREITER");
2064
2065 case JSOp::NewInit:
2066 case JSOp::NewObject:
2067 case JSOp::ObjWithProto:
2068 return write("OBJ");
2069
2070 case JSOp::OptimizeGetIterator:
2071 case JSOp::OptimizeSpreadCall:
2072 return write("OPTIMIZED");
2073
2074 case JSOp::Rest:
2075 return write("REST");
2076
2077 case JSOp::Resume:
2078 return write("RVAL");
2079
2080 case JSOp::SuperBase:
2081 return write("HOMEOBJECTPROTO");
2082
2083 case JSOp::ToPropertyKey:
2084 return write("TOPROPERTYKEY(") && decompilePCForStackOperand(pc, -1) &&
2085 write(")");
2086 case JSOp::ToString:
2087 return write("TOSTRING(") && decompilePCForStackOperand(pc, -1) &&
2088 write(")");
2089
2090 case JSOp::Uninitialized:
2091 return write("UNINITIALIZED");
2092
2093 case JSOp::InitialYield:
2094 case JSOp::Await:
2095 case JSOp::Yield:
2096 // Printing "yield SOMETHING" is confusing since the operand doesn't
2097 // match to the syntax, since the stack operand for "yield 10" is
2098 // the result object, not 10.
2099 if (defIndex == 0) {
2100 return write("RVAL");
2101 }
2102 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2102); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2102); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2103 return write("RESUMEKIND");
2104
2105 case JSOp::ResumeKind:
2106 return write("RESUMEKIND");
2107
2108 case JSOp::AsyncAwait:
2109 case JSOp::AsyncResolve:
2110 case JSOp::AsyncReject:
2111 return write("PROMISE");
2112
2113 case JSOp::CanSkipAwait:
2114 // For stack dump, defIndex == 0 is not used.
2115 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2115); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2115); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2116 return write("CAN_SKIP_AWAIT");
2117
2118 case JSOp::MaybeExtractAwaitValue:
2119 // For stack dump, defIndex == 1 is not used.
2120 MOZ_ASSERT(defIndex == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 0",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2120); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 0" ")"); do { MOZ_CrashSequence
(__null, 2120); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2121 return write("MAYBE_RESOLVED(") && decompilePCForStackOperand(pc, -2) &&
2122 write(")");
2123
2124 case JSOp::CheckPrivateField:
2125 return write("HasPrivateField");
2126
2127 case JSOp::NewPrivateName:
2128 return write("PRIVATENAME");
2129
2130 case JSOp::CheckReturn:
2131 return write("RVAL");
2132
2133 case JSOp::HasOwn:
2134 return write("HasOwn(") && decompilePCForStackOperand(pc, -2) &&
2135 write(", ") && decompilePCForStackOperand(pc, -1) && write(")");
2136
2137 case JSOp::AddDisposable:
2138 return decompilePCForStackOperand(pc, -1);
2139
2140 case JSOp::TakeDisposeCapability:
2141 if (defIndex == 0) {
2142 return write("DISPOSECAPABILITY");
2143 }
2144 MOZ_ASSERT(defIndex == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(defIndex == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defIndex == 1))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("defIndex == 1",
"./../../../../js/src/vm/BytecodeUtil.cpp", 2144); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "defIndex == 1" ")"); do { MOZ_CrashSequence
(__null, 2144); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2145 return write("COUNT");
2146
2147 default:
2148 break;
2149 }
2150 return write("<unknown>");
2151 }
2152#endif /* DEBUG */
2153
2154 return write("(intermediate value)");
2155}
2156
2157bool ExpressionDecompiler::decompilePC(
2158 const OffsetAndDefIndex& offsetAndDefIndex) {
2159 if (offsetAndDefIndex.isSpecial()) {
2160#ifdef DEBUG1
2161 if (isStackDump) {
2162 if (offsetAndDefIndex.isMerged()) {
2163 if (!write("merged<")) {
2164 return false;
2165 }
2166 } else if (offsetAndDefIndex.isIgnored()) {
2167 if (!write("ignored<")) {
2168 return false;
2169 }
2170 }
2171
2172 if (!decompilePC(script->offsetToPC(offsetAndDefIndex.specialOffset()),
2173 offsetAndDefIndex.specialDefIndex())) {
2174 return false;
2175 }
2176
2177 if (!write(">")) {
2178 return false;
2179 }
2180
2181 return true;
2182 }
2183#endif /* DEBUG */
2184 return write("(intermediate value)");
2185 }
2186
2187 return decompilePC(script->offsetToPC(offsetAndDefIndex.offset()),
2188 offsetAndDefIndex.defIndex());
2189}
2190
2191bool ExpressionDecompiler::init() {
2192 cx->check(script);
2193 return sprinter.init();
2194}
2195
2196bool ExpressionDecompiler::write(const char* s) {
2197 sprinter.put(s);
2198 return true;
2199}
2200
2201bool ExpressionDecompiler::write(JSString* str) {
2202 if (str == cx->names().dot_this_) {
2203 return write("this");
2204 }
2205 if (str == cx->names().dot_newTarget_) {
2206 return write("new.target");
2207 }
2208 sprinter.putString(cx, str);
2209 return true;
2210}
2211
2212bool ExpressionDecompiler::quote(JSString* s, char quote) {
2213 QuoteString(&sprinter, s, quote);
2214 return true;
2215}
2216
2217JSAtom* ExpressionDecompiler::loadAtom(jsbytecode* pc) {
2218 return script->getAtom(pc);
2219}
2220
2221bool ExpressionDecompiler::write(ConstantCompareOperand* operand) {
2222 switch (operand->type()) {
2223 case ConstantCompareOperand::EncodedType::Int32: {
2224 sprinter.printf("%d", operand->toInt32());
2225 return true;
2226 }
2227 case ConstantCompareOperand::EncodedType::Boolean: {
2228 return write(operand->toBoolean() ? "true" : "false");
2229 }
2230 case ConstantCompareOperand::EncodedType::Null: {
2231 return write("null");
2232 }
2233 case ConstantCompareOperand::EncodedType::Undefined: {
2234 return write("undefined");
2235 }
2236 }
2237 MOZ_CRASH("Unknown constant compare operand type")do { do { } while (false); MOZ_ReportCrash("" "Unknown constant compare operand type"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2237); AnnotateMozCrashReason
("MOZ_CRASH(" "Unknown constant compare operand type" ")"); do
{ MOZ_CrashSequence(__null, 2237); __attribute__((nomerge)) ::
abort(); } while (false); } while (false)
;
2238}
2239
2240JSString* ExpressionDecompiler::loadString(jsbytecode* pc) {
2241 return script->getString(pc);
2242}
2243
2244JSAtom* ExpressionDecompiler::getArg(unsigned slot) {
2245 MOZ_ASSERT(script->isFunction())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(script->isFunction())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(script->isFunction()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("script->isFunction()"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2245); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "script->isFunction()" ")"); do { MOZ_CrashSequence
(__null, 2245); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2246 MOZ_ASSERT(slot < script->numArgs())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(slot < script->numArgs())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(slot < script->numArgs
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("slot < script->numArgs()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slot < script->numArgs()"
")"); do { MOZ_CrashSequence(__null, 2246); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2247
2248 for (PositionalFormalParameterIter fi(script); fi; fi++) {
2249 if (fi.argumentSlot() == slot) {
2250 if (!fi.isDestructured()) {
2251 return fi.name();
2252 }
2253
2254 // Destructured arguments have no single binding name.
2255 static const char destructuredParam[] = "(destructured parameter)";
2256 return Atomize(cx, destructuredParam, strlen(destructuredParam));
2257 }
2258 }
2259
2260 MOZ_CRASH("No binding")do { do { } while (false); MOZ_ReportCrash("" "No binding", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2260); AnnotateMozCrashReason("MOZ_CRASH(" "No binding" ")"
); do { MOZ_CrashSequence(__null, 2260); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2261}
2262
2263UniqueChars ExpressionDecompiler::getOutput() { return sprinter.release(); }
2264
2265} // anonymous namespace
2266
2267#if defined(DEBUG1) || defined(JS_JITSPEW1)
2268static bool DecompileAtPCForStackDump(
2269 JSContext* cx, HandleScript script,
2270 const OffsetAndDefIndex& offsetAndDefIndex, StringPrinter* sp) {
2271 // The expression decompiler asserts the script is in the current realm.
2272 AutoRealm ar(cx, script);
2273
2274 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2275 BytecodeParser parser(cx, allocScope.alloc(), script);
2276 parser.setStackDump();
2277 if (!parser.parse()) {
2278 return false;
2279 }
2280
2281 ExpressionDecompiler ed(cx, script, parser);
2282 ed.setStackDump();
2283 if (!ed.init()) {
2284 return false;
2285 }
2286
2287 if (!ed.decompilePC(offsetAndDefIndex)) {
2288 return false;
2289 }
2290
2291 UniqueChars result = ed.getOutput();
2292 if (!result) {
2293 return false;
2294 }
2295
2296 sp->put(result.get());
2297 return true;
2298}
2299#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
2300
2301static bool FindStartPC(JSContext* cx, const FrameIter& iter,
2302 const BytecodeParser& parser, int spindex,
2303 int skipStackHits, const Value& v, jsbytecode** valuepc,
2304 uint8_t* defIndex) {
2305 jsbytecode* current = *valuepc;
2306 *valuepc = nullptr;
2307 *defIndex = 0;
2308
2309 if (spindex < 0 && spindex + int(parser.stackDepthAtPC(current)) < 0) {
2310 spindex = JSDVG_SEARCH_STACK1;
2311 }
2312
2313 if (spindex == JSDVG_SEARCH_STACK1) {
2314 size_t index = iter.numFrameSlots();
2315
2316 // The decompiler may be called from inside functions that are not
2317 // called from script, but via the C++ API directly, such as
2318 // Invoke. In that case, the youngest script frame may have a
2319 // completely unrelated pc and stack depth, so we give up.
2320 if (index < size_t(parser.stackDepthAtPC(current))) {
2321 return true;
2322 }
2323
2324 // We search from fp->sp to base to find the most recently calculated
2325 // value matching v under assumption that it is the value that caused
2326 // the exception.
2327 int stackHits = 0;
2328 Value s;
2329 do {
2330 if (!index) {
2331 return true;
2332 }
2333 s = iter.frameSlotValue(--index);
2334 } while (s != v || stackHits++ != skipStackHits);
2335
2336 // If the current PC has fewer values on the stack than the index we are
2337 // looking for, the blamed value must be one pushed by the current
2338 // bytecode (e.g. JSOp::MoreIter), so restore *valuepc.
2339 if (index < size_t(parser.stackDepthAtPC(current))) {
2340 *valuepc = parser.pcForStackOperand(current, index, defIndex);
2341 } else {
2342 *valuepc = current;
2343 *defIndex = index - size_t(parser.stackDepthAtPC(current));
2344 }
2345 } else {
2346 *valuepc = parser.pcForStackOperand(current, spindex, defIndex);
2347 }
2348 return true;
2349}
2350
2351static bool DecompileExpressionFromStack(JSContext* cx, int spindex,
2352 int skipStackHits, HandleValue v,
2353 UniqueChars* res) {
2354 MOZ_ASSERT(spindex < 0 || spindex == JSDVG_IGNORE_STACK ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(spindex < 0 || spindex == 0 || spindex == 1)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(spindex < 0 || spindex == 0 || spindex == 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("spindex < 0 || spindex == 0 || spindex == 1"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2355); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "spindex < 0 || spindex == 0 || spindex == 1"
")"); do { MOZ_CrashSequence(__null, 2355); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2355 spindex == JSDVG_SEARCH_STACK)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(spindex < 0 || spindex == 0 || spindex == 1)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(spindex < 0 || spindex == 0 || spindex == 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("spindex < 0 || spindex == 0 || spindex == 1"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2355); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "spindex < 0 || spindex == 0 || spindex == 1"
")"); do { MOZ_CrashSequence(__null, 2355); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2356
2357 *res = nullptr;
2358
2359 /*
2360 * Give up if we need deterministic behavior for differential testing.
2361 * IonMonkey doesn't use InterpreterFrames and this ensures we get the same
2362 * error messages.
2363 */
2364 if (js::SupportDifferentialTesting()) {
2365 return true;
2366 }
2367
2368 if (spindex == JSDVG_IGNORE_STACK0) {
2369 return true;
2370 }
2371
2372 FrameIter frameIter(cx);
2373
2374 if (frameIter.done() || !frameIter.hasScript() ||
2375 frameIter.realm() != cx->realm() || frameIter.inPrologue()) {
2376 return true;
2377 }
2378
2379 /*
2380 * FIXME: Fall back if iter.isIon(), since the stack snapshot may be for the
2381 * previous pc (see bug 831120).
2382 */
2383 if (frameIter.isIon()) {
2384 return true;
2385 }
2386
2387 RootedScript script(cx, frameIter.script());
2388 jsbytecode* valuepc = frameIter.pc();
2389
2390 MOZ_ASSERT(script->containsPC(valuepc))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(script->containsPC(valuepc))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(script->containsPC(valuepc
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("script->containsPC(valuepc)", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "script->containsPC(valuepc)"
")"); do { MOZ_CrashSequence(__null, 2390); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2391
2392 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2393 BytecodeParser parser(cx, allocScope.alloc(), frameIter.script());
2394 if (!parser.parse()) {
2395 return false;
2396 }
2397
2398 uint8_t defIndex;
2399 if (!FindStartPC(cx, frameIter, parser, spindex, skipStackHits, v, &valuepc,
2400 &defIndex)) {
2401 return false;
2402 }
2403 if (!valuepc) {
2404 return true;
2405 }
2406
2407 ExpressionDecompiler ed(cx, script, parser);
2408 if (!ed.init()) {
2409 return false;
2410 }
2411 if (!ed.decompilePC(valuepc, defIndex)) {
2412 return false;
2413 }
2414
2415 *res = ed.getOutput();
2416 return *res != nullptr;
2417}
2418
2419UniqueChars js::DecompileValueGenerator(JSContext* cx, int spindex,
2420 HandleValue v, HandleString fallbackArg,
2421 int skipStackHits) {
2422 RootedString fallback(cx, fallbackArg);
2423 {
2424 UniqueChars result;
2425 if (!DecompileExpressionFromStack(cx, spindex, skipStackHits, v, &result)) {
2426 return nullptr;
2427 }
2428 if (result && strcmp(result.get(), "(intermediate value)")) {
2429 return result;
2430 }
2431 }
2432 if (!fallback) {
2433 if (v.isUndefined()) {
2434 return DuplicateString(cx, "undefined"); // Prevent users from seeing
2435 // "(void 0)"
2436 }
2437 fallback = ValueToSource(cx, v);
2438 if (!fallback) {
2439 return nullptr;
2440 }
2441 }
2442
2443 return StringToNewUTF8CharsZ(cx, *fallback);
2444}
2445
2446static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
2447 UniqueChars* res) {
2448 MOZ_ASSERT(formalIndex >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(formalIndex >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(formalIndex >= 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("formalIndex >= 0"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2448); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "formalIndex >= 0" ")"); do { MOZ_CrashSequence
(__null, 2448); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2449
2450 *res = nullptr;
2451
2452 /* See note in DecompileExpressionFromStack. */
2453 if (js::SupportDifferentialTesting()) {
2454 return true;
2455 }
2456
2457 /*
2458 * Settle on the nearest script frame, which should be the builtin that
2459 * called the intrinsic.
2460 */
2461 FrameIter frameIter(cx);
2462 MOZ_ASSERT(!frameIter.done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!frameIter.done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!frameIter.done()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!frameIter.done()"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2462); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!frameIter.done()" ")"); do { MOZ_CrashSequence
(__null, 2462); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2463 MOZ_ASSERT(frameIter.script()->selfHosted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(frameIter.script()->selfHosted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(frameIter.script()->selfHosted
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("frameIter.script()->selfHosted()", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2463); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameIter.script()->selfHosted()"
")"); do { MOZ_CrashSequence(__null, 2463); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2464
2465 /*
2466 * Get the second-to-top frame, the non-self-hosted caller of the builtin
2467 * that called the intrinsic.
2468 */
2469 ++frameIter;
2470 if (frameIter.done() || !frameIter.hasScript() ||
2471 frameIter.script()->selfHosted() || frameIter.realm() != cx->realm()) {
2472 return true;
2473 }
2474
2475 RootedScript script(cx, frameIter.script());
2476 jsbytecode* current = frameIter.pc();
2477
2478 MOZ_ASSERT(script->containsPC(current))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(script->containsPC(current))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(script->containsPC(current
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("script->containsPC(current)", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2478); AnnotateMozCrashReason("MOZ_ASSERT" "(" "script->containsPC(current)"
")"); do { MOZ_CrashSequence(__null, 2478); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2479
2480 if (current < script->main()) {
2481 return true;
2482 }
2483
2484 /* Don't handle getters, setters or calls from fun.call/fun.apply. */
2485 JSOp op = JSOp(*current);
2486 if (op != JSOp::Call && op != JSOp::CallContent &&
2487 op != JSOp::CallIgnoresRv && op != JSOp::New && op != JSOp::NewContent) {
2488 return true;
2489 }
2490
2491 if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current)) {
2492 return true;
2493 }
2494
2495 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2496 BytecodeParser parser(cx, allocScope.alloc(), script);
2497 if (!parser.parse()) {
2498 return false;
2499 }
2500
2501 bool pushedNewTarget = op == JSOp::New || op == JSOp::NewContent;
2502 int formalStackIndex = parser.stackDepthAtPC(current) - GET_ARGC(current) -
2503 pushedNewTarget + formalIndex;
2504 MOZ_ASSERT(formalStackIndex >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(formalStackIndex >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(formalStackIndex >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("formalStackIndex >= 0"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2504); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "formalStackIndex >= 0" ")"); do { MOZ_CrashSequence
(__null, 2504); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2505 if (uint32_t(formalStackIndex) >= parser.stackDepthAtPC(current)) {
2506 return true;
2507 }
2508
2509 ExpressionDecompiler ed(cx, script, parser);
2510 if (!ed.init()) {
2511 return false;
2512 }
2513 if (!ed.decompilePCForStackOperand(current, formalStackIndex)) {
2514 return false;
2515 }
2516
2517 *res = ed.getOutput();
2518 return *res != nullptr;
2519}
2520
2521JSString* js::DecompileArgument(JSContext* cx, int formalIndex, HandleValue v) {
2522 {
2523 UniqueChars result;
2524 if (!DecompileArgumentFromStack(cx, formalIndex, &result)) {
2525 return nullptr;
2526 }
2527 if (result && strcmp(result.get(), "(intermediate value)")) {
2528 JS::ConstUTF8CharsZ utf8chars(result.get(), strlen(result.get()));
2529 return NewStringCopyUTF8Z(cx, utf8chars);
2530 }
2531 }
2532 if (v.isUndefined()) {
2533 return cx->names().undefined; // Prevent users from seeing "(void 0)"
2534 }
2535
2536 return ValueToSource(cx, v);
2537}
2538
2539extern bool js::IsValidBytecodeOffset(JSContext* cx, JSScript* script,
2540 size_t offset) {
2541 // This could be faster (by following jump instructions if the target
2542 // is <= offset).
2543 for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
2544 size_t here = r.frontOffset();
2545 if (here >= offset) {
2546 return here == offset;
2547 }
2548 }
2549 return false;
2550}
2551
2552/*
2553 * There are three possible PCCount profiling states:
2554 *
2555 * 1. None: Neither scripts nor the runtime have count information.
2556 * 2. Profile: Active scripts have count information, the runtime does not.
2557 * 3. Query: Scripts do not have count information, the runtime does.
2558 *
2559 * When starting to profile scripts, counting begins immediately, with all JIT
2560 * code discarded and recompiled with counts as necessary. Active interpreter
2561 * frames will not begin profiling until they begin executing another script
2562 * (via a call or return).
2563 *
2564 * The below API functions manage transitions to new states, according
2565 * to the table below.
2566 *
2567 * Old State
2568 * -------------------------
2569 * Function None Profile Query
2570 * --------
2571 * StartPCCountProfiling Profile Profile Profile
2572 * StopPCCountProfiling None Query Query
2573 * PurgePCCounts None None None
2574 */
2575
2576static void ReleaseScriptCounts(JSRuntime* rt) {
2577 MOZ_ASSERT(rt->scriptAndCountsVector)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rt->scriptAndCountsVector)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rt->scriptAndCountsVector
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rt->scriptAndCountsVector", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2577); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rt->scriptAndCountsVector"
")"); do { MOZ_CrashSequence(__null, 2577); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2578
2579 js_delete(rt->scriptAndCountsVector.ref());
2580 rt->scriptAndCountsVector = nullptr;
2581}
2582
2583void JS::StartPCCountProfiling(JSContext* cx) {
2584 JSRuntime* rt = cx->runtime();
2585
2586 if (rt->profilingScripts) {
2587 return;
2588 }
2589
2590 if (rt->scriptAndCountsVector) {
2591 ReleaseScriptCounts(rt);
2592 }
2593
2594 ReleaseAllJITCode(rt->gcContext());
2595
2596 rt->profilingScripts = true;
2597}
2598
2599void JS::StopPCCountProfiling(JSContext* cx) {
2600 JSRuntime* rt = cx->runtime();
2601
2602 if (!rt->profilingScripts) {
2603 return;
2604 }
2605 MOZ_ASSERT(!rt->scriptAndCountsVector)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!rt->scriptAndCountsVector)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!rt->scriptAndCountsVector
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!rt->scriptAndCountsVector", "./../../../../js/src/vm/BytecodeUtil.cpp"
, 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rt->scriptAndCountsVector"
")"); do { MOZ_CrashSequence(__null, 2605); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2606
2607 ReleaseAllJITCode(rt->gcContext());
2608
2609 auto* vec = cx->new_<PersistentRooted<ScriptAndCountsVector>>(
2610 cx, ScriptAndCountsVector());
2611 if (!vec) {
2612 return;
2613 }
2614
2615 for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
2616 for (auto base = zone->cellIter<BaseScript>(); !base.done(); base.next()) {
2617 if (base->hasScriptCounts() && base->hasJitScript()) {
2618 if (!vec->append(base->asJSScript())) {
2619 return;
2620 }
2621 }
2622 }
2623 }
2624
2625 rt->profilingScripts = false;
2626 rt->scriptAndCountsVector = vec;
2627}
2628
2629void JS::PurgePCCounts(JSContext* cx) {
2630 JSRuntime* rt = cx->runtime();
2631
2632 if (!rt->scriptAndCountsVector) {
2633 return;
2634 }
2635 MOZ_ASSERT(!rt->profilingScripts)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!rt->profilingScripts)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!rt->profilingScripts))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!rt->profilingScripts"
, "./../../../../js/src/vm/BytecodeUtil.cpp", 2635); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!rt->profilingScripts" ")"); do { MOZ_CrashSequence
(__null, 2635); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2636
2637 ReleaseScriptCounts(rt);
2638}
2639
2640size_t JS::GetPCCountScriptCount(JSContext* cx) {
2641 JSRuntime* rt = cx->runtime();
2642
2643 if (!rt->scriptAndCountsVector) {
2644 return 0;
2645 }
2646
2647 return rt->scriptAndCountsVector->length();
2648}
2649
2650[[nodiscard]] static bool JSONStringProperty(StringPrinter& sp,
2651 JSONPrinter& json,
2652 const char* name, JSString* str) {
2653 json.beginStringProperty(name);
2654 JSONQuoteString(&sp, str);
2655 json.endStringProperty();
2656 return true;
2657}
2658
2659JSString* JS::GetPCCountScriptSummary(JSContext* cx, size_t index) {
2660 JSRuntime* rt = cx->runtime();
2661
2662 if (!rt->scriptAndCountsVector ||
2663 index >= rt->scriptAndCountsVector->length()) {
2664 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2665 JSMSG_BUFFER_TOO_SMALL);
2666 return nullptr;
2667 }
2668
2669 const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
2670 RootedScript script(cx, sac.script);
2671
2672 JSSprinter sp(cx);
2673 if (!sp.init()) {
2674 return nullptr;
2675 }
2676
2677 JSONPrinter json(sp, false);
2678
2679 json.beginObject();
2680
2681 Rooted<JSString*> filenameStr(cx);
2682 if (const char* filename = script->filename()) {
2683 filenameStr =
2684 JS_NewStringCopyUTF8N(cx, JS::UTF8Chars(filename, strlen(filename)));
2685 } else {
2686 filenameStr = JS_GetEmptyString(cx);
2687 }
2688 if (!filenameStr) {
2689 return nullptr;
2690 }
2691 if (!JSONStringProperty(sp, json, "file", filenameStr)) {
2692 return nullptr;
2693 }
2694 json.property("line", script->lineno());
2695
2696 if (JSFunction* fun = script->function()) {
2697 if (JSAtom* atom = fun->fullDisplayAtom()) {
2698 if (!JSONStringProperty(sp, json, "name", atom)) {
2699 return nullptr;
2700 }
2701 }
2702 }
2703
2704 uint64_t total = 0;
2705
2706 AllBytecodesIterable iter(script);
2707 for (BytecodeLocation loc : iter) {
2708 if (const PCCounts* counts = sac.maybeGetPCCounts(loc.toRawBytecode())) {
2709 total += counts->numExec();
2710 }
2711 }
2712
2713 json.beginObjectProperty("totals");
2714
2715 json.property(PCCounts::numExecName, total);
2716
2717 uint64_t ionActivity = 0;
2718 jit::IonScriptCounts* ionCounts = sac.getIonCounts();
2719 while (ionCounts) {
2720 for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
2721 ionActivity += ionCounts->block(i).hitCount();
2722 }
2723 ionCounts = ionCounts->previous();
2724 }
2725 if (ionActivity) {
2726 json.property("ion", ionActivity);
2727 }
2728
2729 json.endObject();
2730
2731 json.endObject();
2732
2733 return sp.release(cx);
2734}
2735
2736static bool GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac,
2737 StringPrinter& sp) {
2738 JSONPrinter json(sp, false);
2739
2740 RootedScript script(cx, sac.script);
2741
2742 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2743 BytecodeParser parser(cx, allocScope.alloc(), script);
2744 if (!parser.parse()) {
2745 return false;
2746 }
2747
2748 json.beginObject();
2749
2750 JSString* str = JS_DecompileScript(cx, script);
2751 if (!str) {
2752 return false;
2753 }
2754
2755 if (!JSONStringProperty(sp, json, "text", str)) {
2756 return false;
2757 }
2758
2759 json.property("line", script->lineno());
2760
2761 json.beginListProperty("opcodes");
2762
2763 uint64_t hits = 0;
2764 for (BytecodeRangeWithPosition range(cx, script, SkipPrologueOps::Yes);
2765 !range.empty(); range.popFront()) {
2766 jsbytecode* pc = range.frontPC();
2767 size_t offset = script->pcToOffset(pc);
2768 JSOp op = JSOp(*pc);
2769
2770 // If the current instruction is a jump target,
2771 // then update the number of hits.
2772 if (const PCCounts* counts = sac.maybeGetPCCounts(pc)) {
2773 hits = counts->numExec();
2774 }
2775
2776 json.beginObject();
2777
2778 json.property("id", offset);
2779 json.property("line", range.frontLineNumber());
2780 json.property("name", CodeName(op));
2781
2782 {
2783 ExpressionDecompiler ed(cx, script, parser);
2784 if (!ed.init()) {
2785 return false;
2786 }
2787 // defIndex passed here is not used.
2788 if (!ed.decompilePC(pc, /* defIndex = */ 0)) {
2789 return false;
2790 }
2791 UniqueChars text = ed.getOutput();
2792 if (!text) {
2793 return false;
2794 }
2795
2796 JS::ConstUTF8CharsZ utf8chars(text.get(), strlen(text.get()));
2797 JSString* str = NewStringCopyUTF8Z(cx, utf8chars);
2798 if (!str) {
2799 return false;
2800 }
2801
2802 if (!JSONStringProperty(sp, json, "text", str)) {
2803 return false;
2804 }
2805 }
2806
2807 json.beginObjectProperty("counts");
2808 if (hits > 0) {
2809 json.property(PCCounts::numExecName, hits);
2810 }
2811 json.endObject();
2812
2813 json.endObject();
2814
2815 // If the current instruction has thrown,
2816 // then decrement the hit counts with the number of throws.
2817 if (const PCCounts* counts = sac.maybeGetThrowCounts(pc)) {
2818 hits -= counts->numExec();
2819 }
2820 }
2821
2822 json.endList();
2823
2824 if (jit::IonScriptCounts* ionCounts = sac.getIonCounts()) {
2825 json.beginListProperty("ion");
2826
2827 while (ionCounts) {
2828 json.beginList();
2829 for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
2830 const jit::IonBlockCounts& block = ionCounts->block(i);
2831
2832 json.beginObject();
2833 json.property("id", block.id());
2834 json.property("offset", block.offset());
2835
2836 json.beginListProperty("successors");
2837 for (size_t j = 0; j < block.numSuccessors(); j++) {
2838 json.value(block.successor(j));
2839 }
2840 json.endList();
2841
2842 json.property("hits", block.hitCount());
2843
2844 JSString* str = NewStringCopyZ<CanGC>(cx, block.code());
2845 if (!str) {
2846 return false;
2847 }
2848
2849 if (!JSONStringProperty(sp, json, "code", str)) {
2850 return false;
2851 }
2852
2853 json.endObject();
2854 }
2855 json.endList();
2856
2857 ionCounts = ionCounts->previous();
2858 }
2859
2860 json.endList();
2861 }
2862
2863 json.endObject();
2864
2865 return true;
2866}
2867
2868JSString* JS::GetPCCountScriptContents(JSContext* cx, size_t index) {
2869 JSRuntime* rt = cx->runtime();
2870
2871 if (!rt->scriptAndCountsVector ||
2872 index >= rt->scriptAndCountsVector->length()) {
2873 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2874 JSMSG_BUFFER_TOO_SMALL);
2875 return nullptr;
2876 }
2877
2878 const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
2879 JSScript* script = sac.script;
2880
2881 JSSprinter sp(cx);
2882 if (!sp.init()) {
2883 return nullptr;
2884 }
2885
2886 {
2887 AutoRealm ar(cx, &script->global());
2888 if (!GetPCCountJSON(cx, sac, sp)) {
2889 return nullptr;
2890 }
2891 }
2892
2893 return sp.release(cx);
2894}
2895
2896struct CollectedScripts {
2897 MutableHandle<ScriptVector> scripts;
2898 bool ok = true;
2899
2900 explicit CollectedScripts(MutableHandle<ScriptVector> scripts)
2901 : scripts(scripts) {}
2902
2903 static void consider(JSRuntime* rt, void* data, BaseScript* script,
2904 const JS::AutoRequireNoGC& nogc) {
2905 auto self = static_cast<CollectedScripts*>(data);
2906 if (!script->filename()) {
2907 return;
2908 }
2909 if (!self->scripts.append(script->asJSScript())) {
2910 self->ok = false;
2911 }
2912 }
2913};
2914
2915static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm,
2916 GenericPrinter& out) {
2917 AutoRealmUnchecked ar(cx, realm);
2918
2919 // Collect the list of scripts which are part of the current realm.
2920
2921 MOZ_RELEASE_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(coverage::IsLCovEnabled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(coverage::IsLCovEnabled())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("coverage::IsLCovEnabled()"
" (" "Coverage must be enabled for process before generating LCov info"
")", "./../../../../js/src/vm/BytecodeUtil.cpp", 2923); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()" ") (" "Coverage must be enabled for process before generating LCov info"
")"); do { MOZ_CrashSequence(__null, 2923); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2922 coverage::IsLCovEnabled(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(coverage::IsLCovEnabled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(coverage::IsLCovEnabled())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("coverage::IsLCovEnabled()"
" (" "Coverage must be enabled for process before generating LCov info"
")", "./../../../../js/src/vm/BytecodeUtil.cpp", 2923); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()" ") (" "Coverage must be enabled for process before generating LCov info"
")"); do { MOZ_CrashSequence(__null, 2923); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2923 "Coverage must be enabled for process before generating LCov info")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(coverage::IsLCovEnabled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(coverage::IsLCovEnabled())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("coverage::IsLCovEnabled()"
" (" "Coverage must be enabled for process before generating LCov info"
")", "./../../../../js/src/vm/BytecodeUtil.cpp", 2923); AnnotateMozCrashReason
("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()" ") (" "Coverage must be enabled for process before generating LCov info"
")"); do { MOZ_CrashSequence(__null, 2923); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2924
2925 // Hold the scripts that we have already flushed, to avoid flushing them
2926 // twice.
2927 using JSScriptSet = GCHashSet<JSScript*>;
2928 Rooted<JSScriptSet> scriptsDone(cx, JSScriptSet(cx));
2929
2930 Rooted<ScriptVector> queue(cx, ScriptVector(cx));
2931
2932 {
2933 CollectedScripts result(&queue);
2934 IterateScripts(cx, realm, &result, &CollectedScripts::consider);
2935 if (!result.ok) {
2936 ReportOutOfMemory(cx);
2937 return false;
2938 }
2939 }
2940
2941 if (queue.length() == 0) {
2942 return true;
2943 }
2944
2945 // Ensure the LCovRealm exists to collect info into.
2946 coverage::LCovRealm* lcovRealm = realm->lcovRealm();
2947 if (!lcovRealm) {
2948 return false;
2949 }
2950
2951 // Collect code coverage info for one realm.
2952 do {
2953 RootedScript script(cx, queue.popCopy());
2954 RootedFunction fun(cx);
2955
2956 JSScriptSet::AddPtr entry = scriptsDone.lookupForAdd(script);
2957 if (entry) {
2958 continue;
2959 }
2960
2961 if (!coverage::CollectScriptCoverage(script)) {
2962 ReportOutOfMemory(cx);
2963 return false;
2964 }
2965
2966 script->resetScriptCounts();
2967
2968 if (!scriptsDone.add(entry, script)) {
2969 return false;
2970 }
2971
2972 if (!script->isTopLevel()) {
2973 continue;
2974 }
2975
2976 // Iterate from the last to the first object in order to have
2977 // the functions them visited in the opposite order when popping
2978 // elements from the stack of remaining scripts, such that the
2979 // functions are more-less listed with increasing line numbers.
2980 auto gcthings = script->gcthings();
2981 for (JS::GCCellPtr gcThing : mozilla::Reversed(gcthings)) {
2982 if (!gcThing.is<JSObject>()) {
2983 continue;
2984 }
2985 JSObject* obj = &gcThing.as<JSObject>();
2986
2987 if (!obj->is<JSFunction>()) {
2988 continue;
2989 }
2990 fun = &obj->as<JSFunction>();
2991
2992 // getOrCreateScript requires an interpreted function. Skip native or
2993 // partially-initialized functions seen while walking gcthings directly.
2994 if (!fun->isInterpreted()) {
2995 continue;
2996 }
2997
2998 // Queue the script in the list of script associated to the
2999 // current source.
3000 JSScript* childScript = JSFunction::getOrCreateScript(cx, fun);
3001 if (!childScript || !queue.append(childScript)) {
3002 return false;
3003 }
3004 }
3005 } while (!queue.empty());
3006
3007 bool isEmpty = true;
3008 lcovRealm->exportInto(out, &isEmpty);
3009 return true;
3010}
3011
3012JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummaryAll(JSContext* cx,
3013 size_t* length) {
3014 Sprinter out(cx);
3015 if (!out.init()) {
3016 return nullptr;
3017 }
3018
3019 for (RealmsIter realm(cx->runtime()); !realm.done(); realm.next()) {
3020 if (!GenerateLcovInfo(cx, realm, out)) {
3021 return nullptr;
3022 }
3023 }
3024
3025 *length = out.length();
3026 return out.release();
3027}
3028
3029JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx,
3030 size_t* length) {
3031 Sprinter out(cx);
3032 if (!out.init()) {
3033 return nullptr;
3034 }
3035
3036 if (!GenerateLcovInfo(cx, cx->realm(), out)) {
3037 return nullptr;
3038 }
3039
3040 *length = out.length();
3041 return out.release();
3042}