object_template.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. package goja
  2. import (
  3. "fmt"
  4. "github.com/dop251/goja/unistring"
  5. "math"
  6. "reflect"
  7. "sort"
  8. )
  9. type templatePropFactory func(*Runtime) Value
  10. type objectTemplate struct {
  11. propNames []unistring.String
  12. props map[unistring.String]templatePropFactory
  13. symProps map[*Symbol]templatePropFactory
  14. symPropNames []*Symbol
  15. protoFactory func(*Runtime) *Object
  16. }
  17. type templatedObject struct {
  18. baseObject
  19. tmpl *objectTemplate
  20. protoMaterialised bool
  21. }
  22. type templatedFuncObject struct {
  23. templatedObject
  24. f func(FunctionCall) Value
  25. construct func(args []Value, newTarget *Object) *Object
  26. }
  27. // This type exists because Array.prototype is supposed to be an array itself and I could not find
  28. // a different way of implementing it without either introducing another layer of interfaces or hoisting
  29. // the templates to baseObject both of which would have had a negative effect on the performance.
  30. // The implementation is as simple as possible and is not optimised in any way, but I very much doubt anybody
  31. // uses Array.prototype as an actual array.
  32. type templatedArrayObject struct {
  33. templatedObject
  34. }
  35. func newObjectTemplate() *objectTemplate {
  36. return &objectTemplate{
  37. props: make(map[unistring.String]templatePropFactory),
  38. }
  39. }
  40. func (t *objectTemplate) putStr(name unistring.String, f templatePropFactory) {
  41. t.props[name] = f
  42. t.propNames = append(t.propNames, name)
  43. }
  44. func (t *objectTemplate) putSym(s *Symbol, f templatePropFactory) {
  45. if t.symProps == nil {
  46. t.symProps = make(map[*Symbol]templatePropFactory)
  47. }
  48. t.symProps[s] = f
  49. t.symPropNames = append(t.symPropNames, s)
  50. }
  51. func (r *Runtime) newTemplatedObject(tmpl *objectTemplate, obj *Object) *templatedObject {
  52. if obj == nil {
  53. obj = &Object{runtime: r}
  54. }
  55. o := &templatedObject{
  56. baseObject: baseObject{
  57. class: classObject,
  58. val: obj,
  59. extensible: true,
  60. },
  61. tmpl: tmpl,
  62. }
  63. obj.self = o
  64. o.init()
  65. return o
  66. }
  67. func (o *templatedObject) materialiseProto() {
  68. if !o.protoMaterialised {
  69. if o.tmpl.protoFactory != nil {
  70. o.prototype = o.tmpl.protoFactory(o.val.runtime)
  71. }
  72. o.protoMaterialised = true
  73. }
  74. }
  75. func (o *templatedObject) getStr(name unistring.String, receiver Value) Value {
  76. ownProp := o.getOwnPropStr(name)
  77. if ownProp == nil {
  78. o.materialiseProto()
  79. }
  80. return o.getStrWithOwnProp(ownProp, name, receiver)
  81. }
  82. func (o *templatedObject) getSym(s *Symbol, receiver Value) Value {
  83. ownProp := o.getOwnPropSym(s)
  84. if ownProp == nil {
  85. o.materialiseProto()
  86. }
  87. return o.getWithOwnProp(ownProp, s, receiver)
  88. }
  89. func (o *templatedObject) getOwnPropStr(p unistring.String) Value {
  90. if v, exists := o.values[p]; exists {
  91. return v
  92. }
  93. if f := o.tmpl.props[p]; f != nil {
  94. v := f(o.val.runtime)
  95. o.values[p] = v
  96. return v
  97. }
  98. return nil
  99. }
  100. func (o *templatedObject) materialiseSymbols() {
  101. if o.symValues == nil {
  102. o.symValues = newOrderedMap(nil)
  103. for _, p := range o.tmpl.symPropNames {
  104. o.symValues.set(p, o.tmpl.symProps[p](o.val.runtime))
  105. }
  106. }
  107. }
  108. func (o *templatedObject) getOwnPropSym(s *Symbol) Value {
  109. if o.symValues == nil && o.tmpl.symProps[s] == nil {
  110. return nil
  111. }
  112. o.materialiseSymbols()
  113. return o.baseObject.getOwnPropSym(s)
  114. }
  115. func (o *templatedObject) materialisePropNames() {
  116. if o.propNames == nil {
  117. o.propNames = append(([]unistring.String)(nil), o.tmpl.propNames...)
  118. }
  119. }
  120. func (o *templatedObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
  121. existing := o.getOwnPropStr(p) // materialise property (in case it's an accessor)
  122. if existing == nil {
  123. o.materialiseProto()
  124. o.materialisePropNames()
  125. }
  126. return o.baseObject.setOwnStr(p, v, throw)
  127. }
  128. func (o *templatedObject) setOwnSym(name *Symbol, val Value, throw bool) bool {
  129. o.materialiseSymbols()
  130. o.materialiseProto()
  131. return o.baseObject.setOwnSym(name, val, throw)
  132. }
  133. func (o *templatedObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  134. ownProp := o.getOwnPropStr(name)
  135. if ownProp == nil {
  136. o.materialiseProto()
  137. }
  138. return o._setForeignStr(name, ownProp, val, receiver, throw)
  139. }
  140. func (o *templatedObject) proto() *Object {
  141. o.materialiseProto()
  142. return o.prototype
  143. }
  144. func (o *templatedObject) setProto(proto *Object, throw bool) bool {
  145. o.protoMaterialised = true
  146. ret := o.baseObject.setProto(proto, throw)
  147. if ret {
  148. o.protoMaterialised = true
  149. }
  150. return ret
  151. }
  152. func (o *templatedObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) {
  153. return o.setForeignStr(name.string(), val, receiver, throw)
  154. }
  155. func (o *templatedObject) setForeignSym(name *Symbol, val, receiver Value, throw bool) (bool, bool) {
  156. o.materialiseProto()
  157. o.materialiseSymbols()
  158. return o.baseObject.setForeignSym(name, val, receiver, throw)
  159. }
  160. func (o *templatedObject) hasPropertyStr(name unistring.String) bool {
  161. if o.val.self.hasOwnPropertyStr(name) {
  162. return true
  163. }
  164. o.materialiseProto()
  165. if o.prototype != nil {
  166. return o.prototype.self.hasPropertyStr(name)
  167. }
  168. return false
  169. }
  170. func (o *templatedObject) hasPropertySym(s *Symbol) bool {
  171. if o.hasOwnPropertySym(s) {
  172. return true
  173. }
  174. o.materialiseProto()
  175. if o.prototype != nil {
  176. return o.prototype.self.hasPropertySym(s)
  177. }
  178. return false
  179. }
  180. func (o *templatedObject) hasOwnPropertyStr(name unistring.String) bool {
  181. if v, exists := o.values[name]; exists {
  182. return v != nil
  183. }
  184. _, exists := o.tmpl.props[name]
  185. return exists
  186. }
  187. func (o *templatedObject) hasOwnPropertySym(s *Symbol) bool {
  188. if o.symValues != nil {
  189. return o.symValues.has(s)
  190. }
  191. _, exists := o.tmpl.symProps[s]
  192. return exists
  193. }
  194. func (o *templatedObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  195. existingVal := o.getOwnPropStr(name)
  196. if v, ok := o._defineOwnProperty(name, existingVal, descr, throw); ok {
  197. o.values[name] = v
  198. if existingVal == nil {
  199. o.materialisePropNames()
  200. names := copyNamesIfNeeded(o.propNames, 1)
  201. o.propNames = append(names, name)
  202. }
  203. return true
  204. }
  205. return false
  206. }
  207. func (o *templatedObject) defineOwnPropertySym(s *Symbol, descr PropertyDescriptor, throw bool) bool {
  208. o.materialiseSymbols()
  209. return o.baseObject.defineOwnPropertySym(s, descr, throw)
  210. }
  211. func (o *templatedObject) deleteStr(name unistring.String, throw bool) bool {
  212. if val := o.getOwnPropStr(name); val != nil {
  213. if !o.checkDelete(name, val, throw) {
  214. return false
  215. }
  216. o.materialisePropNames()
  217. o._delete(name)
  218. if _, exists := o.tmpl.props[name]; exists {
  219. o.values[name] = nil // white hole
  220. }
  221. }
  222. return true
  223. }
  224. func (o *templatedObject) deleteSym(s *Symbol, throw bool) bool {
  225. o.materialiseSymbols()
  226. return o.baseObject.deleteSym(s, throw)
  227. }
  228. func (o *templatedObject) materialiseProps() {
  229. for name, f := range o.tmpl.props {
  230. if _, exists := o.values[name]; !exists {
  231. o.values[name] = f(o.val.runtime)
  232. }
  233. }
  234. o.materialisePropNames()
  235. }
  236. func (o *templatedObject) iterateStringKeys() iterNextFunc {
  237. o.materialiseProps()
  238. return o.baseObject.iterateStringKeys()
  239. }
  240. func (o *templatedObject) iterateSymbols() iterNextFunc {
  241. o.materialiseSymbols()
  242. return o.baseObject.iterateSymbols()
  243. }
  244. func (o *templatedObject) stringKeys(all bool, keys []Value) []Value {
  245. if all {
  246. o.materialisePropNames()
  247. } else {
  248. o.materialiseProps()
  249. }
  250. return o.baseObject.stringKeys(all, keys)
  251. }
  252. func (o *templatedObject) symbols(all bool, accum []Value) []Value {
  253. o.materialiseSymbols()
  254. return o.baseObject.symbols(all, accum)
  255. }
  256. func (o *templatedObject) keys(all bool, accum []Value) []Value {
  257. return o.symbols(all, o.stringKeys(all, accum))
  258. }
  259. func (r *Runtime) newTemplatedFuncObject(tmpl *objectTemplate, obj *Object, f func(FunctionCall) Value, ctor func([]Value, *Object) *Object) *templatedFuncObject {
  260. if obj == nil {
  261. obj = &Object{runtime: r}
  262. }
  263. o := &templatedFuncObject{
  264. templatedObject: templatedObject{
  265. baseObject: baseObject{
  266. class: classFunction,
  267. val: obj,
  268. extensible: true,
  269. },
  270. tmpl: tmpl,
  271. },
  272. f: f,
  273. construct: ctor,
  274. }
  275. obj.self = o
  276. o.init()
  277. return o
  278. }
  279. func (f *templatedFuncObject) source() String {
  280. return newStringValue(fmt.Sprintf("function %s() { [native code] }", nilSafe(f.getStr("name", nil)).toString()))
  281. }
  282. func (f *templatedFuncObject) export(*objectExportCtx) interface{} {
  283. return f.f
  284. }
  285. func (f *templatedFuncObject) assertCallable() (func(FunctionCall) Value, bool) {
  286. if f.f != nil {
  287. return f.f, true
  288. }
  289. return nil, false
  290. }
  291. func (f *templatedFuncObject) vmCall(vm *vm, n int) {
  292. var nf nativeFuncObject
  293. nf.f = f.f
  294. nf.vmCall(vm, n)
  295. }
  296. func (f *templatedFuncObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
  297. return f.construct
  298. }
  299. func (f *templatedFuncObject) exportType() reflect.Type {
  300. return reflectTypeFunc
  301. }
  302. func (f *templatedFuncObject) typeOf() String {
  303. return stringFunction
  304. }
  305. func (f *templatedFuncObject) hasInstance(v Value) bool {
  306. return hasInstance(f.val, v)
  307. }
  308. func (r *Runtime) newTemplatedArrayObject(tmpl *objectTemplate, obj *Object) *templatedArrayObject {
  309. if obj == nil {
  310. obj = &Object{runtime: r}
  311. }
  312. o := &templatedArrayObject{
  313. templatedObject: templatedObject{
  314. baseObject: baseObject{
  315. class: classArray,
  316. val: obj,
  317. extensible: true,
  318. },
  319. tmpl: tmpl,
  320. },
  321. }
  322. obj.self = o
  323. o.init()
  324. return o
  325. }
  326. func (a *templatedArrayObject) getLenProp() *valueProperty {
  327. lenProp, _ := a.getOwnPropStr("length").(*valueProperty)
  328. if lenProp == nil {
  329. panic(a.val.runtime.NewTypeError("missing length property"))
  330. }
  331. return lenProp
  332. }
  333. func (a *templatedArrayObject) _setOwnIdx(idx uint32) {
  334. lenProp := a.getLenProp()
  335. l := uint32(lenProp.value.ToInteger())
  336. if idx >= l {
  337. lenProp.value = intToValue(int64(idx) + 1)
  338. }
  339. }
  340. func (a *templatedArrayObject) setLength(l uint32, throw bool) bool {
  341. lenProp := a.getLenProp()
  342. oldLen := uint32(lenProp.value.ToInteger())
  343. if l == oldLen {
  344. return true
  345. }
  346. if !lenProp.writable {
  347. a.val.runtime.typeErrorResult(throw, "length is not writable")
  348. return false
  349. }
  350. ret := true
  351. if l < oldLen {
  352. a.materialisePropNames()
  353. a.fixPropOrder()
  354. i := sort.Search(a.idxPropCount, func(idx int) bool {
  355. return strToArrayIdx(a.propNames[idx]) >= l
  356. })
  357. for j := a.idxPropCount - 1; j >= i; j-- {
  358. if !a.deleteStr(a.propNames[j], false) {
  359. l = strToArrayIdx(a.propNames[j]) + 1
  360. ret = false
  361. break
  362. }
  363. }
  364. }
  365. lenProp.value = intToValue(int64(l))
  366. return ret
  367. }
  368. func (a *templatedArrayObject) setOwnStr(name unistring.String, value Value, throw bool) bool {
  369. if name == "length" {
  370. return a.setLength(a.val.runtime.toLengthUint32(value), throw)
  371. }
  372. if !a.templatedObject.setOwnStr(name, value, throw) {
  373. return false
  374. }
  375. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  376. a._setOwnIdx(idx)
  377. }
  378. return true
  379. }
  380. func (a *templatedArrayObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
  381. if !a.templatedObject.setOwnStr(p.string(), v, throw) {
  382. return false
  383. }
  384. if idx := toIdx(p); idx != math.MaxUint32 {
  385. a._setOwnIdx(idx)
  386. }
  387. return true
  388. }
  389. func (a *templatedArrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  390. if name == "length" {
  391. return a.val.runtime.defineArrayLength(a.getLenProp(), descr, a.setLength, throw)
  392. }
  393. if !a.templatedObject.defineOwnPropertyStr(name, descr, throw) {
  394. return false
  395. }
  396. if idx := strToArrayIdx(name); idx != math.MaxUint32 {
  397. a._setOwnIdx(idx)
  398. }
  399. return true
  400. }
  401. func (a *templatedArrayObject) defineOwnPropertyIdx(p valueInt, desc PropertyDescriptor, throw bool) bool {
  402. if !a.templatedObject.defineOwnPropertyStr(p.string(), desc, throw) {
  403. return false
  404. }
  405. if idx := toIdx(p); idx != math.MaxUint32 {
  406. a._setOwnIdx(idx)
  407. }
  408. return true
  409. }