0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00
This commit is contained in:
Marvin Hagemeister 2025-01-06 19:04:42 +01:00
parent 8fc684c126
commit 2da8eee932
4 changed files with 147 additions and 153 deletions

View file

@ -25,6 +25,10 @@ const AST_GROUP_TYPE = 1;
/// <next idx u32> /// <next idx u32>
/// <parent idx u32> /// <parent idx u32>
const NODE_SIZE = 1 + 4 + 4 + 4 + 4; const NODE_SIZE = 1 + 4 + 4 + 4 + 4;
const PROP_OFFSET = 1;
const CHILD_OFFSET = 1 + 4;
const NEXT_OFFSET = 1 + 4 + 4;
const PARENT_OFFSET = 1 + 4 + 4 + 4;
// Span size in buffer: u32 + u32 // Span size in buffer: u32 + u32
const SPAN_SIZE = 4 + 4; const SPAN_SIZE = 4 + 4;
@ -285,16 +289,16 @@ export function installPlugin(plugin, exclude) {
/** /**
* @param {AstContext} ctx * @param {AstContext} ctx
* @param {number} idx * @param {number} idx
* @returns * @returns {FacadeNode | null}
*/ */
function getNode(ctx, idx) { function getNode(ctx, idx) {
if (idx === AST_IDX_INVALID) return null; if (idx === AST_IDX_INVALID) return null;
const cached = ctx.nodes.get(idx); const cached = ctx.nodes.get(idx);
if (cached !== undefined) return cached; if (cached !== undefined) return /** @type {*} */ (cached);
const node = new FacadeNode(ctx, idx); const node = new FacadeNode(ctx, idx);
ctx.nodes.set(idx, /** @type {*} */ (cached)); ctx.nodes.set(idx, /** @type {*} */ (node));
return node; return /** @type {*} */ (node);
} }
/** /**
@ -482,6 +486,15 @@ function toJsValue(ctx, idx) {
return node; return node;
} }
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readType(buf, idx) {
return buf[idx * NODE_SIZE];
}
/** /**
* @param {AstContext} ctx * @param {AstContext} ctx
* @param {number} idx * @param {number} idx
@ -501,10 +514,8 @@ function readSpan(ctx, idx) {
* @param {number} idx * @param {number} idx
* @returns {number} * @returns {number}
*/ */
function readParent(buf, idx) { function readPropOffset(buf, idx) {
let offset = idx * NODE_SIZE; const offset = (idx * NODE_SIZE) + PROP_OFFSET;
// type + prop offset + child + next
offset += 1 + 4 + 4 + 4;
return readU32(buf, offset); return readU32(buf, offset);
} }
@ -513,10 +524,27 @@ function readParent(buf, idx) {
* @param {number} idx * @param {number} idx
* @returns {number} * @returns {number}
*/ */
function readPropOffset(buf, idx) { function readChild(buf, idx) {
let offset = idx * NODE_SIZE; const offset = (idx * NODE_SIZE) * CHILD_OFFSET;
// type + prop offset + child + next return readU32(buf, offset);
offset += 1; }
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readNext(buf, idx) {
const offset = (idx * NODE_SIZE) * NEXT_OFFSET;
return readU32(buf, offset);
}
/**
* @param {AstContext["buf"]} buf
* @param {number} idx
* @returns {number}
*/
function readParent(buf, idx) {
const offset = (idx * NODE_SIZE) * PARENT_OFFSET;
return readU32(buf, offset); return readU32(buf, offset);
} }
@ -576,6 +604,7 @@ function readProperty(ctx, offset) {
const value = readU32(buf, offset); const value = readU32(buf, offset);
return getNode(ctx, value); return getNode(ctx, value);
} else if (kind === PropFlags.RefArr) { } else if (kind === PropFlags.RefArr) {
// FIXME: This is broken atm
const len = readU32(buf, offset); const len = readU32(buf, offset);
offset += 4; offset += 4;
@ -618,9 +647,8 @@ function readProperty(ctx, offset) {
function readValue(ctx, idx, search) { function readValue(ctx, idx, search) {
const { buf } = ctx; const { buf } = ctx;
const type = buf[idx * NODE_SIZE];
if (search === AST_PROP_TYPE) { if (search === AST_PROP_TYPE) {
const type = readType(buf, idx);
return getString(ctx.strTable, ctx.strByType[type]); return getString(ctx.strTable, ctx.strByType[type]);
} else if (search === AST_PROP_RANGE) { } else if (search === AST_PROP_RANGE) {
return readSpan(ctx, idx); return readSpan(ctx, idx);
@ -814,9 +842,8 @@ class MatchCtx {
* @returns {number} * @returns {number}
*/ */
getFirstChild(idx) { getFirstChild(idx) {
let offset = idx * NODE_SIZE; const siblings = this.getSiblings(idx);
offset += 1; return siblings[0] ?? -1;
return readU32(this.buf, offset);
} }
/** /**
@ -824,23 +851,8 @@ class MatchCtx {
* @returns {number} * @returns {number}
*/ */
getLastChild(idx) { getLastChild(idx) {
let offset = idx * NODE_SIZE; const siblings = this.getSiblings(idx);
offset += 1; return siblings.at(-1) ?? -1;
let childId = readU32(this.buf, offset);
if (childId <= AST_IDX_INVALID) return -1;
while (childId > AST_IDX_INVALID) {
let offset = childId * NODE_SIZE;
offset += 1 + 4;
const nextId = readU32(this.buf, offset);
if (nextId <= AST_IDX_INVALID) break;
childId = nextId;
}
return childId;
} }
/** /**
@ -848,32 +860,22 @@ class MatchCtx {
* @returns {number[]} * @returns {number[]}
*/ */
getSiblings(idx) { getSiblings(idx) {
// TODO(@marvinhagemeister): We can rewrite this to not
// use array allocation now.
const { buf } = this; const { buf } = this;
const parent = readParent(buf, idx);
let offset = idx * NODE_SIZE; // Only RefArrays have siblings
offset += 1 + 4 + 4; const parentType = readType(buf, parent);
const parentIdx = readU32(buf, offset); if (parentType !== AST_GROUP_TYPE) {
return [];
const pOffset = parentIdx * NODE_SIZE;
const pType = buf[pOffset + 1];
/** @type {number[]} */
const out = [];
if (pType !== AST_GROUP_TYPE) {
return out;
} }
let childId = readU32(buf, pOffset + 1); const child = readChild(buf, parent);
while (childId > AST_IDX_INVALID) { const out = [child];
out.push(childId);
const nextId = readU32(buf, pOffset + 1 + 4); let next = readNext(buf, child);
if (nextId <= AST_IDX_INVALID) break; while (next > AST_IDX_INVALID) {
out.push(next);
childId = nextId; next = readNext(buf, next);
} }
return out; return out;
@ -965,8 +967,6 @@ function createAstContext(buf) {
setNodeGetters(ctx); setNodeGetters(ctx);
console.log(ctx);
// DEV ONLY: Enable this to inspect the buffer message // DEV ONLY: Enable this to inspect the buffer message
_dump(ctx); _dump(ctx);
@ -1119,9 +1119,7 @@ function traverse(ctx, visitors, idx, cancellationToken) {
if (cancellationToken.isCancellationRequested()) return; if (cancellationToken.isCancellationRequested()) return;
const { buf } = ctx; const { buf } = ctx;
const nodeType = readType(ctx.buf, idx);
let offset = idx * NODE_SIZE;
const nodeType = buf[offset++];
/** @type {VisitorFn[] | null} */ /** @type {VisitorFn[] | null} */
let exits = null; let exits = null;
@ -1149,16 +1147,12 @@ function traverse(ctx, visitors, idx, cancellationToken) {
} }
try { try {
const childIdx = readU32(buf, offset); const childIdx = readChild(buf, idx);
offset += 4;
if (childIdx > AST_IDX_INVALID) { if (childIdx > AST_IDX_INVALID) {
traverse(ctx, visitors, childIdx, cancellationToken); traverse(ctx, visitors, childIdx, cancellationToken);
} }
const nextIdx = readU32(buf, offset); const nextIdx = readNext(buf, idx);
offset += 4;
if (nextIdx > AST_IDX_INVALID) { if (nextIdx > AST_IDX_INVALID) {
traverse(ctx, visitors, nextIdx, cancellationToken); traverse(ctx, visitors, nextIdx, cancellationToken);
} }
@ -1204,23 +1198,27 @@ function _dump(ctx) {
let idx = 0; let idx = 0;
while (idx < (strTableOffset / NODE_SIZE)) { while (idx < (strTableOffset / NODE_SIZE)) {
const offset = idx * NODE_SIZE; const type = readType(buf, idx);
const child = readChild(buf, idx);
const type = buf[offset]; const next = readNext(buf, idx);
const name = getString(ctx.strTable, ctx.strByType[type]);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(`${name}, idx: ${idx}, offset: ${offset}, type: ${type}`);
const parent = readParent(buf, idx); const parent = readParent(buf, idx);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` parent: ${parent}`);
const range = readSpan(ctx, idx); const range = readSpan(ctx, idx);
const name = type === AST_IDX_INVALID
? "<invalid>"
: type === AST_GROUP_TYPE
? "<group>"
: getString(ctx.strTable, ctx.strByType[type]);
// @ts-ignore dump fn // @ts-ignore dump fn
// deno-lint-ignore no-console // deno-lint-ignore no-console
console.log(` range: ${JSON.stringify(range)}`); console.log(`${name}, idx: ${idx}, type: ${type}`);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` child: ${child}, next: ${next}, parent: ${parent}`);
// @ts-ignore dump fn
// deno-lint-ignore no-console
console.log(` range: ${range[0]}, ${range[1]}`);
let propOffset = readPropOffset(buf, idx); let propOffset = readPropOffset(buf, idx);
const count = buf[propOffset++]; const count = buf[propOffset++];
@ -1241,7 +1239,7 @@ function _dump(ctx) {
} }
} }
const v = readU32(buf, offset); const v = readU32(buf, propOffset);
propOffset += 4; propOffset += 4;
if (kind === PropFlags.Ref) { if (kind === PropFlags.Ref) {

View file

@ -70,29 +70,11 @@ fn append_u32(result: &mut Vec<u8>, value: u32) {
result.push(v4); result.push(v4);
} }
#[inline]
fn write_u32(result: &mut [u8], value: u32, offset: usize) {
let v1: u8 = ((value & MASK_U32_1) >> 24) as u8;
let v2: u8 = ((value & MASK_U32_2) >> 16) as u8;
let v3: u8 = ((value & MASK_U32_3) >> 8) as u8;
let v4: u8 = (value & MASK_U32_4) as u8;
result[offset] = v1;
result[offset + 1] = v2;
result[offset + 2] = v3;
result[offset + 3] = v4;
}
fn append_usize(result: &mut Vec<u8>, value: usize) { fn append_usize(result: &mut Vec<u8>, value: usize) {
let raw = u32::try_from(value).unwrap(); let raw = u32::try_from(value).unwrap();
append_u32(result, raw); append_u32(result, raw);
} }
fn write_usize(result: &mut [u8], value: usize, offset: usize) {
let raw = u32::try_from(value).unwrap();
write_u32(result, raw, offset);
}
#[derive(Debug)] #[derive(Debug)]
pub struct StringTable { pub struct StringTable {
id: usize, id: usize,
@ -142,14 +124,27 @@ pub trait AstBufSerializer {
fn serialize(&mut self) -> Vec<u8>; fn serialize(&mut self) -> Vec<u8>;
} }
/// <type u8>
/// <prop offset u32>
/// <child idx u32>
/// <next idx u32>
/// <parent idx u32>
#[derive(Debug)]
struct Node {
kind: u8,
prop_offset: u32,
child: u32,
next: u32,
parent: u32,
}
#[derive(Debug)] #[derive(Debug)]
pub struct SerializeCtx { pub struct SerializeCtx {
id: u32, id: u32,
start_buf: NodeRef, start_buf: NodeRef,
/// Node buffer for traversal nodes: Vec<Node>,
buf: Vec<u8>,
field_buf: Vec<u8>, field_buf: Vec<u8>,
/// Vec of spans /// Vec of spans
@ -168,13 +163,6 @@ pub struct SerializeCtx {
prev_sibling_node: Option<u32>, prev_sibling_node: Option<u32>,
} }
/// <type u8>
/// <prop offset u32>
/// <child idx u32>
/// <next idx u32>
/// <parent idx u32>
const NODE_SIZE: u32 = 1 + 4 + 4 + 4 + 4;
/// This is the internal context used to allocate and fill the buffer. The point /// This is the internal context used to allocate and fill the buffer. The point
/// is to be able to write absolute offsets directly in place. /// is to be able to write absolute offsets directly in place.
/// ///
@ -190,7 +178,7 @@ impl SerializeCtx {
id: 0, id: 0,
spans: vec![], spans: vec![],
start_buf: NodeRef(0), start_buf: NodeRef(0),
buf: vec![], nodes: vec![],
field_buf: vec![], field_buf: vec![],
str_table: StringTable::new(), str_table: StringTable::new(),
kind_name_map: vec![0; kind_size], kind_name_map: vec![0; kind_size],
@ -206,7 +194,7 @@ impl SerializeCtx {
ctx.append_node(0, &DUMMY_SP); ctx.append_node(0, &DUMMY_SP);
ctx.kind_name_map[0] = empty_str; ctx.kind_name_map[0] = empty_str;
ctx.kind_name_map[1] = empty_str; ctx.kind_name_map[1] = empty_str;
ctx.start_buf = NodeRef(ctx.buf.len() as u32); ctx.start_buf = NodeRef(ctx.nodes.len() as u32);
// Insert default props that are always present // Insert default props that are always present
let type_str = ctx.str_table.insert("type"); let type_str = ctx.str_table.insert("type");
@ -251,11 +239,9 @@ impl SerializeCtx {
} }
fn update_parent_link(&mut self, parent_id: u32, ref_id: u32) { fn update_parent_link(&mut self, parent_id: u32, ref_id: u32) {
let offset = ref_id * NODE_SIZE; eprintln!("set parent {} for {}", parent_id, ref_id);
let node = self.nodes.get_mut(ref_id as usize).expect("Invalid id");
// Update parent id of written ref node.parent = parent_id;
let parent_offset = offset + 1 + 4 + 4;
write_u32(&mut self.buf, parent_id, parent_offset.try_into().unwrap());
} }
fn update_ref_links(&mut self, parent_id: u32, ref_id: u32) { fn update_ref_links(&mut self, parent_id: u32, ref_id: u32) {
@ -263,44 +249,45 @@ impl SerializeCtx {
// Update next pointer of previous sibling // Update next pointer of previous sibling
if let Some(prev_id) = self.prev_sibling_node { if let Some(prev_id) = self.prev_sibling_node {
let prev_offset = prev_id * NODE_SIZE; eprintln!("set next {} for {}", ref_id, prev_id);
let node = self.nodes.get_mut(prev_id as usize).unwrap();
let prev_next = prev_offset + 1 + 4; node.next = ref_id;
write_u32(&mut self.buf, ref_id, prev_next.try_into().unwrap());
} else { } else {
// Update parent child pointer // Update parent child pointer
let parent_offset = parent_id * NODE_SIZE; eprintln!("set child {} for {}", ref_id, parent_id);
let node = self.nodes.get_mut(parent_id as usize).unwrap();
let child_offset = parent_offset + 1; node.child = ref_id;
write_u32(&mut self.buf, ref_id, child_offset.try_into().unwrap());
} }
self.prev_sibling_node = Some(ref_id) self.prev_sibling_node = Some(ref_id)
} }
fn append_inner( fn append_inner<K>(
&mut self, &mut self,
kind: u8, kind: K,
field_offset: usize, prop_offset: usize,
span_lo: u32, span_lo: u32,
span_hi: u32, span_hi: u32,
) { ) where
// type K: Into<u8> + Display + Clone,
self.buf.push(kind); {
let kind_u8: u8 = kind.clone().into();
if let Some(v) = self.kind_name_map.get::<usize>(kind.into()) { self.nodes.push(Node {
kind: kind_u8,
prop_offset: prop_offset as u32,
child: 0,
next: 0,
parent: 0,
});
if let Some(v) = self.kind_name_map.get::<usize>(kind_u8.into()) {
if *v == 0 { if *v == 0 {
let s_id = self.str_table.insert(&format!("{kind}")); let s_id = self.str_table.insert(&format!("{kind}"));
self.kind_name_map[kind as usize] = s_id; self.kind_name_map[kind_u8 as usize] = s_id;
} }
} }
// field offset + child idx + next idx + parent idx
append_usize(&mut self.buf, field_offset);
append_usize(&mut self.buf, 0);
append_usize(&mut self.buf, 0);
append_usize(&mut self.buf, 0);
// write spans // write spans
self.spans.push(span_lo); self.spans.push(span_lo);
self.spans.push(span_hi); self.spans.push(span_hi);
@ -316,9 +303,7 @@ impl SerializeCtx {
self.field_offset = self.field_buf.len(); self.field_offset = self.field_buf.len();
self.field_buf.push(0); self.field_buf.push(0);
// type self.append_inner(kind, self.field_offset, span.lo.0, span.hi.0);
let kind_u8 = kind.clone().into();
self.append_inner(kind_u8, self.field_offset, span.lo.0, span.hi.0);
PendingRef(id) PendingRef(id)
} }
@ -411,10 +396,14 @@ impl SerializeCtx {
where where
P: Into<u8> + Display + Clone, P: Into<u8> + Display + Clone,
{ {
eprintln!("prop: {} set parent {} for {:#?}", prop, parent.0, value);
self.field_header(prop, PropFlags::Ref); self.field_header(prop, PropFlags::Ref);
append_u32(&mut self.field_buf, value.0); append_u32(&mut self.field_buf, value.0);
self.update_ref_links(parent.0, value.0); if parent.0 > 0 {
self.update_ref_links(parent.0, value.0);
}
} }
/// Helper for writing optional node offsets /// Helper for writing optional node offsets
@ -426,12 +415,11 @@ impl SerializeCtx {
) where ) where
P: Into<u8> + Display + Clone, P: Into<u8> + Display + Clone,
{ {
let ref_value = if let Some(v) = value { v.0 } else { 0 }; if let Some(v) = value {
self.write_ref(prop, parent, v);
self.field_header(prop, PropFlags::Ref); } else {
append_u32(&mut self.field_buf, ref_value); self.write_null(prop);
};
self.update_ref_links(parent.0, ref_value);
} }
/// Write a vec of node offsets into the property. The necessary space /// Write a vec of node offsets into the property. The necessary space
@ -447,10 +435,8 @@ impl SerializeCtx {
self.field_header(prop, PropFlags::RefArr); self.field_header(prop, PropFlags::RefArr);
let group_id = self.get_id(); let group_id = self.get_id();
append_u32(&mut self.field_buf, group_id); append_u32(&mut self.field_buf, group_id);
// TODO(@marvinhagemeister) This is wrong
self.append_inner(GROUP_KIND, 0, 0, 0); self.append_inner(GROUP_KIND, 0, 0, 0);
self.update_parent_link(parent.0, group_id); self.update_parent_link(parent.0, group_id);
@ -466,16 +452,26 @@ impl SerializeCtx {
/// <string table> /// <string table>
/// <node kind map> <- node kind id maps to string id /// <node kind map> <- node kind id maps to string id
/// <node prop map> <- node property id maps to string id /// <node prop map> <- node property id maps to string id
/// <spans> <- List of spans, rarely needed
/// <offset spans>
/// <offset kind map> /// <offset kind map>
/// <offset prop map> /// <offset prop map>
/// <offset str table> /// <offset str table>
pub fn serialize(&mut self) -> Vec<u8> { pub fn serialize(&mut self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![]; let mut buf: Vec<u8> = vec![];
eprintln!("BUFFER {:#?}", self.nodes);
// The buffer starts with the serialized AST first, because that // The buffer starts with the serialized AST first, because that
// contains absolute offsets. By butting this at the start of the // contains absolute offsets. By butting this at the start of the
// message we don't have to waste time updating any offsets. // message we don't have to waste time updating any offsets.
buf.append(&mut self.buf); for node in &self.nodes {
buf.push(node.kind);
append_u32(&mut buf, node.prop_offset);
append_u32(&mut buf, node.child);
append_u32(&mut buf, node.next);
append_u32(&mut buf, node.parent);
}
// Next follows the string table. We'll keep track of the offset // Next follows the string table. We'll keep track of the offset
// in the message of where the string table begins // in the message of where the string table begins

View file

@ -943,7 +943,7 @@ fn serialize_member_expr(
ctx.write_member_expr(&node.span, optional, computed, obj, prop) ctx.write_member_expr(&node.span, optional, computed, obj, prop)
} }
fn serialize_class_member( fn _serialize_class_member(
ctx: &mut TsEsTreeBuilder, ctx: &mut TsEsTreeBuilder,
member: &ClassMember, member: &ClassMember,
) -> NodeRef { ) -> NodeRef {
@ -1314,7 +1314,7 @@ fn serialize_ts_index_sig(
// pos // pos
} }
fn accessibility_to_str(accessibility: Accessibility) -> String { fn _accessibility_to_str(accessibility: Accessibility) -> String {
match accessibility { match accessibility {
Accessibility::Public => "public".to_string(), Accessibility::Public => "public".to_string(),
Accessibility::Protected => "protected".to_string(), Accessibility::Protected => "protected".to_string(),

View file

@ -304,9 +304,9 @@ impl WorkspaceLinter {
fn logger_printer(msg: &str, is_err: bool) { fn logger_printer(msg: &str, is_err: bool) {
if is_err { if is_err {
eprintln!("{}", msg); eprintln!("{}", msg.trim_end());
} else { } else {
println!("{}", msg); println!("{}", msg.trim_end());
} }
} }