Skip to content

Commit

Permalink
Python + YYBCVM now working
Browse files Browse the repository at this point in the history
  • Loading branch information
UltimatePea committed Oct 19, 2024
1 parent a0496cd commit a172337
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 29 deletions.
65 changes: 60 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
"version": "0.2.0",
"configurations": [
{
"name": "./yybcvm/build/native/vm.exe",
"name": "./yybcvm/build/native/vm.exe [attach]",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/yybcvm/build/native/vm.exe",
"args": [
"./.yybuild.nosync/py/output.yybcb",
"豫言编译器/入口。豫",
"--do-not-load-cache",
"-vv",
],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
Expand All @@ -38,14 +39,65 @@
// "ignoreFailures": false
// },
{
// "text": "set output-radix 16"
"text": "settings set target.output-radix 16"
"text": "target remote | /usr/local/libexec/valgrind/../../bin/vgdb --pid=164540"

},
{
"text": "set output-radix 16"
// "text": "settings set target.output-radix 16"
},
{
"text": "set disable-randomization off"
}
],
"MIMode": "lldb",
// "MIMode": "lldb",
// "miDebuggerPath": "/usr/bin/lldb"
},
{
"name": "./yybcvm/build/native/vm.exe",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/yybcvm/build/native/vm.exe",
"args": [
"./.yybuild.nosync/py/output.yybcb",
"yylib/标准库/语言核心/内建类型。豫",
// "performance-investigation/matrix-multiply/matrix-multiply.yuyan",
// "豫言编译器/入口。豫",
// "--do-not-load-cache",
"-v",
],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [
// {
// "name": "YY_GC_DEBUG_FLAG",
// "value": "1"
// },
// {
// "name": "YY_DEBUG_FLAG",
// "value": "1"
// },
// {
// "name": "YY_GC_INITIAL_HEAP_SIZE_MB",
// "value": "32"
// }
],
"externalConsole": false,
"setupCommands": [
// {
// "text": "handle SIGSEGV noprint nostop pass",
// "description": "ingore libgc related errors",
// "ignoreFailures": false
// },
{
"text": "set output-radix 16"
// "text": "settings set target.output-radix 16"
},
{
"text": "set disable-randomization off"
}
],
// "MIMode": "lldb",
// "miDebuggerPath": "/usr/bin/lldb"
},
{
Expand All @@ -56,7 +108,10 @@
"console": "integratedTerminal",
"cwd": "${workspaceFolder}",
"args": [
"./.yybuild.nosync/py/output_bc.pickle"
"./.yybuild.nosync/py/output_bc.pickle",
// "performance-investigation/matrix-multiply/matrix-multiply.yuyan",
"yylib/标准库/语言核心/内建类型。豫",
"-v",
]

},
Expand Down
1 change: 0 additions & 1 deletion py-interpreter/closure_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ def closure_convert_top_level(inputs: Dict[str, Abt]) -> Dict[str, Abt]:
[closure_convert(N(NT_MultiArgLam(1), [construct_binding("top_except_str", lambda x: N(NT_ExternalCall("yyTopExceptHandler"), [FreeVar(x)]))]), "__top_exception_handler", ALL_CLOSURE_FUNCS )]),
init_ast])

assert "entryMain" not in ALL_CLOSURE_FUNCS
ALL_CLOSURE_FUNCS["entryMain"] = N(NT_MultiArgLam(0), [init_ast])

return ALL_CLOSURE_FUNCS
11 changes: 8 additions & 3 deletions py-interpreter/pass_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
# the decorator should take file name as an argument
# e.g. @cached_pass("recursion_rewrite") def recursion_rewrite(ast: Dict[str, Abt]) -> Dict[str, Abt]: ...

INPUT_PATH_KEY=""

def get_artifact_path(name):
return ".yybuild.nosync/py/" +INPUT_PATH_KEY + "/"+ name

def cached_pass(name):
def decorator(func):
def wrapper(ast):
if os.path.exists(".yybuild.nosync/py/" + name + ".lamir"):
return ir_to_asts(open(".yybuild.nosync/py/" + name + ".lamir", "r").read(), ".yybuild.nosync/py/" + name + ".lamir")
if os.path.exists(get_artifact_path(name + ".lamir")):
return ir_to_asts(open(get_artifact_path(name + ".lamir"), "r").read(), ".yybuild.nosync/py/" + name + ".lamir")
else:
result = func(ast)
ir = asts_to_ir(result)
with open(".yybuild.nosync/py/" + name + ".lamir", "w") as f:
with open(get_artifact_path(name + ".lamir"), "w") as f:
f.write(ir)
return result
return wrapper
Expand Down
3 changes: 3 additions & 0 deletions py-interpreter/yuyan_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def file_path_to_key(path):
# if path ends with 。豫, remove it
if path.endswith("。豫"):
path = path[:-len("。豫")]
# if path ends with .yuyan, remove it
if path.endswith(".yuyan"):
path = path[:-len(".yuyan")]
return path

def do_load_deps(path):
Expand Down
16 changes: 9 additions & 7 deletions py-interpreter/yybc_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from anf_convert import *
from recursion_rewrite import *
from yybc_ast import *
import pass_utils
import struct
from tqdm import tqdm
print("recursion limit", sys.getrecursionlimit())
Expand Down Expand Up @@ -104,7 +105,7 @@ def compile_immediate(params: List[str], locals: List[str], immediate: Abt, stri
case N(NT_ExternalCall(name), args):
return flatten([compile_immediate(params, locals, arg, strings) for arg in reversed(args)]) + [ExternalCall(strings.index(name), len(args))]
case N(NT_CallCCRet(), [func, arg]):
return compile_immediate(params, locals, func, strings) + compile_immediate(params, locals, arg, strings) + [ExternalCall(strings.index("yyCallCCRet"), 2)]
return compile_immediate(params, locals, arg, strings) + compile_immediate(params, locals, func, strings) + [ExternalCall(strings.index("yyCallCCRet"), 2)]
case N(NT_GlobalFuncRef(name), []):
return [FuncRef(strings.index(name))]
case N(NT_WriteGlobalFileRef(name), [arg]):
Expand Down Expand Up @@ -283,33 +284,34 @@ def do_compile_funcs(func_dict):
print("File refs not updated", [name for name in read_file_refs if name not in update_file_refs])
file_refs = update_file_refs
strings = [n for n in all_external_call_names] + file_refs + list(func_dict.keys())
if os.path.exists("./.yybuild.nosync/py/output_bc.pickle"):
if os.path.exists(pass_utils.get_artifact_path("/output_bc.pickle")):
print("Loading from yybc pickle")
cache = pickle.load(open("./.yybuild.nosync/py/output_bc.pickle", "rb"))
cache = pickle.load(open(pass_utils.get_artifact_path("/output_bc.pickle"), "rb"))
strings = cache["strings"]
instrs = cache["instrs"]
else:
instrs = []
for name, func in tqdm(func_dict.items(), desc="Compiling to YYBC"):
instrs.extend(do_compile_func(name, func, strings))
pickle.dump({"strings": strings, "instrs": instrs}, open("./.yybuild.nosync/py/output_bc.pickle", "wb"))
with open("./.yybuild.nosync/py/output.yybcir", "w") as f:
pickle.dump({"strings": strings, "instrs": instrs}, open(pass_utils.get_artifact_path("/output_bc.pickle"), "wb"))
with open(pass_utils.get_artifact_path("/output.yybcir"), "w") as f:
f.write(f"EXTERNCALLS {len(all_external_call_names)} FILES {len(file_refs)} FUNCS {len(func_dict)} STRINGS {len(strings)}\n")
f.write("\n".join([inst_to_text(instr) for instr in instrs]) + "\n")
f.write("\n".join([f"STRING {i} {json.dumps(s)}" for i, s in enumerate(strings)]) + "\n")
write_binary_file("./.yybuild.nosync/py/output.yybcb", instrs, strings, all_external_call_names, file_refs, func_dict)
write_binary_file(pass_utils.get_artifact_path("/output.yybcb"), instrs, strings, all_external_call_names, file_refs, func_dict)
# it is expected that VM calculates the index into the file list by subtracting the number of builtins





if __name__ == "__main__":
os.makedirs(".yybuild.nosync/py/", exist_ok=True)
if len(sys.argv) < 2:
print("Usage: python compiler.py <path_no_extension> <args>")
sys.exit(1)
path = sys.argv[1]
pass_utils.INPUT_PATH_KEY = file_path_to_key(path)
os.makedirs(pass_utils.get_artifact_path(""), exist_ok=True)
asts = do_load_files(path)
converted = closure_convert_top_level(asts)
rewritten = recursion_rewrite_top_level(converted)
Expand Down
42 changes: 39 additions & 3 deletions py-interpreter/yybc_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
CurrentExceptionHandler = []

def do_external_call(name: str, args: List[Any]):
global CurrentExceptionHandler
global CurrentExceptionHandler, pc, stack_ptr, op
match name, args:
case "yyRunningOnWindows", []:
return os.name == "nt"
Expand Down Expand Up @@ -94,6 +94,22 @@ def do_external_call(name: str, args: List[Any]):
exit(code)
case "yyIntGtTest", [a, b]:
return a > b
case "yy_豫言字符串获取JSON字符串", [s, startIdx]:
assert s[startIdx] == "\""
endIdx = startIdx + 1
while s[endIdx] != "\"":
if s[endIdx] == "\\":
endIdx += 2
else:
endIdx += 1
length = endIdx - startIdx + 1
return [s[startIdx+1:endIdx], length]
case "yyCallCC", []:
return stack_ptr
case "yyCallCCRet", [ptr_addr, val]:
pc = stack[ptr_addr - 1]
stack_ptr = stack[ptr_addr - 2]
return val
case _:
raise ValueError(f"Unknown external call {name} on {args}")

Expand All @@ -115,8 +131,12 @@ def start_interpret():
while True:
inst_count += 1
instr = instrs[pc]
# print(inst_count, end=": ")
# print(inst_to_text(instr))
if inst_count % 10000 == 0:
print(inst_count)
if inst_count > 19290852:
print(inst_count, end=": ")
print(inst_to_text(instr))

pc += 1
if inst_count >= 43520:
a = 1
Expand All @@ -127,6 +147,7 @@ def start_interpret():
op.append(stack[stack_ptr + idx])
case StoreLocal(idx):
val = op.pop()
assert len(op) == 0
stack[stack_ptr + idx] = val
case ReadTuple():
idx = op.pop()
Expand All @@ -136,13 +157,16 @@ def start_interpret():
new_val = op.pop()
idx = op.pop()
tuple = op.pop()
assert len(op) == 0
tuple[idx] = new_val
case MakeTuple(length):
vals = [op.pop() for _ in range(length)]
assert len(op) == 0
op.append(list(reversed(vals)))
case CallFuncPtr(nargs, locals):
func = op.pop()
args = [op.pop() for _ in range(nargs)]
assert len(op) == 0
for i in range(nargs):
stack[stack_ptr + locals + i] = args[-i-1]
stack[stack_ptr + locals + nargs] = stack_ptr
Expand All @@ -152,40 +176,52 @@ def start_interpret():
pc = functions[func]
case Return():
val = op.pop()
assert len(op) == 0
pc = stack[stack_ptr - 1]
stack_ptr = stack[stack_ptr - 2]
op.append(val)
case ExternalCall(name, nargs):
args = [op.pop() for _ in range(nargs)]
assert len(op) == 0
call_name = strings[name]
op.append(do_external_call(call_name, args))
case IntConst(val):
op.append(val)
case StringConst(val):
assert len(op) == 0
op.append(strings[val])
case BranchIfFalse(target):
val = op.pop()
assert len(op) == 0
if not val:
pc = labels[target]
case Branch(target):
assert len(op) == 0
pc = labels[target]
case Label(val):
assert len(op) == 0
pass
case BeginFunc(name):
assert len(op) == 0
pass
case EndFunc(name):
raise ValueError("EndFunc")
case PopOpStack():
raise NotImplementedError()
case BoolConst(val):
assert len(op) == 0
op.append(val)
case UnitConst():
assert len(op) == 0
op.append([])
case FuncRef(idx):
assert len(op) == 0
op.append(idx)
case UpdateFileRef(idx):
files[idx] = op.pop()
assert len(op) == 0
case FileRef(idx):
assert len(op) == 0
op.append(files[idx])
case _:
raise ValueError("Unknown instruction", instr)
Expand Down
2 changes: 1 addition & 1 deletion yybcvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ endif
$(CC) -g $(NATIVE_SCFILES) -I /usr/local/include -I /opt/homebrew/include -L /usr/local/lib -L /opt/homebrew/lib -luv -lgc $(ADDITIONAL_INCLUDE_PATHS) -Werror -o build/native/vm.exe

vmopt: $(NATIVE_SOURCES)
$(CC) -g -O3 $(NATIVE_SCFILES) -I /usr/local/include -I /opt/homebrew/include -L /usr/local/lib -L /opt/homebrew/lib -luv -lgc $(ADDITIONAL_INCLUDE_PATHS) -Werror -o build/native/vmopt.exe
$(CC) -g -O3 -DNDEBUG $(NATIVE_SCFILES) -I /usr/local/include -I /opt/homebrew/include -L /usr/local/lib -L /opt/homebrew/lib -luv -lgc $(ADDITIONAL_INCLUDE_PATHS) -Werror -o build/native/vmopt.exe



Expand Down
Loading

0 comments on commit a172337

Please sign in to comment.