compiler.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. package goja
  2. import (
  3. "fmt"
  4. "github.com/dop251/goja/ast"
  5. "github.com/dop251/goja/file"
  6. "sort"
  7. "strconv"
  8. )
  9. const (
  10. blockLoop = iota
  11. blockLoopEnum
  12. blockTry
  13. blockBranch
  14. blockSwitch
  15. blockWith
  16. )
  17. type CompilerError struct {
  18. Message string
  19. File *SrcFile
  20. Offset int
  21. }
  22. type CompilerSyntaxError struct {
  23. CompilerError
  24. }
  25. type CompilerReferenceError struct {
  26. CompilerError
  27. }
  28. type srcMapItem struct {
  29. pc int
  30. srcPos int
  31. }
  32. type Program struct {
  33. code []instruction
  34. values []Value
  35. funcName string
  36. src *SrcFile
  37. srcMap []srcMapItem
  38. }
  39. type compiler struct {
  40. p *Program
  41. scope *scope
  42. block *block
  43. blockStart int
  44. enumGetExpr compiledEnumGetExpr
  45. evalVM *vm
  46. }
  47. type scope struct {
  48. names map[string]uint32
  49. outer *scope
  50. strict bool
  51. eval bool
  52. lexical bool
  53. dynamic bool
  54. accessed bool
  55. argsNeeded bool
  56. thisNeeded bool
  57. namesMap map[string]string
  58. lastFreeTmp int
  59. }
  60. type block struct {
  61. typ int
  62. label string
  63. needResult bool
  64. cont int
  65. breaks []int
  66. conts []int
  67. outer *block
  68. }
  69. func (c *compiler) leaveBlock() {
  70. lbl := len(c.p.code)
  71. for _, item := range c.block.breaks {
  72. c.p.code[item] = jump(lbl - item)
  73. }
  74. if t := c.block.typ; t == blockLoop || t == blockLoopEnum {
  75. for _, item := range c.block.conts {
  76. c.p.code[item] = jump(c.block.cont - item)
  77. }
  78. }
  79. c.block = c.block.outer
  80. }
  81. func (e *CompilerSyntaxError) Error() string {
  82. if e.File != nil {
  83. return fmt.Sprintf("SyntaxError: %s at %s", e.Message, e.File.Position(e.Offset))
  84. }
  85. return fmt.Sprintf("SyntaxError: %s", e.Message)
  86. }
  87. func (e *CompilerReferenceError) Error() string {
  88. return fmt.Sprintf("ReferenceError: %s", e.Message)
  89. }
  90. func (c *compiler) newScope() {
  91. strict := false
  92. if c.scope != nil {
  93. strict = c.scope.strict
  94. }
  95. c.scope = &scope{
  96. outer: c.scope,
  97. names: make(map[string]uint32),
  98. strict: strict,
  99. namesMap: make(map[string]string),
  100. }
  101. }
  102. func (c *compiler) popScope() {
  103. c.scope = c.scope.outer
  104. }
  105. func newCompiler() *compiler {
  106. c := &compiler{
  107. p: &Program{},
  108. }
  109. c.enumGetExpr.init(c, file.Idx(0))
  110. c.newScope()
  111. c.scope.dynamic = true
  112. return c
  113. }
  114. func (p *Program) defineLiteralValue(val Value) uint32 {
  115. for idx, v := range p.values {
  116. if v.SameAs(val) {
  117. return uint32(idx)
  118. }
  119. }
  120. idx := uint32(len(p.values))
  121. p.values = append(p.values, val)
  122. return idx
  123. }
  124. func (p *Program) dumpCode(logger func(format string, args ...interface{})) {
  125. p._dumpCode("", logger)
  126. }
  127. func (p *Program) _dumpCode(indent string, logger func(format string, args ...interface{})) {
  128. logger("values: %+v", p.values)
  129. for pc, ins := range p.code {
  130. logger("%s %d: %T(%v)", indent, pc, ins, ins)
  131. if f, ok := ins.(*newFunc); ok {
  132. f.prg._dumpCode(indent+">", logger)
  133. }
  134. }
  135. }
  136. func (p *Program) sourceOffset(pc int) int {
  137. i := sort.Search(len(p.srcMap), func(idx int) bool {
  138. return p.srcMap[idx].pc > pc
  139. }) - 1
  140. if i >= 0 {
  141. return p.srcMap[i].srcPos
  142. }
  143. return 0
  144. }
  145. func (s *scope) isFunction() bool {
  146. if !s.lexical {
  147. return s.outer != nil
  148. }
  149. return s.outer.isFunction()
  150. }
  151. func (s *scope) lookupName(name string) (idx uint32, found, noDynamics bool) {
  152. var level uint32 = 0
  153. noDynamics = true
  154. for curScope := s; curScope != nil; curScope = curScope.outer {
  155. if curScope != s {
  156. curScope.accessed = true
  157. }
  158. if curScope.dynamic {
  159. noDynamics = false
  160. } else {
  161. var mapped string
  162. if m, exists := curScope.namesMap[name]; exists {
  163. mapped = m
  164. } else {
  165. mapped = name
  166. }
  167. if i, exists := curScope.names[mapped]; exists {
  168. idx = i | (level << 24)
  169. found = true
  170. return
  171. }
  172. }
  173. if name == "arguments" && !s.lexical && s.isFunction() {
  174. s.argsNeeded = true
  175. s.accessed = true
  176. idx, _ = s.bindName(name)
  177. found = true
  178. return
  179. }
  180. level++
  181. }
  182. return
  183. }
  184. func (s *scope) bindName(name string) (uint32, bool) {
  185. if s.lexical {
  186. return s.outer.bindName(name)
  187. }
  188. if idx, exists := s.names[name]; exists {
  189. return idx, false
  190. }
  191. idx := uint32(len(s.names))
  192. s.names[name] = idx
  193. return idx, true
  194. }
  195. func (s *scope) bindNameShadow(name string) (uint32, bool) {
  196. if s.lexical {
  197. return s.outer.bindName(name)
  198. }
  199. unique := true
  200. if idx, exists := s.names[name]; exists {
  201. unique = false
  202. // shadow the var
  203. delete(s.names, name)
  204. n := strconv.Itoa(int(idx))
  205. s.names[n] = idx
  206. }
  207. idx := uint32(len(s.names))
  208. s.names[name] = idx
  209. return idx, unique
  210. }
  211. func (c *compiler) markBlockStart() {
  212. c.blockStart = len(c.p.code)
  213. }
  214. func (c *compiler) compile(in *ast.Program) {
  215. c.p.src = NewSrcFile(in.File.Name(), in.File.Source(), in.SourceMap)
  216. if len(in.Body) > 0 {
  217. if !c.scope.strict {
  218. c.scope.strict = c.isStrict(in.Body)
  219. }
  220. }
  221. c.compileDeclList(in.DeclarationList, false)
  222. c.compileFunctions(in.DeclarationList)
  223. c.markBlockStart()
  224. c.compileStatements(in.Body, true)
  225. c.p.code = append(c.p.code, halt)
  226. code := c.p.code
  227. c.p.code = make([]instruction, 0, len(code)+len(c.scope.names)+2)
  228. if c.scope.eval {
  229. if !c.scope.strict {
  230. c.emit(jne(2), newStash)
  231. } else {
  232. c.emit(pop, newStash)
  233. }
  234. }
  235. l := len(c.p.code)
  236. c.p.code = c.p.code[:l+len(c.scope.names)]
  237. for name, nameIdx := range c.scope.names {
  238. c.p.code[l+int(nameIdx)] = bindName(name)
  239. }
  240. c.p.code = append(c.p.code, code...)
  241. for i := range c.p.srcMap {
  242. c.p.srcMap[i].pc += len(c.scope.names)
  243. }
  244. }
  245. func (c *compiler) compileDeclList(v []ast.Declaration, inFunc bool) {
  246. for _, value := range v {
  247. switch value := value.(type) {
  248. case *ast.FunctionDeclaration:
  249. c.compileFunctionDecl(value)
  250. case *ast.VariableDeclaration:
  251. c.compileVarDecl(value, inFunc)
  252. default:
  253. panic(fmt.Errorf("Unsupported declaration: %T", value))
  254. }
  255. }
  256. }
  257. func (c *compiler) compileFunctions(v []ast.Declaration) {
  258. for _, value := range v {
  259. if value, ok := value.(*ast.FunctionDeclaration); ok {
  260. c.compileFunction(value)
  261. }
  262. }
  263. }
  264. func (c *compiler) compileVarDecl(v *ast.VariableDeclaration, inFunc bool) {
  265. for _, item := range v.List {
  266. if c.scope.strict {
  267. c.checkIdentifierLName(item.Name, int(item.Idx)-1)
  268. c.checkIdentifierName(item.Name, int(item.Idx)-1)
  269. }
  270. if !inFunc || item.Name != "arguments" {
  271. idx, ok := c.scope.bindName(item.Name)
  272. _ = idx
  273. //log.Printf("Define var: %s: %x", item.Name, idx)
  274. if !ok {
  275. // TODO: error
  276. }
  277. }
  278. }
  279. }
  280. func (c *compiler) addDecls() []instruction {
  281. code := make([]instruction, len(c.scope.names))
  282. for name, nameIdx := range c.scope.names {
  283. code[nameIdx] = bindName(name)
  284. }
  285. return code
  286. }
  287. func (c *compiler) convertInstrToStashless(instr uint32, args int) (newIdx int, convert bool) {
  288. level := instr >> 24
  289. idx := instr & 0x00FFFFFF
  290. if level > 0 {
  291. level--
  292. newIdx = int((level << 24) | idx)
  293. } else {
  294. iidx := int(idx)
  295. if iidx < args {
  296. newIdx = -iidx - 1
  297. } else {
  298. newIdx = iidx - args + 1
  299. }
  300. convert = true
  301. }
  302. return
  303. }
  304. func (c *compiler) convertFunctionToStashless(code []instruction, args int) {
  305. code[0] = enterFuncStashless{stackSize: uint32(len(c.scope.names) - args), args: uint32(args)}
  306. for pc := 1; pc < len(code); pc++ {
  307. instr := code[pc]
  308. if instr == ret {
  309. code[pc] = retStashless
  310. }
  311. switch instr := instr.(type) {
  312. case getLocal:
  313. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  314. code[pc] = loadStack(newIdx)
  315. } else {
  316. code[pc] = getLocal(newIdx)
  317. }
  318. case setLocal:
  319. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  320. code[pc] = storeStack(newIdx)
  321. } else {
  322. code[pc] = setLocal(newIdx)
  323. }
  324. case setLocalP:
  325. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  326. code[pc] = storeStackP(newIdx)
  327. } else {
  328. code[pc] = setLocalP(newIdx)
  329. }
  330. case getVar:
  331. level := instr.idx >> 24
  332. idx := instr.idx & 0x00FFFFFF
  333. level--
  334. instr.idx = level<<24 | idx
  335. code[pc] = instr
  336. case setVar:
  337. level := instr.idx >> 24
  338. idx := instr.idx & 0x00FFFFFF
  339. level--
  340. instr.idx = level<<24 | idx
  341. code[pc] = instr
  342. }
  343. }
  344. }
  345. func (c *compiler) compileFunctionDecl(v *ast.FunctionDeclaration) {
  346. idx, ok := c.scope.bindName(v.Function.Name.Name)
  347. if !ok {
  348. // TODO: error
  349. }
  350. _ = idx
  351. // log.Printf("Define function: %s: %x", v.Function.Name.Name, idx)
  352. }
  353. func (c *compiler) compileFunction(v *ast.FunctionDeclaration) {
  354. e := &compiledIdentifierExpr{
  355. name: v.Function.Name.Name,
  356. }
  357. e.init(c, v.Function.Idx0())
  358. e.emitSetter(c.compileFunctionLiteral(v.Function, false))
  359. c.emit(pop)
  360. }
  361. func (c *compiler) emit(instructions ...instruction) {
  362. c.p.code = append(c.p.code, instructions...)
  363. }
  364. func (c *compiler) throwSyntaxError(offset int, format string, args ...interface{}) {
  365. panic(&CompilerSyntaxError{
  366. CompilerError: CompilerError{
  367. File: c.p.src,
  368. Offset: offset,
  369. Message: fmt.Sprintf(format, args...),
  370. },
  371. })
  372. }
  373. func (c *compiler) isStrict(list []ast.Statement) bool {
  374. for _, st := range list {
  375. if st, ok := st.(*ast.ExpressionStatement); ok {
  376. if e, ok := st.Expression.(*ast.StringLiteral); ok {
  377. if e.Literal == `"use strict"` || e.Literal == `'use strict'` {
  378. return true
  379. }
  380. } else {
  381. break
  382. }
  383. } else {
  384. break
  385. }
  386. }
  387. return false
  388. }
  389. func (c *compiler) isStrictStatement(s ast.Statement) bool {
  390. if s, ok := s.(*ast.BlockStatement); ok {
  391. return c.isStrict(s.List)
  392. }
  393. return false
  394. }
  395. func (c *compiler) checkIdentifierName(name string, offset int) {
  396. switch name {
  397. case "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield":
  398. c.throwSyntaxError(offset, "Unexpected strict mode reserved word")
  399. }
  400. }
  401. func (c *compiler) checkIdentifierLName(name string, offset int) {
  402. switch name {
  403. case "eval", "arguments":
  404. c.throwSyntaxError(offset, "Assignment to eval or arguments is not allowed in strict mode")
  405. }
  406. }