preparations for proper memmap'ed files
This commit is contained in:
parent
ded7f6a6d5
commit
235bd1c474
4 changed files with 105 additions and 32 deletions
|
|
@ -68,12 +68,16 @@
|
||||||
# sym
|
# sym
|
||||||
# )
|
# )
|
||||||
#
|
#
|
||||||
|
# The data section MUST be the last section of the file, because processing
|
||||||
|
# stops immediately after ``DATA(`` and the rest is only loaded on demand
|
||||||
|
# by using mem'mapped a file.
|
||||||
|
#
|
||||||
# We now also do index compression, because an index always needs to be read.
|
# We now also do index compression, because an index always needs to be read.
|
||||||
#
|
#
|
||||||
|
|
||||||
import
|
import
|
||||||
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
|
||||||
ropes, idents, crc, idgen, rodutils
|
ropes, idents, crc, idgen, rodutils, memfiles
|
||||||
|
|
||||||
type
|
type
|
||||||
TReasonForRecompile* = enum
|
TReasonForRecompile* = enum
|
||||||
|
|
@ -104,26 +108,28 @@ type
|
||||||
offset*: int # readers use this
|
offset*: int # readers use this
|
||||||
|
|
||||||
TRodReader* = object of TObject
|
TRodReader* = object of TObject
|
||||||
pos*: int # position; used for parsing
|
pos: int # position; used for parsing
|
||||||
s*: string # the whole file in memory; XXX mmap this!
|
s: cstring # mmap'ed file contents
|
||||||
options*: TOptions
|
options: TOptions
|
||||||
reason*: TReasonForRecompile
|
reason: TReasonForRecompile
|
||||||
modDeps*: TStringSeq
|
modDeps: TStringSeq
|
||||||
files*: TStringSeq
|
files: TStringSeq
|
||||||
dataIdx*: int # offset of start of data section
|
dataIdx: int # offset of start of data section
|
||||||
convertersIdx*: int # offset of start of converters section
|
convertersIdx: int # offset of start of converters section
|
||||||
initIdx*, interfIdx*, compilerProcsIdx*, cgenIdx*: int
|
initIdx, interfIdx, compilerProcsIdx: int
|
||||||
filename*: string
|
filename: string
|
||||||
index*, imports*: TIndex
|
index, imports: TIndex
|
||||||
readerIndex*: int
|
readerIndex: int
|
||||||
line*: int # only used for debugging, but is always in the code
|
line: int # only used for debugging, but is always in the code
|
||||||
moduleID*: int
|
moduleID: int
|
||||||
syms*: TIdTable # already processed symbols
|
syms: TIdTable # already processed symbols
|
||||||
|
memfile: TMemFile # unfortunately there is no point in time where we
|
||||||
|
# can close this! XXX
|
||||||
|
|
||||||
PRodReader* = ref TRodReader
|
PRodReader* = ref TRodReader
|
||||||
|
|
||||||
const
|
const
|
||||||
FileVersion* = "1019" # modify this if the rod-format changes!
|
FileVersion* = "1022" # modify this if the rod-format changes!
|
||||||
|
|
||||||
var rodCompilerprocs*: TStrTable
|
var rodCompilerprocs*: TStrTable
|
||||||
|
|
||||||
|
|
@ -541,14 +547,11 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
of "DATA":
|
of "DATA":
|
||||||
r.dataIdx = r.pos + 2 # "(\10"
|
r.dataIdx = r.pos + 2 # "(\10"
|
||||||
# We do not read the DATA section here! We read the needed objects on
|
# We do not read the DATA section here! We read the needed objects on
|
||||||
# demand.
|
# demand. And the DATA section comes last in the file, so we stop here:
|
||||||
skipSection(r)
|
break
|
||||||
of "INIT":
|
of "INIT":
|
||||||
r.initIdx = r.pos + 2 # "(\10"
|
r.initIdx = r.pos + 2 # "(\10"
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
of "CGEN":
|
|
||||||
r.cgenIdx = r.pos + 2
|
|
||||||
skipSection(r)
|
|
||||||
else:
|
else:
|
||||||
MsgWriteln("skipping section: " & $r.pos)
|
MsgWriteln("skipping section: " & $r.pos)
|
||||||
skipSection(r)
|
skipSection(r)
|
||||||
|
|
@ -556,6 +559,12 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
|
|
||||||
|
|
||||||
|
proc startsWith(buf: cstring, token: string, pos = 0): bool =
|
||||||
|
var s = 0
|
||||||
|
while s < token.len and buf[pos+s] == token[s]: inc s
|
||||||
|
result = s == token.len
|
||||||
|
|
||||||
proc newRodReader(modfilename: string, crc: TCrc32,
|
proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
readerIndex: int): PRodReader =
|
readerIndex: int): PRodReader =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -568,7 +577,10 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
r.readerIndex = readerIndex
|
r.readerIndex = readerIndex
|
||||||
r.filename = modfilename
|
r.filename = modfilename
|
||||||
InitIdTable(r.syms)
|
InitIdTable(r.syms)
|
||||||
r.s = readFile(modfilename)
|
if not open(r.memFile, modfilename): return nil
|
||||||
|
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
|
||||||
|
# is save:
|
||||||
|
r.s = cast[cstring](r.memFile.mem)
|
||||||
if startsWith(r.s, "NIM:"):
|
if startsWith(r.s, "NIM:"):
|
||||||
initIITable(r.index.tab)
|
initIITable(r.index.tab)
|
||||||
initIITable(r.imports.tab) # looks like a ROD file
|
initIITable(r.imports.tab) # looks like a ROD file
|
||||||
|
|
|
||||||
|
|
@ -282,15 +282,20 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
result.add('@')
|
result.add('@')
|
||||||
encodeVInt(ord(s.magic), result)
|
encodeVInt(ord(s.magic), result)
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
var codeAst: PNode = nil
|
# we used to attempt to save space here by only storing a dummy AST if
|
||||||
if not astNeeded(s):
|
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
||||||
codeAst = s.ast.sons[codePos]
|
# make that unfeasible nowadays:
|
||||||
# ugly hack to not store the AST:
|
|
||||||
s.ast.sons[codePos] = ast.emptyNode
|
|
||||||
encodeNode(w, s.info, s.ast, result)
|
encodeNode(w, s.info, s.ast, result)
|
||||||
if codeAst != nil:
|
when false:
|
||||||
# resore the AST:
|
var codeAst: PNode = nil
|
||||||
s.ast.sons[codePos] = codeAst
|
if not astNeeded(s):
|
||||||
|
codeAst = s.ast.sons[codePos]
|
||||||
|
# ugly hack to not store the AST:
|
||||||
|
s.ast.sons[codePos] = ast.emptyNode
|
||||||
|
encodeNode(w, s.info, s.ast, result)
|
||||||
|
if codeAst != nil:
|
||||||
|
# resore the AST:
|
||||||
|
s.ast.sons[codePos] = codeAst
|
||||||
if s.options != w.options:
|
if s.options != w.options:
|
||||||
result.add('!')
|
result.add('!')
|
||||||
encodeVInt(cast[int32](s.options), result)
|
encodeVInt(cast[int32](s.options), result)
|
||||||
|
|
@ -458,6 +463,9 @@ proc writeRod(w: PRodWriter) =
|
||||||
f.write("DATA(" & rodNL)
|
f.write("DATA(" & rodNL)
|
||||||
f.write(w.data)
|
f.write(w.data)
|
||||||
f.write(')' & rodNL)
|
f.write(')' & rodNL)
|
||||||
|
# write trailing zero which is necessary because we use memory mapped files
|
||||||
|
# for reading:
|
||||||
|
f.write("\0")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
#echo "interf: ", w.interf.len
|
#echo "interf: ", w.interf.len
|
||||||
|
|
|
||||||
51
lib/pure/memfiles.nim
Normal file
51
lib/pure/memfiles.nim
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module provides support for `memory mapped files`:idx:
|
||||||
|
## (Posix's `mmap`:idx:) on the different operating systems.
|
||||||
|
## XXX Currently it is implemented with Nimrod's
|
||||||
|
## basic IO facilities and does not use any platform specific code!
|
||||||
|
## Oh and currently only ``fmRead`` is supported...
|
||||||
|
|
||||||
|
type
|
||||||
|
TMemFile* = object {.pure.}
|
||||||
|
file: TFile
|
||||||
|
buffer: pointer
|
||||||
|
fileLen: int
|
||||||
|
|
||||||
|
proc open*(f: var TMemFile, filename: string, mode: TFileMode = fmRead): bool =
|
||||||
|
## open a memory mapped file `f`. Returns true for success.
|
||||||
|
assert mode == fmRead
|
||||||
|
result = open(f.file, filename, mode)
|
||||||
|
|
||||||
|
var len = getFileSize(f.file)
|
||||||
|
if len < high(int):
|
||||||
|
f.fileLen = int(len)
|
||||||
|
f.buffer = alloc(f.fileLen)
|
||||||
|
if readBuffer(f.file, f.buffer, f.fileLen) != f.fileLen:
|
||||||
|
raise newException(EIO, "error while reading from file")
|
||||||
|
else:
|
||||||
|
raise newException(EIO, "file too big to fit in memory")
|
||||||
|
|
||||||
|
proc close*(f: var TMemFile) =
|
||||||
|
## closes the memory mapped file `f`. All changes are written back to the
|
||||||
|
## file system, if `f` was opened with write access.
|
||||||
|
dealloc(f.buffer)
|
||||||
|
close(f.file)
|
||||||
|
|
||||||
|
proc mem*(f: var TMemFile): pointer {.inline.} =
|
||||||
|
## retrives a pointer to the memory mapped file `f`. The pointer can be
|
||||||
|
## used directly to change the contents of the file, if `f` was opened
|
||||||
|
## with write access.
|
||||||
|
result = f.buffer
|
||||||
|
|
||||||
|
proc size*(f: var TMemFile): int {.inline.} =
|
||||||
|
## retrives the size of the memory mapped file `f`.
|
||||||
|
result = f.fileLen
|
||||||
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -11,7 +11,7 @@ Version 0.8.14
|
||||||
- thread local vs. global raiseHook()
|
- thread local vs. global raiseHook()
|
||||||
- make pegs support a compile-time option and make c2nim use regexes instead
|
- make pegs support a compile-time option and make c2nim use regexes instead
|
||||||
per default
|
per default
|
||||||
|
- implement lib/pure/memfiles properly
|
||||||
|
|
||||||
incremental compilation
|
incremental compilation
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
@ -20,6 +20,8 @@ incremental compilation
|
||||||
- write test cases: needs test script support
|
- write test cases: needs test script support
|
||||||
- test thread var
|
- test thread var
|
||||||
- test method generation
|
- test method generation
|
||||||
|
- test type converters
|
||||||
|
- test init sections
|
||||||
- test DLL interfacing!
|
- test DLL interfacing!
|
||||||
- hallo.rod is missing initial statements: feature or bug?
|
- hallo.rod is missing initial statements: feature or bug?
|
||||||
- fix remaining bugs
|
- fix remaining bugs
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue