Skip to content

Commit

Permalink
<feature> RAII - new metamethods __init, __move, __dtor that enable u…
Browse files Browse the repository at this point in the history
…ser defined automatic memory management.
  • Loading branch information
hiemstar committed May 9, 2024
1 parent b5e9d53 commit cbeba09
Showing 1 changed file with 104 additions and 10 deletions.
114 changes: 104 additions & 10 deletions src/terralib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2863,6 +2863,56 @@ function typecheck(topexp,luaenv,simultaneousdefinitions)
return anchor:aserror()
end

--check if metamethods.__init is implemented
local function checkinit(anchor, reciever)
if reciever:is "allocvar" then
reciever = newobject(anchor,T.var,reciever.name,reciever.symbol):setlvalue(true):withtype(reciever.type)
end
if reciever:is "var" then
local mt = reciever.type.metamethods
if mt and mt.__init then
return checkmethodwithreciever(anchor, true, "__init", reciever, terralib.newlist(), "statement")
end
end
end

--check if metamethods.__move is implemented
local function checkmove(anchor, reciever)
if reciever:is "var" then
--check if metamethod __move is implemented
local mt = reciever.type.metamethods
if mt and mt.__move then
return checkmethodwithreciever(anchor, true, "__move", reciever, terralib.newlist(), "expression")
end
end
--if no metamethod __move is implemented or if not a 'var' just return
return reciever
end

--check if metamethods.__dtor is implemented
local function checkdtors(anchor, lhs)
local function checkdtor(reciever)
if reciever:is "allocvar" then
reciever = newobject(anchor,T.var,reciever.name,reciever.symbol):setlvalue(true):withtype(reciever.type)
end
if reciever:is "var" then
local mt = reciever.type.metamethods
if mt and mt.__dtor then
return checkmethodwithreciever(anchor, true, "__dtor", reciever, terralib.newlist(), "statement")
end
end
end
--add all implemented destructor calls
local dtors = terralib.newlist{}
for i,e in ipairs(lhs) do
local dtor = checkdtor(e)
if dtor then
dtors:insert(dtor)
end
end
return dtors
end

--functions that handle the checking of expressions
local function checkluaexpression(e,location)
local value = {}
Expand Down Expand Up @@ -3236,7 +3286,12 @@ function typecheck(topexp,luaenv,simultaneousdefinitions)
if s:is "block" then
return checkblock(s)
elseif s:is "returnstat" then
return s:copy { expression = checkexp(s.expression)}
local values = terralib.newlist{}
for i,e in ipairs(s.expression.expressions) do
local v = checkexp(e)
values:insert(checkmove(s,v))
end
return s:copy { expression = createlet(s, terralib.newlist(), values, false)}
elseif s:is "label" or s:is "gotostat" then
local ss = checklabel(s.label)
return copyobject(s, { label = ss })
Expand Down Expand Up @@ -3309,13 +3364,52 @@ function typecheck(topexp,luaenv,simultaneousdefinitions)
elseif s:is "defvar" then
local rhs = s.hasinit and checkexpressions(s.initializers)
local lhs = checkformalparameterlist(s.variables, not s.hasinit)
local res = s.hasinit and createassignment(s,lhs,rhs)
or createstatementlist(s,lhs)
return res
--if there are initializers, create assignment and check if
--any destructors are implemented
if s.hasinit then
--initializers
local res = createassignment(s,lhs,rhs)
--destructor calls
local dtors = checkdtors(s, lhs)
--returned statements:
local stmts = terralib.newlist{ res }
--add deferred calls to the destructors
for i,dtor in ipairs(dtors) do
stmts:insert(newobject(s, T.defer, dtor))
end
return createstatementlist(s,stmts)
else
--if no initializers, check for initializer metamethods and
--return statement list and initializer statements
local stmts = createstatementlist(s,lhs)
--if there is no initializer then apply metamethods.__init if
--defined and add expression to 'res'
for i,e in ipairs(lhs) do
local init = checkinit(s, e)
if init then
stmts.expressions:insert(init)
end
end
return stmts
end
elseif s:is "assignment" then
local rhs = checkexpressions(s.rhs)
local lhs = checkexpressions(s.lhs,"lexpression")
return createassignment(s,lhs,rhs)
local res = createassignment(s,lhs,rhs)
--check for implemented destructor calls
local dtors = checkdtors(s, lhs)
--returned statements:
local stmts = terralib.newlist()
--(1) first apply destructor calls to free any heap memory of 'lhs' objects
stmts:insertall(dtors)
--(2) actual assignment
stmts:insert(res)
--(3) add deferred calls to the destructors
for i,dtor in ipairs(dtors) do
stmts:insert(newobject(s, T.defer, dtor))
end
--return statements
return createstatementlist(s, stmts)
elseif s:is "apply" then
return checkapply(s,"statement")
elseif s:is "method" then
Expand Down Expand Up @@ -3508,11 +3602,11 @@ function terra.includecstring(code,cargs,target)
args:insert(path)
end
-- Obey the SDKROOT variable on macOS to match Clang behavior.
local sdkroot = os.getenv("SDKROOT")
if sdkroot then
args:insert("-isysroot")
args:insert(sdkroot)
end
--local sdkroot = os.getenv("SDKROOT")
--if sdkroot then
-- args:insert("-isysroot")
-- args:insert(sdkroot)
--end
-- Set GNU C version to match value set by Clang: https://github.com/llvm/llvm-project/blob/f77c948d56b09b839262e258af5c6ad701e5b168/clang/lib/Driver/ToolChains/Clang.cpp#L5750-L5753
if ffi.os ~= "Windows" and terralib.llvm_version >= 100 then
args:insert("-fgnuc-version=4.2.1")
Expand Down

0 comments on commit cbeba09

Please sign in to comment.