d3c93a05e4
[INTERPRETER] * NEW: Abort if a stack mismatch is detected after a JIT function has been called. [GB.JIT] * NEW: The GB_JIT_CC environment variable allows to define the C compiler that will generate the code. * OPT: Don't call the compiler through a shell anymore. * NEW: Support for clang. * BUG: Don't use the "," operator anymore to write JIT code. * BUG: Correctly free stack when leaving a function whereas we are still inside a GOSUB. * BUG: Declare all local variables and arguments as volatile as soon the function uses CATCH or FINALLY.
224 lines
5 KiB
Text
224 lines
5 KiB
Text
' Gambas module file
|
|
|
|
Export
|
|
Class __Jit
|
|
|
|
Property Read Time As Float
|
|
|
|
Private $fTime As Float
|
|
Private $sCompiler As String
|
|
Private $aFlags As String[]
|
|
Private $hProcess As Process
|
|
Private $sResult As String
|
|
Private $bDebug As Integer
|
|
|
|
Private Sub Init()
|
|
|
|
Dim sFlag As String
|
|
Dim sCompiler As String
|
|
|
|
sCompiler = Env["GB_JIT_CC"]
|
|
If Not sCompiler Then sCompiler = "gcc"
|
|
|
|
$sCompiler = System.Find(sCompiler)
|
|
If Not $sCompiler Then Error.Raise("Compiler not found")
|
|
|
|
sFlag = Env["GB_JIT_CFLAGS"]
|
|
If Not sFlag Then sFlag = "-O3"
|
|
|
|
$aFlags = Split(sFlag, " ")
|
|
|
|
End
|
|
|
|
Private Sub RunCompiler(sInput As String, Optional sOutput As String, sOption As String) As String
|
|
|
|
Dim aExec As String[]
|
|
'Dim I As Integer
|
|
|
|
aExec = [$sCompiler]
|
|
If sOption Then aExec.Insert(Split(sOption, " "))
|
|
aExec.Insert($aFlags)
|
|
aExec.Add(sInput)
|
|
If sOutput Then
|
|
aExec.Add("-o")
|
|
aExec.Add(sOutput)
|
|
Endif
|
|
|
|
' For I = 0 To aExec.Max
|
|
' aExec[I] = Shell$(aExec[I])
|
|
' Next
|
|
|
|
If $bDebug Then Error "gb.jit: run: "; aExec.Join(" ")
|
|
|
|
$sResult = ""
|
|
$hProcess = Exec aExec For Read As "Compiler"
|
|
$hProcess.Wait
|
|
'Shell aExec.Join(" ") & " 2>&1" To sResult
|
|
|
|
Return $sResult
|
|
|
|
End
|
|
|
|
Public Sub Compiler_Read()
|
|
|
|
Dim sData As String
|
|
|
|
sData = Read #$hProcess, -1024
|
|
$sResult &= sData
|
|
|
|
End
|
|
|
|
Public Sub Compile_Error(({Error}) As String)
|
|
|
|
$sResult &= {Error}
|
|
|
|
End
|
|
|
|
Public Sub _Compile(sArch As String) As String
|
|
|
|
Dim sFile As String
|
|
Dim sDir As String
|
|
Dim sName As String
|
|
Dim sPath As String
|
|
Dim hFile As File
|
|
Dim sResult As String
|
|
Dim sPathO As String
|
|
Dim sPathSO As String
|
|
Dim fTime As Float
|
|
|
|
fTime = Timer
|
|
|
|
Try $bDebug = CInt(Env["GB_JIT_DEBUG"])
|
|
|
|
If $bDebug Then Error "gb.jit: translating "; If(sArch, sArch, "project")
|
|
|
|
If Not $sCompiler Then Init
|
|
|
|
|
|
sName = sArch
|
|
If Not sName Then sName = "gb"
|
|
|
|
sDir = File.Dir(Temp$()) &/ "jit"
|
|
Try Mkdir sDir
|
|
|
|
sPath = sDir &/ "jit.h"
|
|
|
|
If Not Exist(sPath) Then
|
|
|
|
If $bDebug Then Error "gb.jit: generating header"
|
|
|
|
hFile = Open sPath For Output Create
|
|
|
|
Print #hFile, "#define NO_CONFIG_H"
|
|
|
|
Print #hFile, File.Load("gambas.h");
|
|
Print #hFile, File.Load("jit.h");
|
|
Print #hFile, File.Load("gb.jit.h");
|
|
|
|
Print #hFile, "GB_INTERFACE * GB_PTR;"
|
|
Print #hFile, "#define GB (*GB_PTR)"
|
|
Print #hFile, "JIT_INTERFACE * JIT_PTR;"
|
|
Print #hFile, "#define JIT (*JIT_PTR)"
|
|
|
|
Print #hFile, File.Load("gb_error_common.h");
|
|
|
|
Close #hFile
|
|
|
|
If $bDebug Then
|
|
Try Kill "/tmp/jit.h"
|
|
Copy sDir &/ "jit.h" To "/tmp/jit.h"
|
|
Endif
|
|
|
|
' 'Shell $sCompiler & " -fPIC " & Shell(sPath) To sResult
|
|
' sResult = RunCompiler(sPath,, "-fPIC")
|
|
' If Not Exist(sPath & ".gch") Then
|
|
' Error "gb.jit: error: unable to generate precompiled header"
|
|
' Error sResult
|
|
' Return
|
|
' Endif
|
|
'
|
|
' If $bDebug Then
|
|
' Try Kill "/tmp/" & File.Name(sPath)
|
|
' Copy sPath To "/tmp/" & File.Name(sPath)
|
|
' Try Kill "/tmp/" & File.Name(sPath & ".gch")
|
|
' Copy sPath & ".gch" To "/tmp/" & File.Name(sPath & ".gch")
|
|
' Endif
|
|
|
|
Endif
|
|
|
|
sPath = sDir &/ sName & ".c"
|
|
|
|
If $bDebug Then Error "gb.jit: generating "; sPath
|
|
|
|
hFile = Open sPath For Output Create
|
|
|
|
Print #hFile, "#include \"jit.h\""
|
|
Print #hFile
|
|
|
|
If sArch Then
|
|
sDir = "." &/ sArch
|
|
Else
|
|
sDir = "..."
|
|
Endif
|
|
|
|
For Each sFile In Dir(sDir &/ ".gambas")
|
|
ClassStat.Stat(sDir, sFile)
|
|
If Not ClassStat.HasFast Then Continue
|
|
sFile = ClassStat.Name
|
|
If $bDebug Then Error "gb.jit: translating class "; sFile
|
|
Print #hFile, __Jit.Translate(sFile, sArch)
|
|
Next
|
|
|
|
Close #hFile
|
|
|
|
If $bDebug Then
|
|
Try Kill "/tmp/" & File.Name(sPath)
|
|
Copy sPath To "/tmp/" & File.Name(sPath)
|
|
Endif
|
|
|
|
sPathO = File.SetExt(sPath, "o")
|
|
sPathSO = File.SetExt(sPath, "so")
|
|
|
|
If $bDebug Then Error "gb.jit: compiling to "; sPathO
|
|
|
|
'gcc -c -fPIC -o foo.o foo.c
|
|
'Exec [$sCompiler, "-c", "-fPIC", "-o", File.SetExt(sPath, "o"), sPath] To sResult
|
|
'Shell $sCompiler & " -c -fPIC " & sFlag & " -o " & Shell(sPathO) & " " & Shell(sPath) & " 2>&1" To sResult
|
|
sResult = RunCompiler(sPath, sPathSO, "-w -fPIC -shared -lm")
|
|
If Not Exist(sPathSO) Then
|
|
Error "gb.jit: error: unable to compile JIT code:"
|
|
Error sResult
|
|
Return
|
|
Endif
|
|
|
|
' If $bDebug Then Error "gb.jit: linking to "; sPathSO
|
|
'
|
|
' 'gcc -shared -o libfoo.so foo.o
|
|
' 'Exec [$sCompiler, "-shared", "-o", File.SetExt(sPath, "so"), File.SetExt(sPath, "o")] To sResult
|
|
' 'Shell $sCompiler & " -shared " & sFlag & " -lm -o " & Shell(sPathSO) & " " & Shell(sPathO) & " 2>&1" To sResult
|
|
' RunCompiler(sPathO, sPathSO, "-shared -lm")
|
|
' If Not Exist(sPathSO) Then
|
|
' Error "gb.jit: warning: unable to link JIT code:"
|
|
' Error sResult
|
|
' Return
|
|
' Endif
|
|
|
|
fTime = Timer - fTime
|
|
$fTime += fTime
|
|
|
|
If $bDebug Then Error "gb.jit: done in "; Format(fTime, "0.000"); "s"
|
|
|
|
' Shell "objdump -S " & Shell(sPathSO) To sResult
|
|
' Error sResult
|
|
|
|
|
|
|
|
Return sPathSO
|
|
|
|
End
|
|
|
|
Private Function Time_Read() As Float
|
|
|
|
Return $fTime
|
|
|
|
End
|