aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/CallSite.cpp
blob: 48fe82275db3ce4d24f2f0d73e21aeecf7eff752 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
 * This source code is licensed under the terms found in the LICENSE file in
 * node-jsc's root directory.
 */

#include "config.h"
#include "CallSite.h"

#include "helpers.h"

#include <JavaScriptCore/JSCInlines.h>

using namespace JSC;
using namespace WebCore;

namespace Zig {

const JSC::ClassInfo CallSite::s_info = { "CallSite"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(CallSite) };

void CallSite::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSCStackFrame& stackFrame, bool encounteredStrictFrame)
{
    Base::finishCreation(vm);

    /* From v8's "Stack Trace API" (https://github.com/v8/v8/wiki/Stack-Trace-API):
     * "To maintain restrictions imposed on strict mode functions, frames that have a
     * strict mode function and all frames below (its caller etc.) are not allow to access
     * their receiver and function objects. For those frames, getFunction() and getThis()
     * will return undefined.".
     * Thus, if we've already encountered a strict frame, we'll treat our frame as strict too. */

    bool isStrictFrame = encounteredStrictFrame;
    if (!isStrictFrame) {
        JSC::CodeBlock* codeBlock = stackFrame.codeBlock();
        if (codeBlock) {
            isStrictFrame = codeBlock->ownerExecutable()->isInStrictContext();
        }
    }

    JSC::JSObject* calleeObject = JSC::jsCast<JSC::JSObject*>(stackFrame.callee());

    // Initialize "this" and "function" (and set the "IsStrict" flag if needed)
    JSC::CallFrame* callFrame = stackFrame.callFrame();
    if (isStrictFrame) {
        m_thisValue.set(vm, this, JSC::jsUndefined());
        m_function.set(vm, this, JSC::jsUndefined());
        m_flags |= static_cast<unsigned int>(Flags::IsStrict);
    } else {
        if (callFrame) {
            // We know that we're not in strict mode
            m_thisValue.set(vm, this, callFrame->thisValue().toThis(globalObject, JSC::ECMAMode::sloppy()));
        } else {
            m_thisValue.set(vm, this, JSC::jsUndefined());
        }

        m_function.set(vm, this, stackFrame.callee());
    }

    m_functionName.set(vm, this, stackFrame.functionName());
    m_sourceURL.set(vm, this, stackFrame.sourceURL());

    const auto* sourcePositions = stackFrame.getSourcePositions();
    if (sourcePositions) {
        m_lineNumber = JSC::jsNumber(sourcePositions->line.oneBasedInt());
        m_columnNumber = JSC::jsNumber(sourcePositions->startColumn.oneBasedInt());
    }

    if (stackFrame.isEval()) {
        m_flags |= static_cast<unsigned int>(Flags::IsEval);
    }
    if (stackFrame.isConstructor()) {
        m_flags |= static_cast<unsigned int>(Flags::IsConstructor);
    }
    if (!stackFrame.codeBlock()) {
        m_flags |= static_cast<unsigned int>(Flags::IsNative);
    }
}

template<typename Visitor>
void CallSite::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
    CallSite* thisCallSite = jsCast<CallSite*>(cell);
    Base::visitChildren(thisCallSite, visitor);
    visitor.append(thisCallSite->m_thisValue);
    visitor.append(thisCallSite->m_function);
    visitor.append(thisCallSite->m_functionName);
    visitor.append(thisCallSite->m_sourceURL);
}

void CallSite::formatAsString(JSC::VM& vm, JSC::JSGlobalObject* globalObject, WTF::StringBuilder& sb)
{
    JSString* myTypeName = jsTypeStringForValue(globalObject, thisValue());
    JSString* myFunction = functionName().toString(globalObject);
    JSString* myFunctionName = functionName().toString(globalObject);
    JSString* mySourceURL = sourceURL().toString(globalObject);

    JSString* myColumnNumber = columnNumber().toInt32(globalObject) != -1 ? columnNumber().toString(globalObject) : jsEmptyString(vm);
    JSString* myLineNumber = lineNumber().toInt32(globalObject) != -1 ? lineNumber().toString(globalObject) : jsEmptyString(vm);

    bool myIsConstructor = isConstructor();

    if (myFunctionName->length() > 0) {
        if (myIsConstructor) {
            sb.append("new "_s);
        } else {
            // TODO: print type or class name if available
            // sb.append(myTypeName->getString(globalObject));
            // sb.append(" "_s);
        }
        sb.append(myFunctionName->getString(globalObject));
    } else {
        sb.append("<anonymous>"_s);
    }
    sb.append(" ("_s);
    if (isNative()) {
        sb.append("native"_s);
    } else {
        sb.append(mySourceURL->getString(globalObject));
        sb.append(":"_s);
        sb.append(myLineNumber->getString(globalObject));
        sb.append(":"_s);
        sb.append(myColumnNumber->getString(globalObject));
    }
    sb.append(")"_s);
}

DEFINE_VISIT_CHILDREN(CallSite);

}