Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: fix context inspection for V8 6.8 #201

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/llv8-constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ void ScopeInfo::Load() {


void Context::Load() {
kClosureIndex =
LoadConstant("class_Context__closure_index__int", "context_idx_closure");
kClosureIndex = LoadConstant("class_Context__closure_index__int",
"context_idx_closure", -1);
kScopeInfoIndex = LoadConstant("context_idx_scope_info", -1);
kPreviousIndex =
LoadConstant("class_Context__previous_index__int", "context_idx_prev");
// TODO (mmarchini) change LoadConstant to accept variable arguments, a list
Expand Down Expand Up @@ -486,6 +487,9 @@ void Types::Load() {
kFirstJSObjectType =
LoadConstant("type_JSGlobalObject__JS_GLOBAL_OBJECT_TYPE");

kFirstContextType = LoadConstant("FirstContextType");
kLastContextType = LoadConstant("LastContextType");

kHeapNumberType = LoadConstant("type_HeapNumber__HEAP_NUMBER_TYPE");
kMapType = LoadConstant("type_Map__MAP_TYPE");
kGlobalObjectType =
Expand All @@ -507,6 +511,7 @@ void Types::Load() {
kSharedFunctionInfoType =
LoadConstant("type_SharedFunctionInfo__SHARED_FUNCTION_INFO_TYPE");
kScriptType = LoadConstant("type_Script__SCRIPT_TYPE");
kScopeInfoType = LoadConstant("type_ScopeInfo__SCOPE_INFO_TYPE");

if (kJSAPIObjectType == -1) {
common_->Load();
Expand Down
14 changes: 14 additions & 0 deletions src/llv8-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,22 @@ class Context : public Module {
CONSTANTS_DEFAULT_METHODS(Context);

int64_t kClosureIndex;
int64_t kScopeInfoIndex;
int64_t kGlobalObjectIndex;
int64_t kPreviousIndex;
int64_t kNativeIndex;
int64_t kEmbedderDataIndex;
int64_t kMinContextSlots;

inline bool hasClosure() {
// NOTE (mmarchini): V8 6.8 replaced the closure field (which was a
// JSFunction) with a scope_info field (which is a ScopeInfo). The change
// made it easier to get the scope info for a context, but removed our
// ability to get the outer function for a given context. We can still get
// the outer context through the previous field though.
return kClosureIndex != -1;
}

protected:
void Load();
};
Expand Down Expand Up @@ -465,6 +475,9 @@ class Types : public Module {
int64_t kFirstNonstringType;
int64_t kFirstJSObjectType;

int64_t kFirstContextType;
int64_t kLastContextType;

int64_t kHeapNumberType;
int64_t kMapType;
int64_t kGlobalObjectType;
Expand All @@ -483,6 +496,7 @@ class Types : public Module {
int64_t kJSDateType;
int64_t kSharedFunctionInfoType;
int64_t kScriptType;
int64_t kScopeInfoType;

protected:
void Load();
Expand Down
87 changes: 64 additions & 23 deletions src/llv8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,15 @@ std::string JSFunction::Inspect(InspectOptions* options, Error& err) {
snprintf(tmp, sizeof(tmp), "\n context=0x%016" PRIx64, context.raw());
res += tmp;

std::string context_str = context.Inspect(err);
if (err.Fail()) return std::string();
{
InspectOptions ctx_options;
ctx_options.detailed = true;
ctx_options.indent_depth = options->indent_depth + 1;
std::string context_str = context.Inspect(&ctx_options, err);
if (err.Fail()) return std::string();

if (!context_str.empty()) res += "{\n" + context_str + "}";
if (!context_str.empty()) res += ":" + context_str;
}

if (options->print_source) {
SharedFunctionInfo info = Info(err);
Expand Down Expand Up @@ -821,6 +826,12 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) {
return pre + str.Inspect(options, err);
}

if (type >= v8()->types()->kFirstContextType &&
type <= v8()->types()->kLastContextType) {
Context ctx(this);
return pre + ctx.Inspect(options, err);
}

if (type == v8()->types()->kFixedArrayType) {
FixedArray arr(this);
return pre + arr.Inspect(options, err);
Expand Down Expand Up @@ -1047,24 +1058,37 @@ std::string FixedArray::InspectContents(int length, Error& err) {
return res;
}

HeapObject Context::GetScopeInfo(Error& err) {
if (v8()->context()->kScopeInfoIndex != -1) {
return FixedArray::Get<HeapObject>(v8()->context()->kScopeInfoIndex, err);
}
JSFunction closure = Closure(err);
if (err.Fail()) return HeapObject();

std::string Context::Inspect(Error& err) {
std::string res;
SharedFunctionInfo info = closure.Info(err);
if (err.Fail()) return HeapObject();

return info.GetScopeInfo(err);
}

std::string Context::Inspect(InspectOptions* options, Error& err) {
// Not enough postmortem information, return bare minimum
if (v8()->shared_info()->kScopeInfoOffset == -1 &&
v8()->shared_info()->kNameOrScopeInfoOffset == -1)
return res;
return std::string();

Value previous = Previous(err);
if (err.Fail()) return std::string();
std::string res = "<Context";

JSFunction closure = Closure(err);
if (err.Fail()) return std::string();
if (!options->detailed) {
return res + ">";
}

SharedFunctionInfo info = closure.Info(err);
res += ": {\n";

Value previous = Previous(err);
if (err.Fail()) return std::string();

HeapObject scope_obj = info.GetScopeInfo(err);
HeapObject scope_obj = GetScopeInfo(err);
if (err.Fail()) return std::string();

ScopeInfo scope(scope_obj);
Expand All @@ -1076,25 +1100,41 @@ std::string Context::Inspect(Error& err) {
Smi local_count_smi = scope.ContextLocalCount(err);
if (err.Fail()) return std::string();

InspectOptions options;

HeapObject heap_previous = HeapObject(previous);
if (heap_previous.Check()) {
char tmp[128];
snprintf(tmp, sizeof(tmp), " (previous)=0x%016" PRIx64, previous.raw());
res += tmp;
snprintf(tmp, sizeof(tmp), (options->get_indent_spaces() + "(previous)=0x%016" PRIx64).c_str(), previous.raw());
res += std::string(tmp) + ":<Context>,";
}

if (!res.empty()) res += "\n";
{

if (v8()->context()->hasClosure()) {
JSFunction closure = Closure(err);
if (err.Fail()) return std::string();
char tmp[128];
snprintf(tmp, sizeof(tmp), " (closure)=0x%016" PRIx64 " {",
snprintf(tmp, sizeof(tmp), (options->get_indent_spaces() + "(closure)=0x%016" PRIx64 " {").c_str(),
closure.raw());
res += tmp;

InspectOptions options;
res += closure.Inspect(&options, err) + "}";
InspectOptions closure_options;
res += closure.Inspect(&closure_options, err) + "}";
if (err.Fail()) return std::string();
} else {
char tmp[128];
snprintf(tmp, sizeof(tmp), (options->get_indent_spaces() + "(scope_info)=0x%016" PRIx64).c_str(),
scope.raw());

res += std::string(tmp) + ":<ScopeInfo";

Error function_name_error;
HeapObject maybe_function_name = scope.MaybeFunctionName(function_name_error);

if (function_name_error.Success()) {
res += ": for function " + String(maybe_function_name).ToString(err);
}

res += ">";
}

int param_count = param_count_smi.GetValue();
Expand All @@ -1106,17 +1146,18 @@ std::string Context::Inspect(Error& err) {

if (!res.empty()) res += ",\n";

res += " " + name.ToString(err) + "=";
res += options->get_indent_spaces() + name.ToString(err) + "=";
if (err.Fail()) return std::string();

Value value = ContextSlot(i, err);
if (err.Fail()) return std::string();

res += value.Inspect(&options, err);
InspectOptions val_options;
res += value.Inspect(&val_options, err);
if (err.Fail()) return std::string();
}

return res;
return res + "}>";
}


Expand Down
15 changes: 12 additions & 3 deletions src/llv8.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,20 @@ class Value {
: detailed(false),
print_map(false),
print_source(false),
length(kLength) {}
length(kLength),
indent_depth(1) {}

static const unsigned int kLength = 16;
static const unsigned int kIndentSize = 2;
inline std::string get_indent_spaces() {
return std::string(indent_depth * kIndentSize, ' ');
}

bool detailed;
bool print_map;
bool print_source;
unsigned int length;
unsigned int indent_depth;
};

Value(const Value& v) = default;
Expand Down Expand Up @@ -382,15 +388,18 @@ class Context : public FixedArray {
public:
V8_VALUE_DEFAULT_METHODS(Context, FixedArray)

inline JSFunction Closure(Error& err);
inline HeapObject GetScopeInfo(Error& err);
inline Value Previous(Error& err);
inline Value Native(Error& err);
inline bool IsNative(Error& err);
template <class T>
inline T GetEmbedderData(int64_t index, Error& err);
inline Value ContextSlot(int index, Error& err);

std::string Inspect(Error& err);
std::string Inspect(InspectOptions *options, Error& err);

private:
inline JSFunction Closure(Error& err);
};

class ScopeInfo : public FixedArray {
Expand Down
16 changes: 12 additions & 4 deletions test/plugin/inspect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const hashMapTests = {
const arrowSource = 'source:\n' +
'function c.hashmap.(anonymous function)(a,b)=>{a+b}\n' +
'>';

t.ok(lines.includes(arrowSource),
'hashmap[25] should have the correct function source');
cb(null);
Expand Down Expand Up @@ -305,14 +305,22 @@ const hashMapTests = {

const contextTests = {
'previous': {
re: /\(previous\)/,
re: /\(previous\)=(0x[0-9a-f]+)[^\n]+/,
desc: '.(previous)'
},
'closure': {
re: /\(closure\)=(0x[0-9a-f]+)[^\n]+function: closure/i,
re: /(\((?:closure|scope_info)\)=0x[0-9a-f]+)[^\n]+/i,
desc: '.(closure)',
validator(t, sess, addresses, name, cb) {
const address = addresses[name];
const type = addresses[name].split("=")[0];
let address = undefined;
if (type === "(closure)") {
address = addresses[name].split("=")[1];
} else if (type === "(scope_info)") {
address = addresses["previous"];
} else {
return cb(new Error("unknown field"));
}
sess.send(`v8 inspect ${address}`);
sess.linesUntil(/}>/, (err, lines) => {
if (err) return cb(err);
Expand Down