From 13dbb0ec28c44d5dd122f6adf09e2d51e36393dc Mon Sep 17 00:00:00 2001 From: Adel Prokurov Date: Wed, 14 Dec 2022 17:31:25 +0500 Subject: [PATCH] newjs: sideeffect, break and escape analysis (W.I.P) --- vlib/v/gen/newjs/analysis/break.v | 34 +++++++++ vlib/v/gen/newjs/analysis/escape.v | 102 +++++++++++++++++++++++++ vlib/v/gen/newjs/analysis/sideeffect.v | 39 ++++++++++ vlib/v/gen/newjs/expression.v | 30 ++++++++ vlib/v/gen/newjs/js.v | 1 + vlib/v/gen/newjs/util.v | 26 +++++-- 6 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 vlib/v/gen/newjs/analysis/break.v create mode 100644 vlib/v/gen/newjs/analysis/escape.v create mode 100644 vlib/v/gen/newjs/analysis/sideeffect.v create mode 100644 vlib/v/gen/newjs/expression.v diff --git a/vlib/v/gen/newjs/analysis/break.v b/vlib/v/gen/newjs/analysis/break.v new file mode 100644 index 0000000000..966c67ca63 --- /dev/null +++ b/vlib/v/gen/newjs/analysis/break.v @@ -0,0 +1,34 @@ +module analysis + +import v.ast +import v.ast.walker + +struct HasBreakVisitor { +mut: + has_break bool +} + +pub fn has_break(n &ast.Node) bool { + mut v := HasBreakVisitor{has_break: false} + walker.walk(mut v, n) + return v.has_break +} + +fn (mut v HasBreakVisitor) visit(node &ast.Node) ! { + if v.has_break { + return + } + + if node is ast.Stmt { + match node { + ast.BranchStmt { + if node.kind == .key_break && node.label.len > 0 { + v.has_break = true + return + } + } + else {} + } + } +} + diff --git a/vlib/v/gen/newjs/analysis/escape.v b/vlib/v/gen/newjs/analysis/escape.v new file mode 100644 index 0000000000..d825913e63 --- /dev/null +++ b/vlib/v/gen/newjs/analysis/escape.v @@ -0,0 +1,102 @@ +module analysis + +import v.ast +import v.ast.walker + + +pub fn escaping_objects(n &ast.Node) []&ast.Var { + mut v := EscapeAnalysis { + escaping: map[voidptr]bool{} + bottom_scopes: map[voidptr]bool{} + } + + walker.walk(mut v, n) + + mut list := []&ast.Var{} + + for obj, _ in v.escaping { + list << &ast.Var(obj) + } + + return list +} + +struct EscapeAnalysis { +mut: + escaping map[voidptr]bool + top_scope &ast.Scope = unsafe { nil } + bottom_scopes map[voidptr]bool + +} + +fn (mut v EscapeAnalysis) visit(node &ast.Node) ! { + match node { + ast.Expr { + if node is ast.PostfixExpr { + if node.op == .amp { + if node.expr is ast.Ident { + mut collector := EscapingObjectCollector { + analysis: unsafe { v } + } + walker.walk(mut collector, &ast.Node(ast.Expr(node.expr))) + } + } + } + } + + ast.Stmt { + match node { + ast.FnDecl { + v.bottom_scopes[voidptr(node.scope)] = true + mut collector := EscapingObjectCollector { + analysis: unsafe { v } + } + walker.walk(mut collector, &ast.Node(ast.Stmt(node))) + return + } + + ast.ForStmt { + v.bottom_scopes[voidptr(node.scope)] = true + return + } + + else { + return + } + } + } else { + return + } + } +} + +struct EscapingObjectCollector { +mut: + analysis &EscapeAnalysis +} + +fn (mut v EscapingObjectCollector) visit(node &ast.Node) ! { + if node is ast.Expr { + match node { + ast.Ident { + if node.obj is ast.Var { + mut s := node.scope + + for unsafe { s != nil } { + if s == v.analysis.top_scope { + v.analysis.escaping[voidptr(unsafe { &node })] = true + break + } + + if v.analysis.bottom_scopes[voidptr(s)] { + break + } + s = s.parent + } + } + } else { + + } + } + } +} \ No newline at end of file diff --git a/vlib/v/gen/newjs/analysis/sideeffect.v b/vlib/v/gen/newjs/analysis/sideeffect.v new file mode 100644 index 0000000000..158010e388 --- /dev/null +++ b/vlib/v/gen/newjs/analysis/sideeffect.v @@ -0,0 +1,39 @@ +module analysis + +import v.ast +import v.ast.walker + +struct HasSideEffectVisitor { +mut: + has_sideeffect bool +} + +pub fn has_sideeffect(n &ast.Node) bool { + mut v := HasSideEffectVisitor{has_sideeffect: false} + walker.walk(mut v, n) + return v.has_sideeffect +} + +fn (mut v HasSideEffectVisitor) visit(node &ast.Node) ! { + if v.has_sideeffect { + return + } + + if node is ast.Expr { + match node { + ast.InfixExpr { + if node.op == .arrow { + v.has_sideeffect = true + return + } + } + ast.CallExpr { + v.has_sideeffect = true + return + } + // todo: overloaded operators can lead to side effects as well? + else {} + } + } +} + diff --git a/vlib/v/gen/newjs/expression.v b/vlib/v/gen/newjs/expression.v new file mode 100644 index 0000000000..435a255301 --- /dev/null +++ b/vlib/v/gen/newjs/expression.v @@ -0,0 +1,30 @@ +module newjs + +import strings +import v.ast +import v.token +import v.pref +import v.util +import v.util.version +import v.depgraph + +[heap] +struct Expression { + str string + parens bool +} + +fn (e &Expression) str() string { + return e.str +} + +fn (e &Expression) str_with_parens() string { + if e.parens { + return '(' + e.str + ')' + } + return e.str +} + +fn (mut fc FuncContext) translate_expr(expr ast.Expr) &Expression { + return unsafe { nil } +} \ No newline at end of file diff --git a/vlib/v/gen/newjs/js.v b/vlib/v/gen/newjs/js.v index dbec3eecb6..ddfa8cecd9 100644 --- a/vlib/v/gen/newjs/js.v +++ b/vlib/v/gen/newjs/js.v @@ -7,6 +7,7 @@ import v.pref import v.util import v.util.version import v.depgraph +import analysis [heap] diff --git a/vlib/v/gen/newjs/util.v b/vlib/v/gen/newjs/util.v index d5fca1f4a4..1192f5ecc3 100644 --- a/vlib/v/gen/newjs/util.v +++ b/vlib/v/gen/newjs/util.v @@ -107,12 +107,28 @@ fn (mut fc FuncContext) new_variable_with_level(name_ string, mod_level bool) st return var_name } -fn (mut fc FuncContext) new_ident(name string, t ast.Type) { - -} +/* +fn (mut fc FuncContext) new_ident(name string, t ast.Type) &ast.Ident { + id := &ast.Ident { + language: .js + tok_kind: .name + comptime: false + mod: fc.mod_ctx.mod.name + name: name + kind: .variable + info: IdentVar { + typ: t + is_mut: true + is_static: false + is_volatile: false + is_optional: false + share: .mut_t + } + } +}*/ fn is_mod_level(fc &FuncContext, sym &ast.Ident) bool { - return unsafe { sym.scope is nil || (sym.scope == fc.mod_ctx.gen.table.global_scope || sym.scope.parent == fc.mod_ctx.gen.table.global_scope) } + return unsafe { sym.scope == nil || (sym.scope == fc.mod_ctx.gen.table.global_scope || sym.scope.parent == fc.mod_ctx.gen.table.global_scope) } } fn (mut fc FuncContext) ident_name(o &ast.Ident) string { @@ -125,7 +141,7 @@ fn (mut fc FuncContext) ident_name(o &ast.Ident) string { } name := fc.mod_ctx.object_names[o] or { - name := fc.new_variable_with_level(o.name, is_mod_level(o)) + name := fc.new_variable_with_level(o.name, is_mod_level(fc, o)) fc.mod_ctx.object_names[o] = name name }