/src/hermes/lib/VM/JSCallSite.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #include "hermes/VM/JSCallSite.h" |
9 | | |
10 | | #include "hermes/BCGen/HBC/DebugInfo.h" |
11 | | #include "hermes/Support/OptValue.h" |
12 | | #include "hermes/VM/Callable.h" |
13 | | #include "hermes/VM/RuntimeModule-inline.h" |
14 | | |
15 | | namespace hermes { |
16 | | namespace vm { |
17 | | const ObjectVTable JSCallSite::vt{ |
18 | | VTable( |
19 | | CellKind::JSCallSiteKind, |
20 | | cellSize<JSCallSite>(), |
21 | | nullptr, |
22 | | nullptr, |
23 | | nullptr), |
24 | | JSCallSite::_getOwnIndexedRangeImpl, |
25 | | JSCallSite::_haveOwnIndexedImpl, |
26 | | JSCallSite::_getOwnIndexedPropertyFlagsImpl, |
27 | | JSCallSite::_getOwnIndexedImpl, |
28 | | JSCallSite::_setOwnIndexedImpl, |
29 | | JSCallSite::_deleteOwnIndexedImpl, |
30 | | JSCallSite::_checkAllOwnIndexedImpl, |
31 | | }; |
32 | | |
33 | 1 | void JSCallSiteBuildMeta(const GCCell *cell, Metadata::Builder &mb) { |
34 | 1 | mb.addJSObjectOverlapSlots(JSCallSite::numOverlapSlots<JSCallSite>()); |
35 | 1 | JSObjectBuildMeta(cell, mb); |
36 | 1 | const auto *self = static_cast<const JSCallSite *>(cell); |
37 | 1 | mb.setVTable(&JSCallSite::vt); |
38 | 1 | mb.addField("error", &self->error_); |
39 | 1 | } |
40 | | |
41 | | JSCallSite::JSCallSite( |
42 | | Runtime &runtime, |
43 | | Handle<JSObject> parent, |
44 | | Handle<HiddenClass> clazz, |
45 | | Handle<JSError> error, |
46 | | size_t stackFrameIndex) |
47 | | : JSObject(runtime, *parent, *clazz), |
48 | | error_(runtime, *error, runtime.getHeap()), |
49 | 0 | stackFrameIndex_(stackFrameIndex) { |
50 | 0 | assert( |
51 | 0 | error_.getNonNull(runtime)->getStackTrace() && |
52 | 0 | "Error passed to CallSite must have a stack trace"); |
53 | 0 | assert( |
54 | 0 | stackFrameIndex < error_.getNonNull(runtime)->getStackTrace()->size() && |
55 | 0 | "Stack frame index out of bounds"); |
56 | 0 | } |
57 | | |
58 | | CallResult<HermesValue> JSCallSite::create( |
59 | | Runtime &runtime, |
60 | | Handle<JSError> errorHandle, |
61 | 0 | uint32_t stackFrameIndex) { |
62 | 0 | auto jsCallSiteProto = Handle<JSObject>::vmcast(&runtime.callSitePrototype); |
63 | |
|
64 | 0 | auto *jsCallSite = runtime.makeAFixed<JSCallSite>( |
65 | 0 | runtime, |
66 | 0 | jsCallSiteProto, |
67 | 0 | runtime.getHiddenClassForPrototype( |
68 | 0 | *jsCallSiteProto, numOverlapSlots<JSCallSite>()), |
69 | 0 | errorHandle, |
70 | 0 | stackFrameIndex); |
71 | |
|
72 | 0 | return JSObjectInit::initToHermesValue(runtime, jsCallSite); |
73 | 0 | } |
74 | | |
75 | | CallResult<HermesValue> JSCallSite::getFunctionName( |
76 | | Runtime &runtime, |
77 | 0 | Handle<JSCallSite> selfHandle) { |
78 | 0 | Handle<JSError> error = runtime.makeHandle(selfHandle->error_); |
79 | |
|
80 | 0 | auto functionName = JSError::getFunctionNameAtIndex( |
81 | 0 | runtime, error, selfHandle->stackFrameIndex_); |
82 | 0 | return functionName ? functionName.getHermesValue() |
83 | 0 | : HermesValue::encodeNullValue(); |
84 | 0 | } |
85 | | |
86 | | CallResult<HermesValue> JSCallSite::getFileName( |
87 | | Runtime &runtime, |
88 | 0 | Handle<JSCallSite> selfHandle) { |
89 | 0 | const StackTraceInfo *sti = getStackTraceInfo(runtime, selfHandle); |
90 | 0 | if (sti->codeBlock) { |
91 | 0 | OptValue<hbc::DebugSourceLocation> location = |
92 | 0 | JSError::getDebugInfo(sti->codeBlock, sti->bytecodeOffset); |
93 | |
|
94 | 0 | RuntimeModule *runtimeModule = sti->codeBlock->getRuntimeModule(); |
95 | 0 | auto makeUTF8Ref = [](llvh::StringRef ref) { |
96 | 0 | const uint8_t *utf8 = reinterpret_cast<const uint8_t *>(ref.data()); |
97 | 0 | return llvh::makeArrayRef(utf8, ref.size()); |
98 | 0 | }; |
99 | |
|
100 | 0 | if (location) { |
101 | 0 | auto debugInfo = runtimeModule->getBytecode()->getDebugInfo(); |
102 | |
|
103 | 0 | std::string utf8Storage; |
104 | 0 | llvh::StringRef fileName = hbc::getStringFromEntry( |
105 | 0 | debugInfo->getFilenameTable()[location->filenameId], |
106 | 0 | debugInfo->getFilenameStorage(), |
107 | 0 | utf8Storage); |
108 | 0 | return StringPrimitive::createEfficient(runtime, makeUTF8Ref(fileName)); |
109 | 0 | } else { |
110 | 0 | llvh::StringRef sourceURL = runtimeModule->getSourceURL(); |
111 | 0 | if (!sourceURL.empty()) { |
112 | 0 | return StringPrimitive::createEfficient( |
113 | 0 | runtime, makeUTF8Ref(sourceURL)); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | } |
117 | 0 | return HermesValue::encodeNullValue(); |
118 | 0 | } |
119 | | |
120 | | CallResult<HermesValue> JSCallSite::getLineNumber( |
121 | | Runtime &runtime, |
122 | 0 | Handle<JSCallSite> selfHandle) { |
123 | 0 | const StackTraceInfo *sti = getStackTraceInfo(runtime, selfHandle); |
124 | 0 | if (sti->codeBlock) { |
125 | 0 | OptValue<hbc::DebugSourceLocation> location = |
126 | 0 | JSError::getDebugInfo(sti->codeBlock, sti->bytecodeOffset); |
127 | 0 | if (location) { |
128 | 0 | return HermesValue::encodeNumberValue(location->line); |
129 | 0 | } else { |
130 | | // Add 1 to the CJSModuleOffset to account for 1-based indexing of |
131 | | // symbolication tools. |
132 | 0 | return HermesValue::encodeNumberValue( |
133 | 0 | sti->codeBlock->getRuntimeModule()->getBytecode()->getSegmentID() + |
134 | 0 | 1); |
135 | 0 | } |
136 | 0 | } |
137 | 0 | return HermesValue::encodeNullValue(); |
138 | 0 | } |
139 | | |
140 | | CallResult<HermesValue> JSCallSite::getColumnNumber( |
141 | | Runtime &runtime, |
142 | 0 | Handle<JSCallSite> selfHandle) { |
143 | 0 | const StackTraceInfo *sti = getStackTraceInfo(runtime, selfHandle); |
144 | 0 | if (sti->codeBlock) { |
145 | 0 | OptValue<hbc::DebugSourceLocation> location = |
146 | 0 | JSError::getDebugInfo(sti->codeBlock, sti->bytecodeOffset); |
147 | 0 | if (location) { |
148 | 0 | return HermesValue::encodeNumberValue(location->column); |
149 | 0 | } |
150 | 0 | } |
151 | 0 | return HermesValue::encodeNullValue(); |
152 | 0 | } |
153 | | |
154 | | CallResult<HermesValue> JSCallSite::getBytecodeAddress( |
155 | | Runtime &runtime, |
156 | 0 | Handle<JSCallSite> selfHandle) { |
157 | 0 | const StackTraceInfo *sti = getStackTraceInfo(runtime, selfHandle); |
158 | 0 | if (sti->codeBlock) { |
159 | 0 | return HermesValue::encodeNumberValue( |
160 | 0 | sti->bytecodeOffset + sti->codeBlock->getVirtualOffset()); |
161 | 0 | } |
162 | 0 | return HermesValue::encodeNullValue(); |
163 | 0 | } |
164 | | |
165 | | CallResult<HermesValue> JSCallSite::isNative( |
166 | | Runtime &runtime, |
167 | 0 | Handle<JSCallSite> selfHandle) { |
168 | 0 | const StackTraceInfo *sti = getStackTraceInfo(runtime, selfHandle); |
169 | 0 | return HermesValue::encodeBoolValue(!sti->codeBlock); |
170 | 0 | } |
171 | | |
172 | | CallResult<HermesValue> JSCallSite::getThis( |
173 | | Runtime &runtime, |
174 | 0 | Handle<JSCallSite> selfHandle) { |
175 | 0 | return HermesValue::encodeUndefinedValue(); |
176 | 0 | } |
177 | | |
178 | | CallResult<HermesValue> JSCallSite::getTypeName( |
179 | | Runtime &runtime, |
180 | 0 | Handle<JSCallSite> selfHandle) { |
181 | 0 | return HermesValue::encodeNullValue(); |
182 | 0 | } |
183 | | |
184 | | CallResult<HermesValue> JSCallSite::getFunction( |
185 | | Runtime &runtime, |
186 | 0 | Handle<JSCallSite> selfHandle) { |
187 | 0 | return HermesValue::encodeUndefinedValue(); |
188 | 0 | } |
189 | | |
190 | | CallResult<HermesValue> JSCallSite::getMethodName( |
191 | | Runtime &runtime, |
192 | 0 | Handle<JSCallSite> selfHandle) { |
193 | 0 | return HermesValue::encodeNullValue(); |
194 | 0 | } |
195 | | |
196 | | CallResult<HermesValue> JSCallSite::getEvalOrigin( |
197 | | Runtime &runtime, |
198 | 0 | Handle<JSCallSite> selfHandle) { |
199 | 0 | return HermesValue::encodeNullValue(); |
200 | 0 | } |
201 | | |
202 | | CallResult<HermesValue> JSCallSite::isToplevel( |
203 | | Runtime &runtime, |
204 | 0 | Handle<JSCallSite> selfHandle) { |
205 | 0 | return HermesValue::encodeNullValue(); |
206 | 0 | } |
207 | | |
208 | | CallResult<HermesValue> JSCallSite::isEval( |
209 | | Runtime &runtime, |
210 | 0 | Handle<JSCallSite> selfHandle) { |
211 | 0 | return HermesValue::encodeNullValue(); |
212 | 0 | } |
213 | | |
214 | | CallResult<HermesValue> JSCallSite::isConstructor( |
215 | | Runtime &runtime, |
216 | 0 | Handle<JSCallSite> selfHandle) { |
217 | 0 | return HermesValue::encodeNullValue(); |
218 | 0 | } |
219 | | |
220 | | CallResult<HermesValue> JSCallSite::isAsync( |
221 | | Runtime &runtime, |
222 | 0 | Handle<JSCallSite> selfHandle) { |
223 | 0 | return HermesValue::encodeBoolValue(false); |
224 | 0 | } |
225 | | |
226 | | CallResult<HermesValue> JSCallSite::isPromiseAll( |
227 | | Runtime &runtime, |
228 | 0 | Handle<JSCallSite> selfHandle) { |
229 | 0 | return HermesValue::encodeBoolValue(false); |
230 | 0 | } |
231 | | |
232 | | CallResult<HermesValue> JSCallSite::getPromiseIndex( |
233 | | Runtime &runtime, |
234 | 0 | Handle<JSCallSite> selfHandle) { |
235 | 0 | return HermesValue::encodeNullValue(); |
236 | 0 | } |
237 | | |
238 | | const StackTraceInfo *JSCallSite::getStackTraceInfo( |
239 | | Runtime &runtime, |
240 | 0 | Handle<JSCallSite> selfHandle) { |
241 | 0 | JSError *error = selfHandle->error_.getNonNull(runtime); |
242 | 0 | const StackTrace *stacktrace = error->getStackTrace(); |
243 | 0 | assert( |
244 | 0 | stacktrace && |
245 | 0 | "The Error associated with this CallSite has already released its " |
246 | 0 | "stack trace vector"); |
247 | | // Returning a pointer to stacktrace elements is safe because: |
248 | | // 1. stacktrace's ownership is managed (indirectly) by selfHandle (i.e., |
249 | | // the CallSite object); and |
250 | | // 2. stacktrace is not modified after it is created. |
251 | 0 | return &stacktrace->at(selfHandle->stackFrameIndex_); |
252 | 0 | } |
253 | | |
254 | | } // namespace vm |
255 | | } // namespace hermes |