Bug Summary

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