opcode.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. package encoder
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. "unsafe"
  8. "github.com/goccy/go-json/internal/runtime"
  9. )
  10. const uintptrSize = 4 << (^uintptr(0) >> 63)
  11. type OpFlags uint16
  12. const (
  13. AnonymousHeadFlags OpFlags = 1 << 0
  14. AnonymousKeyFlags OpFlags = 1 << 1
  15. IndirectFlags OpFlags = 1 << 2
  16. IsTaggedKeyFlags OpFlags = 1 << 3
  17. NilCheckFlags OpFlags = 1 << 4
  18. AddrForMarshalerFlags OpFlags = 1 << 5
  19. IsNextOpPtrTypeFlags OpFlags = 1 << 6
  20. IsNilableTypeFlags OpFlags = 1 << 7
  21. MarshalerContextFlags OpFlags = 1 << 8
  22. NonEmptyInterfaceFlags OpFlags = 1 << 9
  23. )
  24. type Opcode struct {
  25. Op OpType // operation type
  26. Idx uint32 // offset to access ptr
  27. Next *Opcode // next opcode
  28. End *Opcode // array/slice/struct/map end
  29. NextField *Opcode // next struct field
  30. Key string // struct field key
  31. Offset uint32 // offset size from struct header
  32. PtrNum uint8 // pointer number: e.g. double pointer is 2.
  33. NumBitSize uint8
  34. Flags OpFlags
  35. Type *runtime.Type // go type
  36. Jmp *CompiledCode // for recursive call
  37. FieldQuery *FieldQuery // field query for Interface / MarshalJSON / MarshalText
  38. ElemIdx uint32 // offset to access array/slice elem
  39. Length uint32 // offset to access slice length or array length
  40. Indent uint32 // indent number
  41. Size uint32 // array/slice elem size
  42. DisplayIdx uint32 // opcode index
  43. DisplayKey string // key text to display
  44. }
  45. func (c *Opcode) Validate() error {
  46. var prevIdx uint32
  47. for code := c; !code.IsEnd(); {
  48. if prevIdx != 0 {
  49. if code.DisplayIdx != prevIdx+1 {
  50. return fmt.Errorf(
  51. "invalid index. previous display index is %d but next is %d. dump = %s",
  52. prevIdx, code.DisplayIdx, c.Dump(),
  53. )
  54. }
  55. }
  56. prevIdx = code.DisplayIdx
  57. code = code.IterNext()
  58. }
  59. return nil
  60. }
  61. func (c *Opcode) IterNext() *Opcode {
  62. if c == nil {
  63. return nil
  64. }
  65. switch c.Op.CodeType() {
  66. case CodeArrayElem, CodeSliceElem, CodeMapKey:
  67. return c.End
  68. default:
  69. return c.Next
  70. }
  71. }
  72. func (c *Opcode) IsEnd() bool {
  73. if c == nil {
  74. return true
  75. }
  76. return c.Op == OpEnd || c.Op == OpInterfaceEnd || c.Op == OpRecursiveEnd
  77. }
  78. func (c *Opcode) MaxIdx() uint32 {
  79. max := uint32(0)
  80. for _, value := range []uint32{
  81. c.Idx,
  82. c.ElemIdx,
  83. c.Length,
  84. c.Size,
  85. } {
  86. if max < value {
  87. max = value
  88. }
  89. }
  90. return max
  91. }
  92. func (c *Opcode) ToHeaderType(isString bool) OpType {
  93. switch c.Op {
  94. case OpInt:
  95. if isString {
  96. return OpStructHeadIntString
  97. }
  98. return OpStructHeadInt
  99. case OpIntPtr:
  100. if isString {
  101. return OpStructHeadIntPtrString
  102. }
  103. return OpStructHeadIntPtr
  104. case OpUint:
  105. if isString {
  106. return OpStructHeadUintString
  107. }
  108. return OpStructHeadUint
  109. case OpUintPtr:
  110. if isString {
  111. return OpStructHeadUintPtrString
  112. }
  113. return OpStructHeadUintPtr
  114. case OpFloat32:
  115. if isString {
  116. return OpStructHeadFloat32String
  117. }
  118. return OpStructHeadFloat32
  119. case OpFloat32Ptr:
  120. if isString {
  121. return OpStructHeadFloat32PtrString
  122. }
  123. return OpStructHeadFloat32Ptr
  124. case OpFloat64:
  125. if isString {
  126. return OpStructHeadFloat64String
  127. }
  128. return OpStructHeadFloat64
  129. case OpFloat64Ptr:
  130. if isString {
  131. return OpStructHeadFloat64PtrString
  132. }
  133. return OpStructHeadFloat64Ptr
  134. case OpString:
  135. if isString {
  136. return OpStructHeadStringString
  137. }
  138. return OpStructHeadString
  139. case OpStringPtr:
  140. if isString {
  141. return OpStructHeadStringPtrString
  142. }
  143. return OpStructHeadStringPtr
  144. case OpNumber:
  145. if isString {
  146. return OpStructHeadNumberString
  147. }
  148. return OpStructHeadNumber
  149. case OpNumberPtr:
  150. if isString {
  151. return OpStructHeadNumberPtrString
  152. }
  153. return OpStructHeadNumberPtr
  154. case OpBool:
  155. if isString {
  156. return OpStructHeadBoolString
  157. }
  158. return OpStructHeadBool
  159. case OpBoolPtr:
  160. if isString {
  161. return OpStructHeadBoolPtrString
  162. }
  163. return OpStructHeadBoolPtr
  164. case OpBytes:
  165. return OpStructHeadBytes
  166. case OpBytesPtr:
  167. return OpStructHeadBytesPtr
  168. case OpMap:
  169. return OpStructHeadMap
  170. case OpMapPtr:
  171. c.Op = OpMap
  172. return OpStructHeadMapPtr
  173. case OpArray:
  174. return OpStructHeadArray
  175. case OpArrayPtr:
  176. c.Op = OpArray
  177. return OpStructHeadArrayPtr
  178. case OpSlice:
  179. return OpStructHeadSlice
  180. case OpSlicePtr:
  181. c.Op = OpSlice
  182. return OpStructHeadSlicePtr
  183. case OpMarshalJSON:
  184. return OpStructHeadMarshalJSON
  185. case OpMarshalJSONPtr:
  186. return OpStructHeadMarshalJSONPtr
  187. case OpMarshalText:
  188. return OpStructHeadMarshalText
  189. case OpMarshalTextPtr:
  190. return OpStructHeadMarshalTextPtr
  191. }
  192. return OpStructHead
  193. }
  194. func (c *Opcode) ToFieldType(isString bool) OpType {
  195. switch c.Op {
  196. case OpInt:
  197. if isString {
  198. return OpStructFieldIntString
  199. }
  200. return OpStructFieldInt
  201. case OpIntPtr:
  202. if isString {
  203. return OpStructFieldIntPtrString
  204. }
  205. return OpStructFieldIntPtr
  206. case OpUint:
  207. if isString {
  208. return OpStructFieldUintString
  209. }
  210. return OpStructFieldUint
  211. case OpUintPtr:
  212. if isString {
  213. return OpStructFieldUintPtrString
  214. }
  215. return OpStructFieldUintPtr
  216. case OpFloat32:
  217. if isString {
  218. return OpStructFieldFloat32String
  219. }
  220. return OpStructFieldFloat32
  221. case OpFloat32Ptr:
  222. if isString {
  223. return OpStructFieldFloat32PtrString
  224. }
  225. return OpStructFieldFloat32Ptr
  226. case OpFloat64:
  227. if isString {
  228. return OpStructFieldFloat64String
  229. }
  230. return OpStructFieldFloat64
  231. case OpFloat64Ptr:
  232. if isString {
  233. return OpStructFieldFloat64PtrString
  234. }
  235. return OpStructFieldFloat64Ptr
  236. case OpString:
  237. if isString {
  238. return OpStructFieldStringString
  239. }
  240. return OpStructFieldString
  241. case OpStringPtr:
  242. if isString {
  243. return OpStructFieldStringPtrString
  244. }
  245. return OpStructFieldStringPtr
  246. case OpNumber:
  247. if isString {
  248. return OpStructFieldNumberString
  249. }
  250. return OpStructFieldNumber
  251. case OpNumberPtr:
  252. if isString {
  253. return OpStructFieldNumberPtrString
  254. }
  255. return OpStructFieldNumberPtr
  256. case OpBool:
  257. if isString {
  258. return OpStructFieldBoolString
  259. }
  260. return OpStructFieldBool
  261. case OpBoolPtr:
  262. if isString {
  263. return OpStructFieldBoolPtrString
  264. }
  265. return OpStructFieldBoolPtr
  266. case OpBytes:
  267. return OpStructFieldBytes
  268. case OpBytesPtr:
  269. return OpStructFieldBytesPtr
  270. case OpMap:
  271. return OpStructFieldMap
  272. case OpMapPtr:
  273. c.Op = OpMap
  274. return OpStructFieldMapPtr
  275. case OpArray:
  276. return OpStructFieldArray
  277. case OpArrayPtr:
  278. c.Op = OpArray
  279. return OpStructFieldArrayPtr
  280. case OpSlice:
  281. return OpStructFieldSlice
  282. case OpSlicePtr:
  283. c.Op = OpSlice
  284. return OpStructFieldSlicePtr
  285. case OpMarshalJSON:
  286. return OpStructFieldMarshalJSON
  287. case OpMarshalJSONPtr:
  288. return OpStructFieldMarshalJSONPtr
  289. case OpMarshalText:
  290. return OpStructFieldMarshalText
  291. case OpMarshalTextPtr:
  292. return OpStructFieldMarshalTextPtr
  293. }
  294. return OpStructField
  295. }
  296. func newOpCode(ctx *compileContext, typ *runtime.Type, op OpType) *Opcode {
  297. return newOpCodeWithNext(ctx, typ, op, newEndOp(ctx, typ))
  298. }
  299. func opcodeOffset(idx int) uint32 {
  300. return uint32(idx) * uintptrSize
  301. }
  302. func getCodeAddrByIdx(head *Opcode, idx uint32) *Opcode {
  303. addr := uintptr(unsafe.Pointer(head)) + uintptr(idx)*unsafe.Sizeof(Opcode{})
  304. return *(**Opcode)(unsafe.Pointer(&addr))
  305. }
  306. func copyOpcode(code *Opcode) *Opcode {
  307. codeNum := ToEndCode(code).DisplayIdx + 1
  308. codeSlice := make([]Opcode, codeNum)
  309. head := (*Opcode)((*runtime.SliceHeader)(unsafe.Pointer(&codeSlice)).Data)
  310. ptr := head
  311. c := code
  312. for {
  313. *ptr = Opcode{
  314. Op: c.Op,
  315. Key: c.Key,
  316. PtrNum: c.PtrNum,
  317. NumBitSize: c.NumBitSize,
  318. Flags: c.Flags,
  319. Idx: c.Idx,
  320. Offset: c.Offset,
  321. Type: c.Type,
  322. FieldQuery: c.FieldQuery,
  323. DisplayIdx: c.DisplayIdx,
  324. DisplayKey: c.DisplayKey,
  325. ElemIdx: c.ElemIdx,
  326. Length: c.Length,
  327. Size: c.Size,
  328. Indent: c.Indent,
  329. Jmp: c.Jmp,
  330. }
  331. if c.End != nil {
  332. ptr.End = getCodeAddrByIdx(head, c.End.DisplayIdx)
  333. }
  334. if c.NextField != nil {
  335. ptr.NextField = getCodeAddrByIdx(head, c.NextField.DisplayIdx)
  336. }
  337. if c.Next != nil {
  338. ptr.Next = getCodeAddrByIdx(head, c.Next.DisplayIdx)
  339. }
  340. if c.IsEnd() {
  341. break
  342. }
  343. ptr = getCodeAddrByIdx(head, c.DisplayIdx+1)
  344. c = c.IterNext()
  345. }
  346. return head
  347. }
  348. func setTotalLengthToInterfaceOp(code *Opcode) {
  349. for c := code; !c.IsEnd(); {
  350. if c.Op == OpInterface || c.Op == OpInterfacePtr {
  351. c.Length = uint32(code.TotalLength())
  352. }
  353. c = c.IterNext()
  354. }
  355. }
  356. func ToEndCode(code *Opcode) *Opcode {
  357. c := code
  358. for !c.IsEnd() {
  359. c = c.IterNext()
  360. }
  361. return c
  362. }
  363. func copyToInterfaceOpcode(code *Opcode) *Opcode {
  364. copied := copyOpcode(code)
  365. c := copied
  366. c = ToEndCode(c)
  367. c.Idx += uintptrSize
  368. c.ElemIdx = c.Idx + uintptrSize
  369. c.Length = c.Idx + 2*uintptrSize
  370. c.Op = OpInterfaceEnd
  371. return copied
  372. }
  373. func newOpCodeWithNext(ctx *compileContext, typ *runtime.Type, op OpType, next *Opcode) *Opcode {
  374. return &Opcode{
  375. Op: op,
  376. Idx: opcodeOffset(ctx.ptrIndex),
  377. Next: next,
  378. Type: typ,
  379. DisplayIdx: ctx.opcodeIndex,
  380. Indent: ctx.indent,
  381. }
  382. }
  383. func newEndOp(ctx *compileContext, typ *runtime.Type) *Opcode {
  384. return newOpCodeWithNext(ctx, typ, OpEnd, nil)
  385. }
  386. func (c *Opcode) TotalLength() int {
  387. var idx int
  388. code := c
  389. for !code.IsEnd() {
  390. maxIdx := int(code.MaxIdx() / uintptrSize)
  391. if idx < maxIdx {
  392. idx = maxIdx
  393. }
  394. if code.Op == OpRecursiveEnd {
  395. break
  396. }
  397. code = code.IterNext()
  398. }
  399. maxIdx := int(code.MaxIdx() / uintptrSize)
  400. if idx < maxIdx {
  401. idx = maxIdx
  402. }
  403. return idx + 1
  404. }
  405. func (c *Opcode) dumpHead(code *Opcode) string {
  406. var length uint32
  407. if code.Op.CodeType() == CodeArrayHead {
  408. length = code.Length
  409. } else {
  410. length = code.Length / uintptrSize
  411. }
  412. return fmt.Sprintf(
  413. `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d])`,
  414. code.DisplayIdx,
  415. strings.Repeat("-", int(code.Indent)),
  416. code.Op,
  417. code.Idx/uintptrSize,
  418. code.ElemIdx/uintptrSize,
  419. length,
  420. )
  421. }
  422. func (c *Opcode) dumpMapHead(code *Opcode) string {
  423. return fmt.Sprintf(
  424. `[%03d]%s%s ([idx:%d])`,
  425. code.DisplayIdx,
  426. strings.Repeat("-", int(code.Indent)),
  427. code.Op,
  428. code.Idx/uintptrSize,
  429. )
  430. }
  431. func (c *Opcode) dumpMapEnd(code *Opcode) string {
  432. return fmt.Sprintf(
  433. `[%03d]%s%s ([idx:%d])`,
  434. code.DisplayIdx,
  435. strings.Repeat("-", int(code.Indent)),
  436. code.Op,
  437. code.Idx/uintptrSize,
  438. )
  439. }
  440. func (c *Opcode) dumpElem(code *Opcode) string {
  441. var length uint32
  442. if code.Op.CodeType() == CodeArrayElem {
  443. length = code.Length
  444. } else {
  445. length = code.Length / uintptrSize
  446. }
  447. return fmt.Sprintf(
  448. `[%03d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`,
  449. code.DisplayIdx,
  450. strings.Repeat("-", int(code.Indent)),
  451. code.Op,
  452. code.Idx/uintptrSize,
  453. code.ElemIdx/uintptrSize,
  454. length,
  455. code.Size,
  456. )
  457. }
  458. func (c *Opcode) dumpField(code *Opcode) string {
  459. return fmt.Sprintf(
  460. `[%03d]%s%s ([idx:%d][key:%s][offset:%d])`,
  461. code.DisplayIdx,
  462. strings.Repeat("-", int(code.Indent)),
  463. code.Op,
  464. code.Idx/uintptrSize,
  465. code.DisplayKey,
  466. code.Offset,
  467. )
  468. }
  469. func (c *Opcode) dumpKey(code *Opcode) string {
  470. return fmt.Sprintf(
  471. `[%03d]%s%s ([idx:%d])`,
  472. code.DisplayIdx,
  473. strings.Repeat("-", int(code.Indent)),
  474. code.Op,
  475. code.Idx/uintptrSize,
  476. )
  477. }
  478. func (c *Opcode) dumpValue(code *Opcode) string {
  479. return fmt.Sprintf(
  480. `[%03d]%s%s ([idx:%d])`,
  481. code.DisplayIdx,
  482. strings.Repeat("-", int(code.Indent)),
  483. code.Op,
  484. code.Idx/uintptrSize,
  485. )
  486. }
  487. func (c *Opcode) Dump() string {
  488. codes := []string{}
  489. for code := c; !code.IsEnd(); {
  490. switch code.Op.CodeType() {
  491. case CodeSliceHead:
  492. codes = append(codes, c.dumpHead(code))
  493. code = code.Next
  494. case CodeMapHead:
  495. codes = append(codes, c.dumpMapHead(code))
  496. code = code.Next
  497. case CodeArrayElem, CodeSliceElem:
  498. codes = append(codes, c.dumpElem(code))
  499. code = code.End
  500. case CodeMapKey:
  501. codes = append(codes, c.dumpKey(code))
  502. code = code.End
  503. case CodeMapValue:
  504. codes = append(codes, c.dumpValue(code))
  505. code = code.Next
  506. case CodeMapEnd:
  507. codes = append(codes, c.dumpMapEnd(code))
  508. code = code.Next
  509. case CodeStructField:
  510. codes = append(codes, c.dumpField(code))
  511. code = code.Next
  512. case CodeStructEnd:
  513. codes = append(codes, c.dumpField(code))
  514. code = code.Next
  515. default:
  516. codes = append(codes, fmt.Sprintf(
  517. "[%03d]%s%s ([idx:%d])",
  518. code.DisplayIdx,
  519. strings.Repeat("-", int(code.Indent)),
  520. code.Op,
  521. code.Idx/uintptrSize,
  522. ))
  523. code = code.Next
  524. }
  525. }
  526. return strings.Join(codes, "\n")
  527. }
  528. func (c *Opcode) DumpDOT() string {
  529. type edge struct {
  530. from, to *Opcode
  531. label string
  532. weight int
  533. }
  534. var edges []edge
  535. b := &bytes.Buffer{}
  536. fmt.Fprintf(b, "digraph \"%p\" {\n", c.Type)
  537. fmt.Fprintln(b, "mclimit=1.5;\nrankdir=TD;\nordering=out;\nnode[shape=box];")
  538. for code := c; !code.IsEnd(); {
  539. label := code.Op.String()
  540. fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, label)
  541. if p := code.Next; p != nil {
  542. edges = append(edges, edge{
  543. from: code,
  544. to: p,
  545. label: "Next",
  546. weight: 10,
  547. })
  548. }
  549. if p := code.NextField; p != nil {
  550. edges = append(edges, edge{
  551. from: code,
  552. to: p,
  553. label: "NextField",
  554. weight: 2,
  555. })
  556. }
  557. if p := code.End; p != nil {
  558. edges = append(edges, edge{
  559. from: code,
  560. to: p,
  561. label: "End",
  562. weight: 1,
  563. })
  564. }
  565. if p := code.Jmp; p != nil {
  566. edges = append(edges, edge{
  567. from: code,
  568. to: p.Code,
  569. label: "Jmp",
  570. weight: 1,
  571. })
  572. }
  573. switch code.Op.CodeType() {
  574. case CodeSliceHead:
  575. code = code.Next
  576. case CodeMapHead:
  577. code = code.Next
  578. case CodeArrayElem, CodeSliceElem:
  579. code = code.End
  580. case CodeMapKey:
  581. code = code.End
  582. case CodeMapValue:
  583. code = code.Next
  584. case CodeMapEnd:
  585. code = code.Next
  586. case CodeStructField:
  587. code = code.Next
  588. case CodeStructEnd:
  589. code = code.Next
  590. default:
  591. code = code.Next
  592. }
  593. if code.IsEnd() {
  594. fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, code.Op.String())
  595. }
  596. }
  597. sort.Slice(edges, func(i, j int) bool {
  598. return edges[i].to.DisplayIdx < edges[j].to.DisplayIdx
  599. })
  600. for _, e := range edges {
  601. fmt.Fprintf(b, "\"%p\" -> \"%p\" [label=%q][weight=%d];\n", e.from, e.to, e.label, e.weight)
  602. }
  603. fmt.Fprint(b, "}")
  604. return b.String()
  605. }
  606. func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
  607. idx := opcodeOffset(ctx.ptrIndex)
  608. ctx.incPtrIndex()
  609. elemIdx := opcodeOffset(ctx.ptrIndex)
  610. ctx.incPtrIndex()
  611. length := opcodeOffset(ctx.ptrIndex)
  612. return &Opcode{
  613. Op: OpSlice,
  614. Type: typ,
  615. Idx: idx,
  616. DisplayIdx: ctx.opcodeIndex,
  617. ElemIdx: elemIdx,
  618. Length: length,
  619. Indent: ctx.indent,
  620. }
  621. }
  622. func newSliceElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, size uintptr) *Opcode {
  623. return &Opcode{
  624. Op: OpSliceElem,
  625. Type: typ,
  626. Idx: head.Idx,
  627. DisplayIdx: ctx.opcodeIndex,
  628. ElemIdx: head.ElemIdx,
  629. Length: head.Length,
  630. Indent: ctx.indent,
  631. Size: uint32(size),
  632. }
  633. }
  634. func newArrayHeaderCode(ctx *compileContext, typ *runtime.Type, alen int) *Opcode {
  635. idx := opcodeOffset(ctx.ptrIndex)
  636. ctx.incPtrIndex()
  637. elemIdx := opcodeOffset(ctx.ptrIndex)
  638. return &Opcode{
  639. Op: OpArray,
  640. Type: typ,
  641. Idx: idx,
  642. DisplayIdx: ctx.opcodeIndex,
  643. ElemIdx: elemIdx,
  644. Indent: ctx.indent,
  645. Length: uint32(alen),
  646. }
  647. }
  648. func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, length int, size uintptr) *Opcode {
  649. return &Opcode{
  650. Op: OpArrayElem,
  651. Type: typ,
  652. Idx: head.Idx,
  653. DisplayIdx: ctx.opcodeIndex,
  654. ElemIdx: head.ElemIdx,
  655. Length: uint32(length),
  656. Indent: ctx.indent,
  657. Size: uint32(size),
  658. }
  659. }
  660. func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
  661. idx := opcodeOffset(ctx.ptrIndex)
  662. ctx.incPtrIndex()
  663. return &Opcode{
  664. Op: OpMap,
  665. Type: typ,
  666. Idx: idx,
  667. DisplayIdx: ctx.opcodeIndex,
  668. Indent: ctx.indent,
  669. }
  670. }
  671. func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
  672. return &Opcode{
  673. Op: OpMapKey,
  674. Type: typ,
  675. Idx: head.Idx,
  676. DisplayIdx: ctx.opcodeIndex,
  677. Indent: ctx.indent,
  678. }
  679. }
  680. func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
  681. return &Opcode{
  682. Op: OpMapValue,
  683. Type: typ,
  684. Idx: head.Idx,
  685. DisplayIdx: ctx.opcodeIndex,
  686. Indent: ctx.indent,
  687. }
  688. }
  689. func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode {
  690. return &Opcode{
  691. Op: OpMapEnd,
  692. Type: typ,
  693. Idx: head.Idx,
  694. DisplayIdx: ctx.opcodeIndex,
  695. Indent: ctx.indent,
  696. Next: newEndOp(ctx, typ),
  697. }
  698. }
  699. func newRecursiveCode(ctx *compileContext, typ *runtime.Type, jmp *CompiledCode) *Opcode {
  700. return &Opcode{
  701. Op: OpRecursive,
  702. Type: typ,
  703. Idx: opcodeOffset(ctx.ptrIndex),
  704. Next: newEndOp(ctx, typ),
  705. DisplayIdx: ctx.opcodeIndex,
  706. Indent: ctx.indent,
  707. Jmp: jmp,
  708. }
  709. }