Skip to content
File

Blob: src/workerd/jsg/observer.h

cpp181 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/util/strong-bool.h>
8 
9#include <v8-local-handle.h>
10 
11#include <kj/common.h>
12#include <kj/exception.h>
13#include <kj/string.h>
14 
15// Forward declare v8::Isolate here, this allows us to avoid including the V8 header and compile
16// some targets without depending on V8.
17namespace v8 {
18class Isolate;
19}
20 
21namespace workerd::jsg {
22 
23class Url;
24 
25struct ResolveObserver {
26 virtual ~ResolveObserver() noexcept(false) {}
27 
28 // Identifies the context in which a module resolution is being performed.
29 enum class Context {
30 // The resolve is being performed by a worker bundle module
31 // (that is, a worker script is calling import or require).
32 BUNDLE,
33 // The resolve is being performed by a builtin module
34 // (that is, one of the modules built into the worker runtime).
35 BUILTIN,
36 // Like builtin, but it's a module that is *only* resolvable from a builtin
37 // (like the `node-internal:...` modules)
38 BUILTIN_ONLY,
39 // Resolves only user-importable built-in modules (the kBuiltin bundle),
40 // excluding both worker bundle modules and internal-only modules. Used
41 // by user-facing APIs like process.getBuiltinModule() that must not
42 // expose internal modules or return user bundle overrides.
43 PUBLIC_BUILTIN,
44 };
45 
46 enum class Source {
47 // The resolve originated from a static import statement.
48 STATIC_IMPORT,
49 // The resolve originated from a dynamic import statement.
50 DYNAMIC_IMPORT,
51 // The resolve originated from a CommonJS require() call.
52 REQUIRE,
53 // The resolve originated from an internal direct call to
54 // the ModuleRegistry.
55 INTERNAL,
56 };
57 
58 // Used to report the status of a module resolution.
59 class ResolveStatus {
60 public:
61 ResolveStatus() = default;
62 KJ_DISALLOW_COPY_AND_MOVE(ResolveStatus);
63 virtual ~ResolveStatus() noexcept(false) {}
64 
65 // Indicates that the module resolution was successful and a
66 // matching module was found in the registry.
67 virtual void found() {}
68 
69 // Indicates that the module resolution failed because no matching
70 // module was found in the registry.
71 virtual void notFound() {}
72 
73 // Indicates that the module resolution failed because an error
74 // occurred.
75 virtual void exception(kj::Exception&& exception) {}
76 };
77 
78 // Called when a module is being resolved. The returned ResolveStatus
79 // object will be used to report the result of the resolution.
80 // It is guaranteed that isolate lock is not held during invocation.
81 virtual kj::Own<ResolveStatus> onResolveModule(
82 const Url& specifier, Context context, Source source) const {
83 static ResolveStatus nonopStatus;
84 return {&nonopStatus, kj::NullDisposer::instance};
85 }
86 
87 // Called when a module is being resolved. The returned ResolveStatus
88 // object will be used to report the result of the resolution.
89 // It is guaranteed that isolate lock is not held during invocation.
90 virtual kj::Own<ResolveStatus> onResolveModule(
91 kj::StringPtr specifier, Context context, Source source) const {
92 static ResolveStatus nonopStatus;
93 return {&nonopStatus, kj::NullDisposer::instance};
94 }
95};
96 
97struct CompilationObserver {
98 virtual ~CompilationObserver() noexcept(false) {}
99 
100 // see ModuleInfoCompileOption
101 enum class Option { BUNDLE, BUILTIN };
102 
103 // Monitors behavior of compilation processes.
104 
105 // Called at the start of ESM compilation.
106 // Returned value will be destroyed when module compilation finishes.
107 // It is guaranteed that isolate lock is held during invocation.
108 virtual kj::Own<void> onEsmCompilationStart(
109 v8::Isolate* isolate, kj::StringPtr name, Option option) const {
110 return kj::Own<void>();
111 }
112 
113 // Called at the start of Script (e.g. non-ESM) compilation.
114 // Returned value will be destroyed when module compilation finishes.
115 // It is guaranteed that isolate lock is held during invocation.
116 virtual kj::Own<void> onScriptCompilationStart(
117 v8::Isolate* isolate, kj::Maybe<kj::StringPtr> name = kj::none) const {
118 return kj::Own<void>();
119 }
120 
121 // Called at the start of wasm compilation.
122 // Returned value will be destroyed when module compilation finishes.
123 // It is guaranteed that isolate lock is held during invocation.
124 virtual kj::Own<void> onWasmCompilationStart(v8::Isolate* isolate, size_t codeSize) const {
125 return kj::Own<void>();
126 }
127 
128 // Variation that is called at the start of wasm compilation from cache.
129 // Returned value will be destroyed when module compilation finishes.
130 // It is guaranteed that isolate lock is held during invocation.
131 virtual kj::Own<void> onWasmCompilationFromCacheStart(v8::Isolate* isolate) const {
132 return kj::Own<void>();
133 }
134 
135 // Called at the start of json module parsing.
136 // Returned value will be destroyed when parsing completes.
137 // It is guaranteed that isolate lock is held during invocation.
138 virtual kj::Own<void> onJsonCompilationStart(v8::Isolate* isolate, size_t inputSize) const {
139 return kj::Own<void>();
140 }
141 
142 virtual void onCompileCacheFound(v8::Isolate* isolate) const {}
143 virtual void onCompileCacheRejected(v8::Isolate* isolate) const {}
144 virtual void onCompileCacheGenerated(v8::Isolate* isolate) const {}
145 virtual void onCompileCacheGenerationFailed(v8::Isolate* isolate) const {}
146};
147 
148struct InternalExceptionObserver {
149 virtual ~InternalExceptionObserver() noexcept(false) {}
150 
151 struct Detail {
152 bool isInternal;
153 bool isFromRemote;
154 bool isDurableObjectReset;
155 using InternalErrorId = kj::FixedArray<char, 24>;
156 kj::Maybe<InternalErrorId> internalErrorId;
157 };
158 
159 // Called when an internal exception is created (see exceptionToJs).
160 // Used to collect metrics on various internal error conditions.
161 virtual void reportInternalException(const kj::Exception&, Detail detail) {}
162};
163 
164WD_STRONG_BOOL(IsCodeLike);
165 
166struct IsolateObserver: public CompilationObserver,
167 public InternalExceptionObserver,
168 public ResolveObserver {
169 virtual ~IsolateObserver() noexcept(false) {}
170 
171 // Called when eval(), new Function(), or similar dynamic code generation
172 // is performed. Note that the source here may not be a string if isCodeLike
173 // is YES.
174 virtual void onDynamicEval(
175 v8::Local<v8::Context> context, v8::Local<v8::Value> source, IsCodeLike isCodeLike) {
176 // Default is to do nothing.
177 }
178};
179 
180} // namespace workerd::jsg