summaryrefslogtreecommitdiffstats
path: root/js/src/wasm/WasmDebug.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/wasm/WasmDebug.h
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/wasm/WasmDebug.h')
-rw-r--r--js/src/wasm/WasmDebug.h187
1 files changed, 187 insertions, 0 deletions
diff --git a/js/src/wasm/WasmDebug.h b/js/src/wasm/WasmDebug.h
new file mode 100644
index 0000000000..35c8a838ed
--- /dev/null
+++ b/js/src/wasm/WasmDebug.h
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ *
+ * Copyright 2016 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_debug_h
+#define wasm_debug_h
+
+#include "js/HashTable.h"
+#include "wasm/WasmCode.h"
+#include "wasm/WasmCodegenTypes.h"
+#include "wasm/WasmConstants.h"
+#include "wasm/WasmExprType.h"
+#include "wasm/WasmModule.h"
+#include "wasm/WasmTypeDecls.h"
+#include "wasm/WasmValType.h"
+
+namespace js {
+
+class Debugger;
+class WasmBreakpointSite;
+class WasmInstanceObject;
+
+namespace wasm {
+
+struct MetadataTier;
+
+// The generated source location for the AST node/expression. The offset field
+// refers an offset in an binary format file.
+
+struct ExprLoc {
+ uint32_t lineno;
+ uint32_t column;
+ uint32_t offset;
+ ExprLoc() : lineno(0), column(0), offset(0) {}
+ ExprLoc(uint32_t lineno_, uint32_t column_, uint32_t offset_)
+ : lineno(lineno_), column(column_), offset(offset_) {}
+};
+
+using StepperCounters =
+ HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy>;
+using WasmBreakpointSiteMap =
+ HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>,
+ SystemAllocPolicy>;
+
+/*
+ * [SMDOC] Wasm debug traps
+ *
+ * There is a single debug trap handler for the process, WasmHandleDebugTrap in
+ * WasmBuiltins.cpp. That function is invoked through the Debug Trap Stub,
+ * generated by GenerateDebugTrapStub in WasmStubs.cpp. When any function in an
+ * instance needs to trap for any reason (enter frame, leave frame, breakpoint,
+ * or single-stepping) then a pointer to the Debug Trap Stub is installed in the
+ * Instance. Debug-enabled code will look for this pointer and call it if it is
+ * not null.
+ *
+ * WasmHandleDebugTrap may therefore be called very frequently when any function
+ * in the instance is being debugged, and must filter the trap against the
+ * tables in the DebugState. It can make use of the return address for the
+ * call, which identifies the site uniquely.
+ *
+ * In order to greatly reduce the frequency of calls to the Debug Trap Stub, an
+ * array of flag bits, one per function, is attached to the instance. The code
+ * at the breakable point calls a shared stub within the function containing the
+ * breakable point to check whether the bit is set for the function. If it is
+ * not set, the stub can return to its caller immediately; if the bit is set,
+ * the stub will jump to the installed Debug Trap Stub.
+ */
+
+class DebugState {
+ const SharedCode code_;
+ const SharedModule module_;
+
+ // State maintained when debugging is enabled.
+
+ bool enterFrameTrapsEnabled_;
+ uint32_t enterAndLeaveFrameTrapsCounter_;
+ WasmBreakpointSiteMap breakpointSites_;
+ StepperCounters stepperCounters_;
+
+ void enableDebuggingForFunction(Instance* instance, uint32_t funcIndex);
+ void disableDebuggingForFunction(Instance* instance, uint32_t funcIndex);
+ void enableDebugTrap(Instance* instance);
+ void disableDebugTrap(Instance* instance);
+
+ public:
+ DebugState(const Code& code, const Module& module);
+
+ void trace(JSTracer* trc);
+ void finalize(JS::GCContext* gcx);
+
+ const Bytes& bytecode() const { return module_->debugBytecode(); }
+
+ [[nodiscard]] bool getLineOffsets(size_t lineno, Vector<uint32_t>* offsets);
+ [[nodiscard]] bool getAllColumnOffsets(Vector<ExprLoc>* offsets);
+ [[nodiscard]] bool getOffsetLocation(uint32_t offset, size_t* lineno,
+ size_t* column);
+
+ // The Code can track enter/leave frame events. Any such event triggers
+ // debug trap. The enter/leave frame events enabled or disabled across
+ // all functions.
+
+ void adjustEnterAndLeaveFrameTrapsState(JSContext* cx, Instance* instance,
+ bool enabled);
+ void ensureEnterFrameTrapsState(JSContext* cx, Instance* instance,
+ bool enabled);
+ bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; }
+
+ // When the Code is debugEnabled, individual breakpoints can be enabled or
+ // disabled at instruction offsets.
+
+ bool hasBreakpointTrapAtOffset(uint32_t offset);
+ void toggleBreakpointTrap(JSRuntime* rt, Instance* instance, uint32_t offset,
+ bool enabled);
+ WasmBreakpointSite* getBreakpointSite(uint32_t offset) const;
+ WasmBreakpointSite* getOrCreateBreakpointSite(JSContext* cx,
+ Instance* instance,
+ uint32_t offset);
+ bool hasBreakpointSite(uint32_t offset);
+ void destroyBreakpointSite(JS::GCContext* gcx, Instance* instance,
+ uint32_t offset);
+ void clearBreakpointsIn(JS::GCContext* gcx, WasmInstanceObject* instance,
+ js::Debugger* dbg, JSObject* handler);
+
+ // When the Code is debug-enabled, single-stepping mode can be toggled on
+ // the granularity of individual functions.
+
+ bool stepModeEnabled(uint32_t funcIndex) const;
+ [[nodiscard]] bool incrementStepperCount(JSContext* cx, Instance* instance,
+ uint32_t funcIndex);
+ void decrementStepperCount(JS::GCContext* gcx, Instance* instance,
+ uint32_t funcIndex);
+
+ // Stack inspection helpers.
+
+ [[nodiscard]] bool debugGetLocalTypes(uint32_t funcIndex,
+ ValTypeVector* locals,
+ size_t* argsLength,
+ StackResults* stackResults);
+ [[nodiscard]] bool getGlobal(Instance& instance, uint32_t globalIndex,
+ MutableHandleValue vp);
+
+ // Debug URL helpers.
+
+ [[nodiscard]] bool getSourceMappingURL(JSContext* cx,
+ MutableHandleString result) const;
+
+ // Accessors for commonly used elements of linked structures.
+
+ const MetadataTier& metadata(Tier t) const { return code_->metadata(t); }
+ const Metadata& metadata() const { return code_->metadata(); }
+ const CodeRangeVector& codeRanges(Tier t) const {
+ return metadata(t).codeRanges;
+ }
+ const CallSiteVector& callSites(Tier t) const {
+ return metadata(t).callSites;
+ }
+
+ uint32_t funcToCodeRangeIndex(uint32_t funcIndex) const {
+ return metadata(Tier::Debug).funcToCodeRange[funcIndex];
+ }
+
+ // about:memory reporting:
+
+ void addSizeOfMisc(MallocSizeOf mallocSizeOf, Metadata::SeenSet* seenMetadata,
+ Code::SeenSet* seenCode, size_t* code, size_t* data) const;
+};
+
+using UniqueDebugState = UniquePtr<DebugState>;
+
+} // namespace wasm
+} // namespace js
+
+#endif // wasm_debug_h