compiler.go 11 KB

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