Skip to content

Commit

Permalink
enable vtable implementation for C++ and make it an experimental feat…
Browse files Browse the repository at this point in the history
…ure (#23004)

follow up #22991

- [x] turning it into an experimental feature

---------

Co-authored-by: Andreas Rumpf <[email protected]>
  • Loading branch information
ringabout and Araq authored Nov 30, 2023
1 parent 9140f8e commit b5f5b74
Show file tree
Hide file tree
Showing 15 changed files with 42 additions and 24 deletions.
2 changes: 1 addition & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on vtable by using `-d:nimPreviewVtables`. methods are confined in the same module where the type has been defined.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.

## Standard library additions and changes
Expand Down
22 changes: 15 additions & 7 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,13 @@ proc genDisplay(m: BModule; t: PType, depth: int): Rope =
result.add seqs[0]
result.add "}"

proc genVTable(seqs: seq[PSym]): string =
result = "{"
for i in 0..<seqs.len:
if i > 0: result.add ", "
result.add "(void *) " & seqs[i].loc.r
result.add "}"

proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
cgsym(m, "TNimTypeV2")
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
Expand Down Expand Up @@ -1714,18 +1721,19 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay])
addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)])

let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
if dispatchMethods.len > 0:
let vTablePointerName = getTempName(m)
m.s[cfsVars].addf("static void* $1[$2] = $3;$n", [vTablePointerName, rope(dispatchMethods.len), genVTable(dispatchMethods)])
for i in dispatchMethods:
genProcPrototype(m, i)
addf(typeEntry, "$1.vTable = $2;$n", [name, vTablePointerName])

m.s[cfsTypeInit3].add typeEntry

if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)

proc genVTable(seqs: seq[PSym]): string =
result = "{"
for i in 0..<seqs.len:
if i > 0: result.add ", "
result.add "(void *) " & seqs[i].loc.r
result.add "}"

proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
cgsym(m, "TNimTypeV2")
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
Expand Down
3 changes: 1 addition & 2 deletions compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2234,8 +2234,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
incl m.flags, objHasKidsValid
if optMultiMethods in m.g.config.globalOptions or
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or
not m.g.config.isDefined("nimPreviewVtables") or
m.g.config.backend == backendCpp or sfCompileToCpp in m.module.flags:
vtables notin m.g.config.features:
generateIfMethodDispatchers(graph, m.idgen)


Expand Down
2 changes: 1 addition & 1 deletion compiler/cgmeth.nim
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =

proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym = nil
if s.typ[1].owner.getModule != s.getModule and g.config.isDefined("nimPreviewVtables"):
if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"):
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")")
for i in 0..<g.methods.len:
Expand Down
2 changes: 2 additions & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,5 @@ proc initDefines*(symbols: StringTableRef) =

defineSymbol("nimHasCastExtendedVm")
defineSymbol("nimHasWarnStdPrefix")

defineSymbol("nimHasVtables")
5 changes: 4 additions & 1 deletion compiler/nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
define:nimPreviewVtables
define:nimPreviewNonVarDestructor
threads:off

Expand Down Expand Up @@ -58,3 +57,7 @@ define:useStdoutAsStdmsg
warning[StdPrefix]:on
warningAsError[StdPrefix]:on
@end

@if nimHasVtables:
experimental:vtables
@end
3 changes: 2 additions & 1 deletion compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ type
flexibleOptionalParams,
strictDefs,
strictCaseObjects,
inferGenericTypes
inferGenericTypes,
vtables

LegacyFeature* = enum
allowSemcheckedAstModification,
Expand Down
4 changes: 1 addition & 3 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -861,9 +861,7 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
trackStmt(c, c.module, result, isTopLevel = true)
if optMultiMethods notin c.config.globalOptions and
c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
c.config.isDefined("nimPreviewVtables") and
c.config.backend != backendCpp and
sfCompileToCpp notin c.module.flags:
Feature.vtables in c.config.features:
sortVTableDispatchers(c.graph)

if sfMainModule in c.module.flags:
Expand Down
7 changes: 5 additions & 2 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1606,8 +1606,11 @@ when not defined(js) and defined(nimV2):
traceImpl: pointer
typeInfoV1: pointer # for backwards compat, usually nil
flags: int
when defined(nimPreviewVtables) and not defined(cpp):
vTable: UncheckedArray[pointer] # vtable for types
when defined(gcDestructors):
when defined(cpp):
vTable: ptr UncheckedArray[pointer] # vtable for types
else:
vTable: UncheckedArray[pointer] # vtable for types
PNimTypeV2 = ptr TNimTypeV2

proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
Expand Down
2 changes: 1 addition & 1 deletion lib/system/arc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ template tearDownForeignThreadGc* =
proc isObjDisplayCheck(source: PNimTypeV2, targetDepth: int16, token: uint32): bool {.compilerRtl, inl.} =
result = targetDepth <= source.depth and source.display[targetDepth] == token

when defined(nimPreviewVtables) and not defined(cpp):
when defined(gcDestructors):
proc nimGetVTable(p: pointer, index: int): pointer
{.compilerRtl, inline, raises: [].} =
result = cast[ptr PNimTypeV2](p).vTable[index]
3 changes: 1 addition & 2 deletions tests/config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,4 @@ switch("define", "nimPreviewNonVarDestructor")

switch("warningAserror", "UnnamedBreak")
switch("legacy", "verboseTypeMismatch")
switch("define", "nimPreviewVtables")

switch("experimental", "vtables")
2 changes: 1 addition & 1 deletion tests/generics/tobjecttyperel.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
matrix: "-u:nimPreviewVtables"
matrix: "-d:nimInternalNonVtablesTesting"
output: '''(peel: 0, color: 15)
(color: 15)
17
Expand Down
2 changes: 1 addition & 1 deletion tests/method/tgeneric_methods.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
matrix: "--mm:arc --multimethods:on -u:nimPreviewVtables; --mm:refc --multimethods:on -u:nimPreviewVtables"
matrix: "--mm:arc --multimethods:on -d:nimInternalNonVtablesTesting; --mm:refc --multimethods:on -d:nimInternalNonVtablesTesting"
output: '''wow2
X 1
X 3'''
Expand Down
2 changes: 1 addition & 1 deletion tests/method/tmethods_old.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
matrix: "--mm:arc -u:nimPreviewVtables"
matrix: "--mm:arc -d:nimInternalNonVtablesTesting"
output: '''
do nothing
'''
Expand Down
5 changes: 5 additions & 0 deletions tests/method/tvtable.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
discard """
targets: "c cpp"
"""

type FooBase = ref object of RootObj
dummy: int
type Foo = ref object of FooBase
Expand All @@ -15,5 +19,6 @@ method bar(x: Foo2, a: float32) =
proc test() =
var x = new Foo2
x.bar(2.3)
doAssert x.value <= 2.3

test()

0 comments on commit b5f5b74

Please sign in to comment.