runtime_v2.nim 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #[
  2. In this new runtime we simplify the object layouts a bit: The runtime type
  3. information is only accessed for the objects that have it and it's always
  4. at offset 0 then. The ``ref`` object header is independent from the
  5. runtime type and only contains a reference count.
  6. Object subtyping is checked via the generated 'name'. This should have
  7. comparable overhead to the old pointer chasing approach but has the benefit
  8. that it works across DLL boundaries.
  9. The generated name is a concatenation of the object names in the hierarchy
  10. so that a subtype check becomes a substring check. For example::
  11. type
  12. ObjectA = object of RootObj
  13. ObjectB = object of ObjectA
  14. ObjectA's ``name`` is "|ObjectA|RootObj|".
  15. ObjectB's ``name`` is "|ObjectB|ObjectA|RootObj|".
  16. Now to check for ``x of ObjectB`` we need to check
  17. for ``x.typ.name.hasSubstring("|ObjectB|")``. In the actual implementation,
  18. however, we could also use a
  19. hash of ``package & "." & module & "." & name`` to save space.
  20. ]#
  21. type
  22. RefHeader = object
  23. rc: int # the object header is now a single RC field.
  24. # we could remove it in non-debug builds but this seems
  25. # unwise.
  26. template `+!`(p: pointer, s: int): pointer =
  27. cast[pointer](cast[int](p) +% s)
  28. template `-!`(p: pointer, s: int): pointer =
  29. cast[pointer](cast[int](p) -% s)
  30. template head(p: pointer): ptr RefHeader =
  31. cast[ptr RefHeader](cast[int](p) -% sizeof(RefHeader))
  32. var allocs*: int
  33. proc nimNewObj(size: int): pointer {.compilerRtl.} =
  34. let s = size + sizeof(RefHeader)
  35. when defined(nimscript):
  36. discard
  37. elif defined(useMalloc):
  38. var orig = c_malloc(s)
  39. nimZeroMem(orig, s)
  40. result = orig +! sizeof(RefHeader)
  41. else:
  42. result = alloc0(s) +! sizeof(RefHeader)
  43. inc allocs
  44. proc nimDecWeakRef(p: pointer) {.compilerRtl.} =
  45. dec head(p).rc
  46. proc nimIncWeakRef(p: pointer) {.compilerRtl.} =
  47. inc head(p).rc
  48. proc nimRawDispose(p: pointer) {.compilerRtl.} =
  49. when not defined(nimscript):
  50. if head(p).rc != 0:
  51. cstderr.rawWrite "[FATAL] dangling references exist\n"
  52. quit 1
  53. when defined(useMalloc):
  54. c_free(p -! sizeof(RefHeader))
  55. else:
  56. dealloc(p -! sizeof(RefHeader))
  57. if allocs > 0:
  58. dec allocs
  59. else:
  60. cstderr.rawWrite "[FATAL] unpaired dealloc\n"
  61. quit 1
  62. template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x))
  63. #proc dispose*(x: pointer) = nimRawDispose(x)
  64. proc nimDestroyAndDispose(p: pointer) {.compilerRtl.} =
  65. let d = cast[ptr PNimType](p)[].destructor
  66. if d != nil: cast[DestructorProc](d)(p)
  67. when false:
  68. cstderr.rawWrite cast[ptr PNimType](p)[].name
  69. cstderr.rawWrite "\n"
  70. if d == nil:
  71. cstderr.rawWrite "bah, nil\n"
  72. else:
  73. cstderr.rawWrite "has destructor!\n"
  74. nimRawDispose(p)
  75. proc isObj(obj: PNimType, subclass: cstring): bool {.compilerproc.} =
  76. proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
  77. result = strstr(obj.name, subclass) != nil
  78. proc chckObj(obj: PNimType, subclass: cstring) {.compilerproc.} =
  79. # checks if obj is of type subclass:
  80. if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion")