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-18/lib/clang/18 -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/js/src/js-confdefs.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 -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/c/include -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/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../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 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -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-05-16-034744-15991-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, "", 5, 0,
1, JOF_ATOM|JOF_USES_ENV) 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
(BindGName, bind_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME|
JOF_IC) 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, "", 5, 0, 1, JOF_ATOM
|JOF_USES_ENV) 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(BindGName
, bind_g_name, __null, 5, 0, 1, JOF_ATOM|JOF_GNAME|JOF_IC) 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, "", 5, 0, 1, JOF_ATOM
|JOF_USES_ENV) 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(BindGName, bind_g_name, __null
, 5, 0, 1, JOF_ATOM|JOF_GNAME|JOF_IC) 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
1108static UniqueChars 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::BindGName:
1979 return write("GLOBAL");
1980
1981 case JSOp::BindName:
1982 case JSOp::BindVar:
1983 return write("ENV");
1984
1985 case JSOp::Callee:
1986 return write("CALLEE");
1987
1988 case JSOp::EnvCallee:
1989 return write("ENVCALLEE");
1990
1991 case JSOp::CallSiteObj:
1992 return write("OBJ");
1993
1994 case JSOp::Double:
1995 sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
1996 return true;
1997
1998 case JSOp::Exception:
1999 return write("EXCEPTION");
2000
2001 case JSOp::ExceptionAndStack:
2002 if (defIndex == 0) {
2003 return write("EXCEPTION");
2004 }
2005 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"
, 2005); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 1"
")"); do { *((volatile int*)__null) = 2005; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2006 return write("STACK");
2007
2008 case JSOp::Try:
2009 // Used for the values live on entry to the finally block.
2010 // See TryNoteKind::Finally above.
2011 if (defIndex == 0) {
2012 return write("PC");
2013 }
2014 if (defIndex == 1) {
2015 return write("STACK");
2016 }
2017 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"
, 2017); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 2"
")"); do { *((volatile int*)__null) = 2017; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2018 return write("THROWING");
2019
2020 case JSOp::FunctionThis:
2021 case JSOp::ImplicitThis:
2022 return write("THIS");
2023
2024 case JSOp::FunWithProto:
2025 return write("FUN");
2026
2027 case JSOp::Generator:
2028 return write("GENERATOR");
2029
2030 case JSOp::GetImport:
2031 return write("VAL");
2032
2033 case JSOp::GetRval:
2034 return write("RVAL");
2035
2036 case JSOp::Hole:
2037 return write("HOLE");
2038
2039 case JSOp::IsGenClosing:
2040 // For stack dump, defIndex == 0 is not used.
2041 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"
, 2041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 1"
")"); do { *((volatile int*)__null) = 2041; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2042 return write("ISGENCLOSING");
2043
2044 case JSOp::IsNoIter:
2045 // For stack dump, defIndex == 0 is not used.
2046 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"
, 2046); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 1"
")"); do { *((volatile int*)__null) = 2046; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2047 return write("ISNOITER");
2048
2049 case JSOp::IsConstructing:
2050 return write("JS_IS_CONSTRUCTING");
2051
2052 case JSOp::IsNullOrUndefined:
2053 return write("IS_NULL_OR_UNDEF");
2054
2055 case JSOp::Iter:
2056 return write("ITER");
2057
2058 case JSOp::Lambda:
2059 return write("FUN");
2060
2061 case JSOp::ToAsyncIter:
2062 return write("ASYNCITER");
2063
2064 case JSOp::MoreIter:
2065 // For stack dump, defIndex == 0 is not used.
2066 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"
, 2066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 1"
")"); do { *((volatile int*)__null) = 2066; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2067 return write("MOREITER");
2068
2069 case JSOp::NewInit:
2070 case JSOp::NewObject:
2071 case JSOp::ObjWithProto:
2072 return write("OBJ");
2073
2074 case JSOp::OptimizeGetIterator:
2075 case JSOp::OptimizeSpreadCall:
2076 return write("OPTIMIZED");
2077
2078 case JSOp::Rest:
2079 return write("REST");
2080
2081 case JSOp::Resume:
2082 return write("RVAL");
2083
2084 case JSOp::SuperBase:
2085 return write("HOMEOBJECTPROTO");
2086
2087 case JSOp::ToPropertyKey:
2088 return write("TOPROPERTYKEY(") && decompilePCForStackOperand(pc, -1) &&
2089 write(")");
2090 case JSOp::ToString:
2091 return write("TOSTRING(") && decompilePCForStackOperand(pc, -1) &&
2092 write(")");
2093
2094 case JSOp::Uninitialized:
2095 return write("UNINITIALIZED");
2096
2097 case JSOp::InitialYield:
2098 case JSOp::Await:
2099 case JSOp::Yield:
2100 // Printing "yield SOMETHING" is confusing since the operand doesn't
2101 // match to the syntax, since the stack operand for "yield 10" is
2102 // the result object, not 10.
2103 if (defIndex == 0) {
2104 return write("RVAL");
2105 }
2106 if (defIndex == 1) {
2107 return write("GENERATOR");
2108 }
2109 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"
, 2109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 2"
")"); do { *((volatile int*)__null) = 2109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2110 return write("RESUMEKIND");
2111
2112 case JSOp::ResumeKind:
2113 return write("RESUMEKIND");
2114
2115 case JSOp::AsyncAwait:
2116 case JSOp::AsyncResolve:
2117 case JSOp::AsyncReject:
2118 return write("PROMISE");
2119
2120 case JSOp::CanSkipAwait:
2121 // For stack dump, defIndex == 0 is not used.
2122 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"
, 2122); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 1"
")"); do { *((volatile int*)__null) = 2122; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2123 return write("CAN_SKIP_AWAIT");
2124
2125 case JSOp::MaybeExtractAwaitValue:
2126 // For stack dump, defIndex == 1 is not used.
2127 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"
, 2127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "defIndex == 0"
")"); do { *((volatile int*)__null) = 2127; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2128 return write("MAYBE_RESOLVED(") && decompilePCForStackOperand(pc, -2) &&
2129 write(")");
2130
2131 case JSOp::CheckPrivateField:
2132 return write("HasPrivateField");
2133
2134 case JSOp::NewPrivateName:
2135 return write("PRIVATENAME");
2136
2137 case JSOp::CheckReturn:
2138 return write("RVAL");
2139
2140 case JSOp::HasOwn:
2141 return write("HasOwn(") && decompilePCForStackOperand(pc, -2) &&
2142 write(", ") && decompilePCForStackOperand(pc, -1) && write(")");
2143
2144 default:
2145 break;
2146 }
2147 return write("<unknown>");
2148 }
2149#endif /* DEBUG */
2150
2151 return write("(intermediate value)");
2152}
2153
2154bool ExpressionDecompiler::decompilePC(
2155 const OffsetAndDefIndex& offsetAndDefIndex) {
2156 if (offsetAndDefIndex.isSpecial()) {
2157#ifdef DEBUG1
2158 if (isStackDump) {
2159 if (offsetAndDefIndex.isMerged()) {
2160 if (!write("merged<")) {
2161 return false;
2162 }
2163 } else if (offsetAndDefIndex.isIgnored()) {
2164 if (!write("ignored<")) {
2165 return false;
2166 }
2167 }
2168
2169 if (!decompilePC(script->offsetToPC(offsetAndDefIndex.specialOffset()),
2170 offsetAndDefIndex.specialDefIndex())) {
2171 return false;
2172 }
2173
2174 if (!write(">")) {
2175 return false;
2176 }
2177
2178 return true;
2179 }
2180#endif /* DEBUG */
2181 return write("(intermediate value)");
2182 }
2183
2184 return decompilePC(script->offsetToPC(offsetAndDefIndex.offset()),
2185 offsetAndDefIndex.defIndex());
2186}
2187
2188bool ExpressionDecompiler::init() {
2189 cx->check(script);
2190 return sprinter.init();
2191}
2192
2193bool ExpressionDecompiler::write(const char* s) {
2194 sprinter.put(s);
2195 return true;
2196}
2197
2198bool ExpressionDecompiler::write(JSString* str) {
2199 if (str == cx->names().dot_this_) {
2200 return write("this");
2201 }
2202 if (str == cx->names().dot_newTarget_) {
2203 return write("new.target");
2204 }
2205 sprinter.putString(cx, str);
2206 return true;
2207}
2208
2209bool ExpressionDecompiler::quote(JSString* s, char quote) {
2210 QuoteString(&sprinter, s, quote);
2211 return true;
2212}
2213
2214JSAtom* ExpressionDecompiler::loadAtom(jsbytecode* pc) {
2215 return script->getAtom(pc);
2216}
2217
2218JSString* ExpressionDecompiler::loadString(jsbytecode* pc) {
2219 return script->getString(pc);
2220}
2221
2222JSAtom* ExpressionDecompiler::getArg(unsigned slot) {
2223 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"
, 2223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "script->isFunction()"
")"); do { *((volatile int*)__null) = 2223; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2224 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"
, 2224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slot < script->numArgs()"
")"); do { *((volatile int*)__null) = 2224; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2225
2226 for (PositionalFormalParameterIter fi(script); fi; fi++) {
2227 if (fi.argumentSlot() == slot) {
2228 if (!fi.isDestructured()) {
2229 return fi.name();
2230 }
2231
2232 // Destructured arguments have no single binding name.
2233 static const char destructuredParam[] = "(destructured parameter)";
2234 return Atomize(cx, destructuredParam, strlen(destructuredParam));
2235 }
2236 }
2237
2238 MOZ_CRASH("No binding")do { do { } while (false); MOZ_ReportCrash("" "No binding", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/vm/BytecodeUtil.cpp"
, 2238); AnnotateMozCrashReason("MOZ_CRASH(" "No binding" ")"
); do { *((volatile int*)__null) = 2238; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2239}
2240
2241UniqueChars ExpressionDecompiler::getOutput() { return sprinter.release(); }
2242
2243} // anonymous namespace
2244
2245#if defined(DEBUG1) || defined(JS_JITSPEW1)
2246static bool DecompileAtPCForStackDump(
2247 JSContext* cx, HandleScript script,
2248 const OffsetAndDefIndex& offsetAndDefIndex, StringPrinter* sp) {
2249 // The expression decompiler asserts the script is in the current realm.
2250 AutoRealm ar(cx, script);
2251
2252 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2253 BytecodeParser parser(cx, allocScope.alloc(), script);
2254 parser.setStackDump();
2255 if (!parser.parse()) {
2256 return false;
2257 }
2258
2259 ExpressionDecompiler ed(cx, script, parser);
2260 ed.setStackDump();
2261 if (!ed.init()) {
2262 return false;
2263 }
2264
2265 if (!ed.decompilePC(offsetAndDefIndex)) {
2266 return false;
2267 }
2268
2269 UniqueChars result = ed.getOutput();
2270 if (!result) {
2271 return false;
2272 }
2273
2274 sp->put(result.get());
2275 return true;
2276}
2277#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
2278
2279static bool FindStartPC(JSContext* cx, const FrameIter& iter,
2280 const BytecodeParser& parser, int spindex,
2281 int skipStackHits, const Value& v, jsbytecode** valuepc,
2282 uint8_t* defIndex) {
2283 jsbytecode* current = *valuepc;
2284 *valuepc = nullptr;
2285 *defIndex = 0;
2286
2287 if (spindex < 0 && spindex + int(parser.stackDepthAtPC(current)) < 0) {
2288 spindex = JSDVG_SEARCH_STACK1;
2289 }
2290
2291 if (spindex == JSDVG_SEARCH_STACK1) {
2292 size_t index = iter.numFrameSlots();
2293
2294 // The decompiler may be called from inside functions that are not
2295 // called from script, but via the C++ API directly, such as
2296 // Invoke. In that case, the youngest script frame may have a
2297 // completely unrelated pc and stack depth, so we give up.
2298 if (index < size_t(parser.stackDepthAtPC(current))) {
2299 return true;
2300 }
2301
2302 // We search from fp->sp to base to find the most recently calculated
2303 // value matching v under assumption that it is the value that caused
2304 // the exception.
2305 int stackHits = 0;
2306 Value s;
2307 do {
2308 if (!index) {
2309 return true;
2310 }
2311 s = iter.frameSlotValue(--index);
2312 } while (s != v || stackHits++ != skipStackHits);
2313
2314 // If the current PC has fewer values on the stack than the index we are
2315 // looking for, the blamed value must be one pushed by the current
2316 // bytecode (e.g. JSOp::MoreIter), so restore *valuepc.
2317 if (index < size_t(parser.stackDepthAtPC(current))) {
2318 *valuepc = parser.pcForStackOperand(current, index, defIndex);
2319 } else {
2320 *valuepc = current;
2321 *defIndex = index - size_t(parser.stackDepthAtPC(current));
2322 }
2323 } else {
2324 *valuepc = parser.pcForStackOperand(current, spindex, defIndex);
2325 }
2326 return true;
2327}
2328
2329static bool DecompileExpressionFromStack(JSContext* cx, int spindex,
2330 int skipStackHits, HandleValue v,
2331 UniqueChars* res) {
2332 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"
, 2333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "spindex < 0 || spindex == 0 || spindex == 1"
")"); do { *((volatile int*)__null) = 2333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2333 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"
, 2333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "spindex < 0 || spindex == 0 || spindex == 1"
")"); do { *((volatile int*)__null) = 2333; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2334
2335 *res = nullptr;
2336
2337 /*
2338 * Give up if we need deterministic behavior for differential testing.
2339 * IonMonkey doesn't use InterpreterFrames and this ensures we get the same
2340 * error messages.
2341 */
2342 if (js::SupportDifferentialTesting()) {
2343 return true;
2344 }
2345
2346 if (spindex == JSDVG_IGNORE_STACK0) {
2347 return true;
2348 }
2349
2350 FrameIter frameIter(cx);
2351
2352 if (frameIter.done() || !frameIter.hasScript() ||
2353 frameIter.realm() != cx->realm() || frameIter.inPrologue()) {
2354 return true;
2355 }
2356
2357 /*
2358 * FIXME: Fall back if iter.isIon(), since the stack snapshot may be for the
2359 * previous pc (see bug 831120).
2360 */
2361 if (frameIter.isIon()) {
2362 return true;
2363 }
2364
2365 RootedScript script(cx, frameIter.script());
2366 jsbytecode* valuepc = frameIter.pc();
2367
2368 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"
, 2368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "script->containsPC(valuepc)"
")"); do { *((volatile int*)__null) = 2368; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2369
2370 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2371 BytecodeParser parser(cx, allocScope.alloc(), frameIter.script());
2372 if (!parser.parse()) {
2373 return false;
2374 }
2375
2376 uint8_t defIndex;
2377 if (!FindStartPC(cx, frameIter, parser, spindex, skipStackHits, v, &valuepc,
2378 &defIndex)) {
2379 return false;
2380 }
2381 if (!valuepc) {
2382 return true;
2383 }
2384
2385 ExpressionDecompiler ed(cx, script, parser);
2386 if (!ed.init()) {
2387 return false;
2388 }
2389 if (!ed.decompilePC(valuepc, defIndex)) {
2390 return false;
2391 }
2392
2393 *res = ed.getOutput();
2394 return *res != nullptr;
2395}
2396
2397UniqueChars js::DecompileValueGenerator(JSContext* cx, int spindex,
2398 HandleValue v, HandleString fallbackArg,
2399 int skipStackHits) {
2400 RootedString fallback(cx, fallbackArg);
2401 {
2402 UniqueChars result;
2403 if (!DecompileExpressionFromStack(cx, spindex, skipStackHits, v, &result)) {
2404 return nullptr;
2405 }
2406 if (result && strcmp(result.get(), "(intermediate value)")) {
2407 return result;
2408 }
2409 }
2410 if (!fallback) {
2411 if (v.isUndefined()) {
2412 return DuplicateString(cx, "undefined"); // Prevent users from seeing
2413 // "(void 0)"
2414 }
2415 fallback = ValueToSource(cx, v);
2416 if (!fallback) {
2417 return nullptr;
2418 }
2419 }
2420
2421 return StringToNewUTF8CharsZ(cx, *fallback);
2422}
2423
2424static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
2425 UniqueChars* res) {
2426 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"
, 2426); AnnotateMozCrashReason("MOZ_ASSERT" "(" "formalIndex >= 0"
")"); do { *((volatile int*)__null) = 2426; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2427
2428 *res = nullptr;
2429
2430 /* See note in DecompileExpressionFromStack. */
2431 if (js::SupportDifferentialTesting()) {
2432 return true;
2433 }
2434
2435 /*
2436 * Settle on the nearest script frame, which should be the builtin that
2437 * called the intrinsic.
2438 */
2439 FrameIter frameIter(cx);
2440 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"
, 2440); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!frameIter.done()"
")"); do { *((volatile int*)__null) = 2440; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2441 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"
, 2441); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameIter.script()->selfHosted()"
")"); do { *((volatile int*)__null) = 2441; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2442
2443 /*
2444 * Get the second-to-top frame, the non-self-hosted caller of the builtin
2445 * that called the intrinsic.
2446 */
2447 ++frameIter;
2448 if (frameIter.done() || !frameIter.hasScript() ||
2449 frameIter.script()->selfHosted() || frameIter.realm() != cx->realm()) {
2450 return true;
2451 }
2452
2453 RootedScript script(cx, frameIter.script());
2454 jsbytecode* current = frameIter.pc();
2455
2456 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"
, 2456); AnnotateMozCrashReason("MOZ_ASSERT" "(" "script->containsPC(current)"
")"); do { *((volatile int*)__null) = 2456; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2457
2458 if (current < script->main()) {
2459 return true;
2460 }
2461
2462 /* Don't handle getters, setters or calls from fun.call/fun.apply. */
2463 JSOp op = JSOp(*current);
2464 if (op != JSOp::Call && op != JSOp::CallContent &&
2465 op != JSOp::CallIgnoresRv && op != JSOp::New && op != JSOp::NewContent) {
2466 return true;
2467 }
2468
2469 if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current)) {
2470 return true;
2471 }
2472
2473 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2474 BytecodeParser parser(cx, allocScope.alloc(), script);
2475 if (!parser.parse()) {
2476 return false;
2477 }
2478
2479 bool pushedNewTarget = op == JSOp::New || op == JSOp::NewContent;
2480 int formalStackIndex = parser.stackDepthAtPC(current) - GET_ARGC(current) -
2481 pushedNewTarget + formalIndex;
2482 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"
, 2482); AnnotateMozCrashReason("MOZ_ASSERT" "(" "formalStackIndex >= 0"
")"); do { *((volatile int*)__null) = 2482; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2483 if (uint32_t(formalStackIndex) >= parser.stackDepthAtPC(current)) {
2484 return true;
2485 }
2486
2487 ExpressionDecompiler ed(cx, script, parser);
2488 if (!ed.init()) {
2489 return false;
2490 }
2491 if (!ed.decompilePCForStackOperand(current, formalStackIndex)) {
2492 return false;
2493 }
2494
2495 *res = ed.getOutput();
2496 return *res != nullptr;
2497}
2498
2499JSString* js::DecompileArgument(JSContext* cx, int formalIndex, HandleValue v) {
2500 {
2501 UniqueChars result;
2502 if (!DecompileArgumentFromStack(cx, formalIndex, &result)) {
2503 return nullptr;
2504 }
2505 if (result && strcmp(result.get(), "(intermediate value)")) {
2506 JS::ConstUTF8CharsZ utf8chars(result.get(), strlen(result.get()));
2507 return NewStringCopyUTF8Z(cx, utf8chars);
2508 }
2509 }
2510 if (v.isUndefined()) {
2511 return cx->names().undefined; // Prevent users from seeing "(void 0)"
2512 }
2513
2514 return ValueToSource(cx, v);
2515}
2516
2517extern bool js::IsValidBytecodeOffset(JSContext* cx, JSScript* script,
2518 size_t offset) {
2519 // This could be faster (by following jump instructions if the target
2520 // is <= offset).
2521 for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
2522 size_t here = r.frontOffset();
2523 if (here >= offset) {
2524 return here == offset;
2525 }
2526 }
2527 return false;
2528}
2529
2530/*
2531 * There are three possible PCCount profiling states:
2532 *
2533 * 1. None: Neither scripts nor the runtime have count information.
2534 * 2. Profile: Active scripts have count information, the runtime does not.
2535 * 3. Query: Scripts do not have count information, the runtime does.
2536 *
2537 * When starting to profile scripts, counting begins immediately, with all JIT
2538 * code discarded and recompiled with counts as necessary. Active interpreter
2539 * frames will not begin profiling until they begin executing another script
2540 * (via a call or return).
2541 *
2542 * The below API functions manage transitions to new states, according
2543 * to the table below.
2544 *
2545 * Old State
2546 * -------------------------
2547 * Function None Profile Query
2548 * --------
2549 * StartPCCountProfiling Profile Profile Profile
2550 * StopPCCountProfiling None Query Query
2551 * PurgePCCounts None None None
2552 */
2553
2554static void ReleaseScriptCounts(JSRuntime* rt) {
2555 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"
, 2555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rt->scriptAndCountsVector"
")"); do { *((volatile int*)__null) = 2555; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2556
2557 js_delete(rt->scriptAndCountsVector.ref());
2558 rt->scriptAndCountsVector = nullptr;
2559}
2560
2561void JS::StartPCCountProfiling(JSContext* cx) {
2562 JSRuntime* rt = cx->runtime();
2563
2564 if (rt->profilingScripts) {
2565 return;
2566 }
2567
2568 if (rt->scriptAndCountsVector) {
2569 ReleaseScriptCounts(rt);
2570 }
2571
2572 ReleaseAllJITCode(rt->gcContext());
2573
2574 rt->profilingScripts = true;
2575}
2576
2577void JS::StopPCCountProfiling(JSContext* cx) {
2578 JSRuntime* rt = cx->runtime();
2579
2580 if (!rt->profilingScripts) {
2581 return;
2582 }
2583 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"
, 2583); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rt->scriptAndCountsVector"
")"); do { *((volatile int*)__null) = 2583; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2584
2585 ReleaseAllJITCode(rt->gcContext());
2586
2587 auto* vec = cx->new_<PersistentRooted<ScriptAndCountsVector>>(
2588 cx, ScriptAndCountsVector());
2589 if (!vec) {
2590 return;
2591 }
2592
2593 for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
2594 for (auto base = zone->cellIter<BaseScript>(); !base.done(); base.next()) {
2595 if (base->hasScriptCounts() && base->hasJitScript()) {
2596 if (!vec->append(base->asJSScript())) {
2597 return;
2598 }
2599 }
2600 }
2601 }
2602
2603 rt->profilingScripts = false;
2604 rt->scriptAndCountsVector = vec;
2605}
2606
2607void JS::PurgePCCounts(JSContext* cx) {
2608 JSRuntime* rt = cx->runtime();
2609
2610 if (!rt->scriptAndCountsVector) {
2611 return;
2612 }
2613 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"
, 2613); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rt->profilingScripts"
")"); do { *((volatile int*)__null) = 2613; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2614
2615 ReleaseScriptCounts(rt);
2616}
2617
2618size_t JS::GetPCCountScriptCount(JSContext* cx) {
2619 JSRuntime* rt = cx->runtime();
2620
2621 if (!rt->scriptAndCountsVector) {
2622 return 0;
2623 }
2624
2625 return rt->scriptAndCountsVector->length();
2626}
2627
2628[[nodiscard]] static bool JSONStringProperty(StringPrinter& sp,
2629 JSONPrinter& json,
2630 const char* name, JSString* str) {
2631 json.beginStringProperty(name);
2632 JSONQuoteString(&sp, str);
2633 json.endStringProperty();
2634 return true;
2635}
2636
2637JSString* JS::GetPCCountScriptSummary(JSContext* cx, size_t index) {
2638 JSRuntime* rt = cx->runtime();
2639
2640 if (!rt->scriptAndCountsVector ||
2641 index >= rt->scriptAndCountsVector->length()) {
2642 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2643 JSMSG_BUFFER_TOO_SMALL);
2644 return nullptr;
2645 }
2646
2647 const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
2648 RootedScript script(cx, sac.script);
2649
2650 JSSprinter sp(cx);
2651 if (!sp.init()) {
2652 return nullptr;
2653 }
2654
2655 JSONPrinter json(sp, false);
2656
2657 json.beginObject();
2658
2659 Rooted<JSString*> filenameStr(cx);
2660 if (const char* filename = script->filename()) {
2661 filenameStr =
2662 JS_NewStringCopyUTF8N(cx, JS::UTF8Chars(filename, strlen(filename)));
2663 } else {
2664 filenameStr = JS_GetEmptyString(cx);
2665 }
2666 if (!filenameStr) {
2667 return nullptr;
2668 }
2669 if (!JSONStringProperty(sp, json, "file", filenameStr)) {
2670 return nullptr;
2671 }
2672 json.property("line", script->lineno());
2673
2674 if (JSFunction* fun = script->function()) {
2675 if (JSAtom* atom = fun->fullDisplayAtom()) {
2676 if (!JSONStringProperty(sp, json, "name", atom)) {
2677 return nullptr;
2678 }
2679 }
2680 }
2681
2682 uint64_t total = 0;
2683
2684 AllBytecodesIterable iter(script);
2685 for (BytecodeLocation loc : iter) {
2686 if (const PCCounts* counts = sac.maybeGetPCCounts(loc.toRawBytecode())) {
2687 total += counts->numExec();
2688 }
2689 }
2690
2691 json.beginObjectProperty("totals");
2692
2693 json.property(PCCounts::numExecName, total);
2694
2695 uint64_t ionActivity = 0;
2696 jit::IonScriptCounts* ionCounts = sac.getIonCounts();
2697 while (ionCounts) {
2698 for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
2699 ionActivity += ionCounts->block(i).hitCount();
2700 }
2701 ionCounts = ionCounts->previous();
2702 }
2703 if (ionActivity) {
2704 json.property("ion", ionActivity);
2705 }
2706
2707 json.endObject();
2708
2709 json.endObject();
2710
2711 return sp.release(cx);
2712}
2713
2714static bool GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac,
2715 StringPrinter& sp) {
2716 JSONPrinter json(sp, false);
2717
2718 RootedScript script(cx, sac.script);
2719
2720 LifoAllocScope allocScope(&cx->tempLifoAlloc());
2721 BytecodeParser parser(cx, allocScope.alloc(), script);
2722 if (!parser.parse()) {
2723 return false;
2724 }
2725
2726 json.beginObject();
2727
2728 JSString* str = JS_DecompileScript(cx, script);
2729 if (!str) {
2730 return false;
2731 }
2732
2733 if (!JSONStringProperty(sp, json, "text", str)) {
2734 return false;
2735 }
2736
2737 json.property("line", script->lineno());
2738
2739 json.beginListProperty("opcodes");
2740
2741 uint64_t hits = 0;
2742 for (BytecodeRangeWithPosition range(cx, script); !range.empty();
2743 range.popFront()) {
2744 jsbytecode* pc = range.frontPC();
2745 size_t offset = script->pcToOffset(pc);
2746 JSOp op = JSOp(*pc);
2747
2748 // If the current instruction is a jump target,
2749 // then update the number of hits.
2750 if (const PCCounts* counts = sac.maybeGetPCCounts(pc)) {
2751 hits = counts->numExec();
2752 }
2753
2754 json.beginObject();
2755
2756 json.property("id", offset);
2757 json.property("line", range.frontLineNumber());
2758 json.property("name", CodeName(op));
2759
2760 {
2761 ExpressionDecompiler ed(cx, script, parser);
2762 if (!ed.init()) {
2763 return false;
2764 }
2765 // defIndex passed here is not used.
2766 if (!ed.decompilePC(pc, /* defIndex = */ 0)) {
2767 return false;
2768 }
2769 UniqueChars text = ed.getOutput();
2770 if (!text) {
2771 return false;
2772 }
2773
2774 JS::ConstUTF8CharsZ utf8chars(text.get(), strlen(text.get()));
2775 JSString* str = NewStringCopyUTF8Z(cx, utf8chars);
2776 if (!str) {
2777 return false;
2778 }
2779
2780 if (!JSONStringProperty(sp, json, "text", str)) {
2781 return false;
2782 }
2783 }
2784
2785 json.beginObjectProperty("counts");
2786 if (hits > 0) {
2787 json.property(PCCounts::numExecName, hits);
2788 }
2789 json.endObject();
2790
2791 json.endObject();
2792
2793 // If the current instruction has thrown,
2794 // then decrement the hit counts with the number of throws.
2795 if (const PCCounts* counts = sac.maybeGetThrowCounts(pc)) {
2796 hits -= counts->numExec();
2797 }
2798 }
2799
2800 json.endList();
2801
2802 if (jit::IonScriptCounts* ionCounts = sac.getIonCounts()) {
2803 json.beginListProperty("ion");
2804
2805 while (ionCounts) {
2806 json.beginList();
2807 for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
2808 const jit::IonBlockCounts& block = ionCounts->block(i);
2809
2810 json.beginObject();
2811 json.property("id", block.id());
2812 json.property("offset", block.offset());
2813
2814 json.beginListProperty("successors");
2815 for (size_t j = 0; j < block.numSuccessors(); j++) {
2816 json.value(block.successor(j));
2817 }
2818 json.endList();
2819
2820 json.property("hits", block.hitCount());
2821
2822 JSString* str = NewStringCopyZ<CanGC>(cx, block.code());
2823 if (!str) {
2824 return false;
2825 }
2826
2827 if (!JSONStringProperty(sp, json, "code", str)) {
2828 return false;
2829 }
2830
2831 json.endObject();
2832 }
2833 json.endList();
2834
2835 ionCounts = ionCounts->previous();
2836 }
2837
2838 json.endList();
2839 }
2840
2841 json.endObject();
2842
2843 if (sp.hadOutOfMemory()) {
2844 sp.reportOutOfMemory();
2845 return false;
2846 }
2847
2848 return true;
2849}
2850
2851JSString* JS::GetPCCountScriptContents(JSContext* cx, size_t index) {
2852 JSRuntime* rt = cx->runtime();
2853
2854 if (!rt->scriptAndCountsVector ||
2855 index >= rt->scriptAndCountsVector->length()) {
2856 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2857 JSMSG_BUFFER_TOO_SMALL);
2858 return nullptr;
2859 }
2860
2861 const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
2862 JSScript* script = sac.script;
2863
2864 JSSprinter sp(cx);
2865 if (!sp.init()) {
2866 return nullptr;
2867 }
2868
2869 {
2870 AutoRealm ar(cx, &script->global());
2871 if (!GetPCCountJSON(cx, sac, sp)) {
2872 return nullptr;
2873 }
2874 }
2875
2876 return sp.release(cx);
2877}
2878
2879struct CollectedScripts {
2880 MutableHandle<ScriptVector> scripts;
2881 bool ok = true;
2882
2883 explicit CollectedScripts(MutableHandle<ScriptVector> scripts)
2884 : scripts(scripts) {}
2885
2886 static void consider(JSRuntime* rt, void* data, BaseScript* script,
2887 const JS::AutoRequireNoGC& nogc) {
2888 auto self = static_cast<CollectedScripts*>(data);
2889 if (!script->filename()) {
2890 return;
2891 }
2892 if (!self->scripts.append(script->asJSScript())) {
2893 self->ok = false;
2894 }
2895 }
2896};
2897
2898static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm,
2899 GenericPrinter& out) {
2900 AutoRealmUnchecked ar(cx, realm);
2901
2902 // Collect the list of scripts which are part of the current realm.
2903
2904 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"
, 2906); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()"
") (" "Coverage must be enabled for process before generating LCov info"
")"); do { *((volatile int*)__null) = 2906; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2905 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"
, 2906); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()"
") (" "Coverage must be enabled for process before generating LCov info"
")"); do { *((volatile int*)__null) = 2906; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2906 "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"
, 2906); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "coverage::IsLCovEnabled()"
") (" "Coverage must be enabled for process before generating LCov info"
")"); do { *((volatile int*)__null) = 2906; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2907
2908 // Hold the scripts that we have already flushed, to avoid flushing them
2909 // twice.
2910 using JSScriptSet = GCHashSet<JSScript*>;
2911 Rooted<JSScriptSet> scriptsDone(cx, JSScriptSet(cx));
2912
2913 Rooted<ScriptVector> queue(cx, ScriptVector(cx));
2914
2915 {
2916 CollectedScripts result(&queue);
2917 IterateScripts(cx, realm, &result, &CollectedScripts::consider);
2918 if (!result.ok) {
2919 ReportOutOfMemory(cx);
2920 return false;
2921 }
2922 }
2923
2924 if (queue.length() == 0) {
2925 return true;
2926 }
2927
2928 // Ensure the LCovRealm exists to collect info into.
2929 coverage::LCovRealm* lcovRealm = realm->lcovRealm();
2930 if (!lcovRealm) {
2931 return false;
2932 }
2933
2934 // Collect code coverage info for one realm.
2935 do {
2936 RootedScript script(cx, queue.popCopy());
2937 RootedFunction fun(cx);
2938
2939 JSScriptSet::AddPtr entry = scriptsDone.lookupForAdd(script);
2940 if (entry) {
2941 continue;
2942 }
2943
2944 if (!coverage::CollectScriptCoverage(script, false)) {
2945 ReportOutOfMemory(cx);
2946 return false;
2947 }
2948
2949 script->resetScriptCounts();
2950
2951 if (!scriptsDone.add(entry, script)) {
2952 return false;
2953 }
2954
2955 if (!script->isTopLevel()) {
2956 continue;
2957 }
2958
2959 // Iterate from the last to the first object in order to have
2960 // the functions them visited in the opposite order when popping
2961 // elements from the stack of remaining scripts, such that the
2962 // functions are more-less listed with increasing line numbers.
2963 auto gcthings = script->gcthings();
2964 for (JS::GCCellPtr gcThing : mozilla::Reversed(gcthings)) {
2965 if (!gcThing.is<JSObject>()) {
2966 continue;
2967 }
2968 JSObject* obj = &gcThing.as<JSObject>();
2969
2970 if (!obj->is<JSFunction>()) {
2971 continue;
2972 }
2973 fun = &obj->as<JSFunction>();
2974
2975 // Ignore asm.js functions
2976 if (!fun->isInterpreted()) {
2977 continue;
2978 }
2979
2980 // Queue the script in the list of script associated to the
2981 // current source.
2982 JSScript* childScript = JSFunction::getOrCreateScript(cx, fun);
2983 if (!childScript || !queue.append(childScript)) {
2984 return false;
2985 }
2986 }
2987 } while (!queue.empty());
2988
2989 bool isEmpty = true;
2990 lcovRealm->exportInto(out, &isEmpty);
2991 return true;
2992}
2993
2994JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummaryAll(JSContext* cx,
2995 size_t* length) {
2996 Sprinter out(cx);
2997 if (!out.init()) {
2998 return nullptr;
2999 }
3000
3001 for (RealmsIter realm(cx->runtime()); !realm.done(); realm.next()) {
3002 if (!GenerateLcovInfo(cx, realm, out)) {
3003 return nullptr;
3004 }
3005 }
3006
3007 *length = out.length();
3008 return out.release();
3009}
3010
3011JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx,
3012 size_t* length) {
3013 Sprinter out(cx);
3014 if (!out.init()) {
3015 return nullptr;
3016 }
3017
3018 if (!GenerateLcovInfo(cx, cx->realm(), out)) {
3019 return nullptr;
3020 }
3021
3022 *length = out.length();
3023 return out.release();
3024}