Skip to content

Commit

Permalink
Merge pull request #84 from ferus-web/fixes-83
Browse files Browse the repository at this point in the history
Fix vector allocations, don't hold pointers to atoms, hold atoms instead
  • Loading branch information
xTrayambak authored Feb 17, 2025
2 parents 52de6a5 + 9ed90cc commit ce8d37d
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 43 deletions.
2 changes: 1 addition & 1 deletion bali.nimble
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Package

version = "0.6.1"
version = "0.6.2"
author = "xTrayambak"
description = "The Bali JavaScript Engine"
license = "GPL3"
Expand Down
38 changes: 24 additions & 14 deletions src/bali/grammar/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -283,26 +283,22 @@ proc parseTypeofCall*(parser: Parser): Option[PositionedArguments] =

some(args)

#[ proc parseTable*(parser: Parser): Option[JSValue] =
proc parseTable*(parser: Parser): Option[MAtom] =
# We are assuming that the starting curly bracket (`{`) has been consumed.
debug "parser: parsing table"
if parser.tokenizer.eof:
parser.error Other, "expected expression, got EOF"

var
table: Table[JSValue, JSValue]
currentKey: JSValue
table: seq[(MAtom, MAtom)]
currentKey: MAtom

metLCurly = false
metRCurly = false
state = TableParsingState.Key

while not parser.tokenizer.eof and not metLCurly:
while not parser.tokenizer.eof and not metRCurly:
let token = parser.tokenizer.next()

if token.kind == TokenKind.LCurly:
metLCurly = true
break
case state
of TableParsingState.Key:
let key =
Expand All @@ -313,10 +309,15 @@ proc parseTypeofCall*(parser: Parser): Option[PositionedArguments] =
stackStr(token.str)
of TokenKind.Number:
&parser.parseAtom(token)
of TokenKind.RCurly:
metRCurly = true
break
stackNull()
of TokenKind.Whitespace: continue; stackNull()
else:
parser.error UnexpectedToken, $token.kind & " (expected identifier or string)"

table[key] = null()
table.add((key, stackNull()))
currentKey = key
state = TableParsingState.Colon
of TableParsingState.Colon:
Expand All @@ -330,16 +331,17 @@ proc parseTypeofCall*(parser: Parser): Option[PositionedArguments] =
case token.kind
of TokenKind.Identifier:
parser.error Other, "identifiers are not supported in maps yet"
of TokenKind.Whitespace: discard
else:
let atom = parser.parseAtom(token)
if !atom:
parser.error UnexpectedToken, "expected value, got " & $token.kind

table[currentKey] = &atom
table &= (currentKey, &atom)
state = TableParsingState.Key

if not metLCurly:
parser.error Other, "property list must be ended by }" ]#
if not metRCurly:
parser.error Other, "property list must be ended by }"

proc parseArray*(parser: Parser): Option[MAtom] =
# We are assuming that the starting bracket (`[`) has been consumed.
Expand Down Expand Up @@ -654,6 +656,9 @@ proc parseDeclaration*(
of TokenKind.LBracket:
atom = parser.parseArray()
break
of TokenKind.LCurly:
atom = parser.parseTable()
break
else:
parser.error UnexpectedToken, $tok.kind

Expand Down Expand Up @@ -811,6 +816,8 @@ proc parseAtom*(parser: Parser, token: Token): Option[MAtom] =
return some stackBoolean(false)
of TokenKind.LBracket:
return parser.parseArray()
of TokenKind.LCurly:
return parser.parseTable()
else:
return
# parser.error UnexpectedToken, "expected value, got " & $token.kind & " instead."
Expand Down Expand Up @@ -1324,8 +1331,11 @@ proc parseStatement*(parser: Parser): Option[Statement] =
of TokenKind.InvalidShebang:
parser.error Other, "shebang cannot be preceded by whitespace"
of TokenKind.Break:
if token.containsUnicodeEsc:
parser.error Other, "keyword `break` cannot contain unicode escape(s)."

return some breakStmt()
of TokenKind.String, TokenKind.Number, TokenKind.Null, TokenKind.LBracket:
of TokenKind.String, TokenKind.Number, TokenKind.Null, TokenKind.LBracket, TokenKind.LCurly:
return some waste(&parser.parseAtom(token))
of TokenKind.Comment:
if token.multiline:
Expand Down
4 changes: 2 additions & 2 deletions src/bali/runtime/abstract/to_string.nim
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ proc ToString*(runtime: Runtime, value: JSValue): string =
var buffer = "["

# FIXME: not spec compliant!
for i, item in value.sequence:
buffer &= runtime.ToString(item)
for i, _ in value.sequence:
buffer &= runtime.ToString(value.sequence[i].addr)
if i < value.sequence.len - 1:
buffer &= ", "

Expand Down
7 changes: 6 additions & 1 deletion src/bali/runtime/atom_helpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ proc wrap*[T: object](obj: T): JSValue =
mObj

proc wrap*(val: seq[JSValue]): JSValue =
sequence(val)
var atoms = newSeq[MAtom](val.len)

for i, value in val:
atoms[i] = val[i][]

sequence(move(atoms))

proc `[]=`*[T: not JSValue](atom: var JSValue, name: string, value: T) =
atom[name] = wrap(value)
Expand Down
15 changes: 13 additions & 2 deletions src/bali/runtime/bridge.nim
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,25 @@ proc defineConstructor*(runtime: Runtime, name: string, fn: NativeFunction) {.in
ValueError, "Attempt to define constructor for unknown type: " & name
)

template ret*(atom: MAtom) =
template ret*(atom: JSValue) =
## Shorthand for:
## ..code-block:: Nim
## runtime.vm.registers.retVal = some(atom)
## return
runtime.vm.registers.retVal = some(atom)
return

template dangerRet*(atom: sink MAtom) =
{.warning: "Don't use `dangerRet(MAtom)`, use `ret(JSValue)` instead. This is dangerous!".}
## Return an atom.
## **WARNING**: The atom **MUST** be allocated on the heap, otherwise you
## will be rewarded with undefined behaviour and undiagnosable crashes.
## The functions `str`, `integer`, `floating`, `obj`, and any other atom creation
## functions that don't have "stack" in their name allocate on the heap alongside
## `createObjFromType`
runtime.vm.registers.retVal = some(atom.addr)
return

template ret*[T](value: T) =
## Shorthand for:
## ..code-block:: Nim
Expand All @@ -241,7 +252,7 @@ proc registerType*[T](runtime: Runtime, name: string, prototype: typedesc[T]) =

for fname, fatom in prototype().fieldPairs:
when fatom is JSValue:
jsType.members[fname] = initAtomOrFunction[NativeFunction](null())
jsType.members[fname] = initAtomOrFunction[NativeFunction](undefined())
else:
jsType.members[fname] = initAtomOrFunction[NativeFunction](fatom.wrap())

Expand Down
6 changes: 3 additions & 3 deletions src/bali/runtime/interpreter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1155,11 +1155,11 @@ proc generateInternalIR*(runtime: Runtime) =
)

let idx = &(&index).getInt()
let vec = (&atom).sequence
var vec = (&atom).sequence
if idx < 0 or idx > vec.len - 1:
ret undefined()

ret vec[idx] # TODO: add indexing for tables/object fields
ret vec[idx].addr # TODO: add indexing for tables/object fields
,
)
runtime.ir.call("BALI_INDEX_INTERNAL")
Expand Down Expand Up @@ -1333,7 +1333,7 @@ proc run*(runtime: Runtime) =
runtime.vm.setEntryPoint("outer")

for error in runtime.ast.errors:
runtime.syntaxError(error, if runtime.opts.test262: 0 else: 1)
runtime.syntaxError($error, if runtime.opts.test262: 0 else: 1)

if runtime.ast.doNotEvaluate and runtime.opts.test262:
debug "runtime: `doNotEvaluate` is set to `true` in Test262 mode - skipping execution."
Expand Down
6 changes: 3 additions & 3 deletions src/bali/runtime/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ proc markLocal*(
inc runtime.addrIdx

proc loadIRAtom*(runtime: Runtime, atom: MAtom): uint =
debug "codegen: loading atom with kind: " & $atom.kind
case atom.kind
of Integer:
runtime.ir.loadInt(runtime.addrIdx, atom)
Expand Down Expand Up @@ -230,11 +231,10 @@ proc loadIRAtom*(runtime: Runtime, atom: MAtom): uint =
of Sequence:
runtime.ir.loadList(runtime.addrIdx)
result = runtime.addrIdx

for item in atom.sequence:
assert(item != nil)
inc runtime.addrIdx
let idx = runtime.loadIRAtom(item[])
let idx = runtime.loadIRAtom(item)
runtime.ir.appendList(result, idx)
else:
unreachable
Expand Down
19 changes: 8 additions & 11 deletions src/bali/runtime/vm/atom.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type
of Integer:
integer*: int
of Sequence:
sequence*: seq[JSValue]
sequence*: seq[MAtom]
lCap*: Option[int]
lHomogenous*: bool = false
of UnsignedInt:
Expand Down Expand Up @@ -109,6 +109,8 @@ proc `=copy`*(dest: var MAtom, src: MAtom) =
proc hash*(atom: MAtom): Hash =
var h: Hash = 0

h = h !& atom.kind.int

case atom.kind
of String:
h = h !& atom.str.hash()
Expand Down Expand Up @@ -237,7 +239,7 @@ proc getFloat*(atom: MAtom | JSValue): Option[float64] {.inline.} =
if atom.kind == Float:
return some atom.floatVal

proc getSequence*(atom: MAtom | JSValue): Option[seq[JSValue]] {.inline.} =
proc getSequence*(atom: MAtom | JSValue): Option[seq[MAtom]] {.inline.} =
if atom.kind == Sequence:
return some(atom.sequence)

Expand All @@ -262,7 +264,8 @@ func stackStr*(s: string): MAtom =
## This is used by the parser.
MAtom(kind: String, str: s)

proc ident*(ident: string, inRuntime: bool = false): JSValue {.inline.} =
proc ident*(ident: string): JSValue {.inline.} =
assert off
var mem = newJSValue(Ident)
mem.ident = ident

Expand Down Expand Up @@ -344,20 +347,14 @@ proc null*(inRuntime: bool = false): JSValue {.inline.} =
func stackNull*(): MAtom =
MAtom(kind: Null)

proc sequence*(s: seq[JSValue], inRuntime: bool = false): JSValue {.inline.} =
proc sequence*(s: seq[MAtom]): JSValue {.inline.} =
var mem = newJSValue(Sequence)
mem.sequence = s

ensureMove(mem)

func stackSequence*(s: seq[MAtom]): MAtom {.inline.} =
var sequence = newSeq[JSValue](s.len)
var s = deepCopy(s)

for i, _ in s:
sequence[i] = s[i].addr

MAtom(kind: Sequence, sequence: sequence)
MAtom(kind: Sequence, sequence: s)

proc bigint*(value: SomeSignedInt | string): JSValue =
var mem = newJSValue(BigInteger)
Expand Down
2 changes: 1 addition & 1 deletion src/bali/runtime/vm/runtime/pulsar/interpreter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ proc execute*(interpreter: var PulsarInterpreter, op: var Operation) =
inc interpreter.currIndex
return # TODO: type errors

list.sequence.add(&source)
list.sequence.add((&source)[])

interpreter.stack[pos] = list
inc interpreter.currIndex
Expand Down
10 changes: 5 additions & 5 deletions src/bali/stdlib/json.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ proc convertJsonNodeToAtom*(node: JsonNode): JSValue =
elif node.kind == JNull:
return null(true)
elif node.kind == JBool:
return boolean(node.getBool(), true)
return boolean(node.getBool())
elif node.kind == JArray:
var arr = sequence(@[], true)
var arr = sequence(@[])
for elem in node.getElems():
arr.sequence &= elem.convertJsonNodeToAtom()
arr.sequence &= elem.convertJsonNodeToAtom()[]

return arr
elif node.kind == JFloat:
return floating(node.getFloat(), true)
return floating(node.getFloat())
elif node.kind == JObject:
var jObj = obj()

Expand All @@ -42,7 +42,7 @@ proc convertJsonNodeToAtom*(node: JsonNode): JSValue =

type JSON = object

proc atomToJsonNode*(atom: JSValue): JsonNode =
proc atomToJsonNode*(atom: JSValue | MAtom): JsonNode =
if atom.kind == Integer:
return newJInt(&atom.getInt())
elif atom.kind == UnsignedInt:
Expand Down

0 comments on commit ce8d37d

Please sign in to comment.