Coverage Report

Created: 2023-02-22 06:51

/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