From 6488a3e3e28812765ecce6ac07ee23cbb7bfb644 Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Wed, 28 Oct 2020 16:58:07 -0400 Subject: [PATCH] Re-start repository for v2 --- .gitignore | 41 - LICENSE | 13 - README | 184 -- README.md | 4 + benchmarks/fannkuch.py | 52 - benchmarks/fannkuch_med.py | 53 - benchmarks/interp.py | 128 - benchmarks/interp2.py | 139 - benchmarks/nbody.py | 131 - benchmarks/nbody_med.py | 132 - benchmarks/raytrace.py | 385 --- docs/INSTALLING | 89 - docs/PROFILING | 5 - include/Python.h | 45 - ...-stackmap-sections-for-ELF-object-fi.patch | 196 -- ...ate-the-stackmap-format-to-use-64bit.patch | 573 ---- ...lim-to-avoid-making-redundant-change.patch | 29 - llvm_revision.txt | 1 - microbenchmarks/attribute_lookup.py | 15 - microbenchmarks/attrs.py | 19 - microbenchmarks/closures.py | 11 - microbenchmarks/empty_loop.py | 11 - microbenchmarks/fib.py | 9 - microbenchmarks/fib2.py | 8 - microbenchmarks/function_calls.py | 66 - microbenchmarks/iteration.py | 4 - microbenchmarks/lcg.py | 15 - microbenchmarks/nested.py | 11 - microbenchmarks/prime_summing.cpp | 20 - microbenchmarks/prime_summing.py | 14 - microbenchmarks/repatching.py | 20 - microbenchmarks/simple_sum.py | 11 - microbenchmarks/sort.py | 15 - microbenchmarks/vecf_add.py | 22 - microbenchmarks/vecf_dot.py | 21 - src/Makefile | 721 ----- src/analysis/fpc.h | 112 - src/analysis/function_analysis.cpp | 318 -- src/analysis/function_analysis.h | 77 - src/analysis/scoping_analysis.cpp | 384 --- src/analysis/scoping_analysis.h | 59 - src/analysis/type_analysis.cpp | 564 ---- src/analysis/type_analysis.h | 47 - src/asm_writing/assembler.cpp | 813 ----- src/asm_writing/assembler.h | 129 - src/asm_writing/icinfo.cpp | 265 -- src/asm_writing/icinfo.h | 120 - src/asm_writing/mc_writer.cpp | 898 ------ src/asm_writing/mc_writer.h | 61 - src/asm_writing/rewriter.cpp | 430 --- src/asm_writing/rewriter.h | 138 - src/asm_writing/rewriter2.cpp | 749 ----- src/asm_writing/rewriter2.h | 275 -- src/asm_writing/types.h | 164 - src/codegen/codegen.cpp | 177 -- src/codegen/codegen.h | 88 - src/codegen/compvars.cpp | 1346 -------- src/codegen/compvars.h | 325 -- src/codegen/dis.cpp | 209 -- src/codegen/dis.h | 48 - src/codegen/entry.cpp | 291 -- src/codegen/entry.h | 34 - src/codegen/gcbuilder.cpp | 44 - src/codegen/gcbuilder.h | 36 - src/codegen/irgen.cpp | 2809 ----------------- src/codegen/irgen.h | 74 - src/codegen/irgen/hooks.cpp | 510 --- src/codegen/irgen/hooks.h | 26 - src/codegen/irgen/util.cpp | 158 - src/codegen/irgen/util.h | 37 - src/codegen/llvm_interpreter.cpp | 628 ---- src/codegen/llvm_interpreter.h | 32 - src/codegen/memmgr.cpp | 249 -- src/codegen/memmgr.h | 26 - src/codegen/opt/aa.cpp | 320 -- src/codegen/opt/const_classes.cpp | 243 -- src/codegen/opt/dead_allocs.cpp | 462 --- src/codegen/opt/escape_analysis.cpp | 223 -- src/codegen/opt/escape_analysis.h | 73 - src/codegen/opt/inliner.cpp | 328 -- src/codegen/opt/inliner.h | 25 - src/codegen/opt/mallocs_nonnull.cpp | 201 -- src/codegen/opt/passes.h | 30 - src/codegen/opt/util.cpp | 44 - src/codegen/opt/util.h | 27 - src/codegen/osrentry.h | 57 - src/codegen/parse_ast.py | 164 - src/codegen/parser.cpp | 784 ----- src/codegen/parser.h | 27 - src/codegen/patchpoints.cpp | 152 - src/codegen/patchpoints.h | 96 - src/codegen/profiling/dumprof.cpp | 51 - src/codegen/profiling/oprofile.cpp | 81 - src/codegen/profiling/pprof.cpp | 71 - src/codegen/profiling/process_pprof.py | 55 - src/codegen/profiling/profiling.cpp | 39 - src/codegen/profiling/profiling.h | 37 - src/codegen/runtime_hooks.cpp | 196 -- src/codegen/runtime_hooks.h | 38 - src/codegen/stackmaps.cpp | 197 -- src/codegen/stackmaps.h | 64 - src/codegen/unwinding.cpp | 68 - src/core/ast.cpp | 1120 ------- src/core/ast.h | 779 ----- src/core/cfg.cpp | 706 ----- src/core/cfg.h | 93 - src/core/common.h | 74 - src/core/options.cpp | 54 - src/core/options.h | 36 - src/core/stats.cpp | 59 - src/core/stats.h | 55 - src/core/types.h | 370 --- src/core/util.cpp | 117 - src/core/util.h | 91 - src/gc/collector.cpp | 151 - src/gc/collector.h | 93 - src/gc/gc_alloc.h | 62 - src/gc/heap.cpp | 399 --- src/gc/heap.h | 124 - src/gc/root_finder.cpp | 111 - src/gc/root_finder.h | 27 - src/jit.cpp | 235 -- src/runtime/bool.cpp | 90 - src/runtime/builtin_modules/builtins.cpp | 298 -- src/runtime/builtin_modules/math.cpp | 69 - src/runtime/builtin_modules/time.cpp | 43 - src/runtime/dict.cpp | 140 - src/runtime/file.cpp | 182 -- src/runtime/float.cpp | 521 --- src/runtime/float.h | 22 - src/runtime/gc_runtime.h | 32 - src/runtime/importing.cpp | 138 - src/runtime/importing.h | 25 - src/runtime/inline/boxing.cpp | 65 - src/runtime/inline/boxing.h | 51 - src/runtime/inline/gc_runtime.cpp | 108 - src/runtime/inline/link_forcer.cpp | 106 - src/runtime/inline/list.cpp | 93 - src/runtime/inline/xrange.cpp | 163 - src/runtime/inline/xrange.h | 24 - src/runtime/int.cpp | 452 --- src/runtime/int.h | 70 - src/runtime/list.cpp | 315 -- src/runtime/list.h | 40 - src/runtime/objmodel.cpp | 2138 ------------- src/runtime/objmodel.h | 79 - src/runtime/stacktrace.cpp | 54 - src/runtime/str.cpp | 376 --- src/runtime/tuple.cpp | 187 -- src/runtime/types.cpp | 487 --- src/runtime/types.h | 260 -- src/runtime/util.cpp | 87 - src/runtime/util.h | 29 - test/test.c | 8 - test/test.cpp | 15 - test/test.s | 6 - test/test_extension/setup.py | 9 - test/test_extension/test.c | 49 - test/tests/1.py | 4 - test/tests/10.py | 16 - test/tests/11.py | 27 - test/tests/12.py | 9 - test/tests/13.py | 14 - test/tests/14.py | 8 - test/tests/15.py | 12 - test/tests/16.py | 23 - test/tests/17.py | 31 - test/tests/18.py | 14 - test/tests/19.py | 9 - test/tests/2.py | 4 - test/tests/20.py | 30 - test/tests/21.py | 8 - test/tests/22.py | 3 - test/tests/23.py | 1 - test/tests/24.py | 3 - test/tests/25.py | 19 - test/tests/26.py | 20 - test/tests/27.py | 24 - test/tests/28.py | 15 - test/tests/29.py | 13 - test/tests/3.py | 9 - test/tests/30.py | 13 - test/tests/31.expected | 1 - test/tests/31.py | 21 - test/tests/32.expected | 1 - test/tests/32.py | 11 - test/tests/33.py | 16 - test/tests/34.py | 8 - test/tests/35.py | 12 - test/tests/36.py | 19 - test/tests/37.py | 17 - test/tests/38.py | 14 - test/tests/39.py | 1 - test/tests/4.py | 3 - test/tests/40.py | 2 - test/tests/41.py | 28 - test/tests/42.py | 15 - test/tests/43.py | 10 - test/tests/44.py | 10 - test/tests/45.py | 15 - test/tests/46.py | 18 - test/tests/47.py | 9 - test/tests/48.py | 5 - test/tests/49.py | 3 - test/tests/5.py | 3 - test/tests/50.py | 10 - test/tests/51.py | 26 - test/tests/52.py | 22 - test/tests/53.py | 21 - test/tests/54.py | 28 - test/tests/55.py | 34 - test/tests/56.py | 7 - test/tests/57.py | 20 - test/tests/58.py | 12 - test/tests/59.py | 16 - test/tests/6.py | 5 - test/tests/60.py | 26 - test/tests/61.py | 8 - test/tests/62.py | 8 - test/tests/63.py | 12 - test/tests/65.py | 18 - test/tests/66.py | 7 - test/tests/67.py | 7 - test/tests/68.py | 5 - test/tests/69.py | 12 - test/tests/7.py | 60 - test/tests/70.py | 1 - test/tests/71.py | 21 - test/tests/72.py | 12 - test/tests/73.py | 35 - test/tests/74.py | 11 - test/tests/75.py | 5 - test/tests/8.py | 2 - test/tests/9.py | 14 - test/tests/arith.py | 34 - test/tests/binop_ics.py | 16 - test/tests/binop_invalidation.py | 79 - test/tests/binops_reverse.py | 24 - test/tests/binops_subclass.py | 37 - test/tests/boolops.py | 34 - test/tests/break_outside_loop.py | 1 - test/tests/builtins.py | 13 - test/tests/call_patches.py | 20 - test/tests/callattr.py | 27 - test/tests/callattr_caching.py | 18 - test/tests/class_changing.py | 18 - test/tests/class_clsgetattr_ics.py | 13 - test/tests/class_freeing.py | 24 - test/tests/class_freeing_time.py | 20 - test/tests/class_getattrsetattr_ics.py | 14 - test/tests/class_noctor.py | 16 - test/tests/classdef_arbitrary.py | 43 - test/tests/classname.py | 12 - test/tests/clsattr_clears_itself.py | 19 - test/tests/comparisons.py | 71 - test/tests/comparisons_more.py | 3 - test/tests/continue_outside_loop.py | 1 - test/tests/ctor_ics.py | 42 - test/tests/dict.py | 11 - test/tests/dict_internals.py | 30 - test/tests/extension.expected | 4 - test/tests/extension.py | 15 - test/tests/fannkuch_small.py | 49 - test/tests/fib_small.py | 7 - test/tests/file.py | 8 - test/tests/finalization_cycles.py | 21 - test/tests/float.py | 5 - test/tests/float_locals.py | 30 - test/tests/float_osr.py | 15 - test/tests/float_precision.py | 33 - test/tests/for.py | 36 - test/tests/for_iter.py | 35 - test/tests/func_caching.py | 10 - test/tests/getattr.py | 5 - test/tests/getattr_ics.py | 12 - test/tests/getattr_nonstring.py | 1 - test/tests/getitem.py | 24 - test/tests/global_and_local.py | 11 - test/tests/global_directive.py | 19 - test/tests/global_ics.py | 12 - test/tests/globals.py | 12 - test/tests/hash.py | 8 - test/tests/icgetattr_invalid.py | 53 - test/tests/im_caching.py | 35 - test/tests/im_ics.py | 10 - test/tests/init_must_return_none.py | 14 - test/tests/instance_callable.py | 10 - test/tests/int_ics.py | 5 - test/tests/interp2_small.py | 139 - test/tests/is.py | 9 - test/tests/list.py | 28 - test/tests/list_unpacking.py | 7 - test/tests/longargs_stackusage.py | 31 - test/tests/loops.py | 7 - test/tests/many_attrs.py | 111 - test/tests/many_attrs_setattr.py | 20 - test/tests/math_more.py | 5 - test/tests/math_test.py | 15 - test/tests/metaclass_parent.py | 10 - test/tests/mod.py | 11 - test/tests/nbody_small.py | 132 - test/tests/non_function_ctors.py | 17 - test/tests/nondirectly_callable_ics.py | 20 - test/tests/none_not_settable.py | 21 - test/tests/nonself_resurrection.py | 18 - test/tests/nonzero_patching.py | 11 - test/tests/osr_big.py | 36 - test/tests/osr_weird.py | 28 - test/tests/patching_under.py | 35 - test/tests/polymorphic_ics.py | 15 - test/tests/raytrace_small.py | 384 --- test/tests/resurrection.py | 24 - test/tests/return_in_class.py | 2 - test/tests/return_outside_func.py | 1 - test/tests/scoping_classes.py | 21 - test/tests/setattr_patching_under.py | 37 - test/tests/setitem.py | 20 - test/tests/slice.py | 6 - test/tests/sort_small.py | 20 - test/tests/speculation_test.py | 11 - test/tests/str_functions.py | 6 - test/tests/string_interpolation.py | 4 - test/tests/t.py | 7 - test/tests/t2.py | 8 - test/tests/time_test.py | 2 - test/tests/tuple_depth.py | 8 - test/tests/tuple_iteration.py | 9 - test/tests/tuple_unpacking.py | 22 - test/tests/tuple_unpacking_invalid.py | 2 - test/tests/tuples.py | 66 - test/tests/unaryops.py | 8 - test/tests/with_exit.py | 61 - test/tests/with_parsed.py | 27 - test/tests/xrange.py | 5 - test/unittests/gc.cpp | 100 - tools/annotate.py | 45 - tools/build_system/ld | 31 - tools/cumulate.sh | 1 - tools/demangle.cpp | 20 - tools/find_problem.py | 58 - tools/git_svn_gotorev.py | 84 - tools/mcjitcache.cpp | 109 - tools/publicize.cpp | 177 -- tools/tester.py | 383 --- 344 files changed, 4 insertions(+), 36369 deletions(-) delete mode 100644 .gitignore delete mode 100644 LICENSE delete mode 100644 README create mode 100644 README.md delete mode 100644 benchmarks/fannkuch.py delete mode 100644 benchmarks/fannkuch_med.py delete mode 100644 benchmarks/interp.py delete mode 100644 benchmarks/interp2.py delete mode 100644 benchmarks/nbody.py delete mode 100644 benchmarks/nbody_med.py delete mode 100644 benchmarks/raytrace.py delete mode 100644 docs/INSTALLING delete mode 100644 docs/PROFILING delete mode 100644 include/Python.h delete mode 100644 llvm_patches/0001-Support-emitting-stackmap-sections-for-ELF-object-fi.patch delete mode 100644 llvm_patches/0002-Stackmaps-Update-the-stackmap-format-to-use-64bit.patch delete mode 100644 llvm_patches/0003-Update-TailCallElim-to-avoid-making-redundant-change.patch delete mode 100644 llvm_revision.txt delete mode 100644 microbenchmarks/attribute_lookup.py delete mode 100644 microbenchmarks/attrs.py delete mode 100644 microbenchmarks/closures.py delete mode 100644 microbenchmarks/empty_loop.py delete mode 100644 microbenchmarks/fib.py delete mode 100644 microbenchmarks/fib2.py delete mode 100644 microbenchmarks/function_calls.py delete mode 100644 microbenchmarks/iteration.py delete mode 100644 microbenchmarks/lcg.py delete mode 100644 microbenchmarks/nested.py delete mode 100644 microbenchmarks/prime_summing.cpp delete mode 100644 microbenchmarks/prime_summing.py delete mode 100644 microbenchmarks/repatching.py delete mode 100644 microbenchmarks/simple_sum.py delete mode 100644 microbenchmarks/sort.py delete mode 100644 microbenchmarks/vecf_add.py delete mode 100644 microbenchmarks/vecf_dot.py delete mode 100644 src/Makefile delete mode 100644 src/analysis/fpc.h delete mode 100644 src/analysis/function_analysis.cpp delete mode 100644 src/analysis/function_analysis.h delete mode 100644 src/analysis/scoping_analysis.cpp delete mode 100644 src/analysis/scoping_analysis.h delete mode 100644 src/analysis/type_analysis.cpp delete mode 100644 src/analysis/type_analysis.h delete mode 100644 src/asm_writing/assembler.cpp delete mode 100644 src/asm_writing/assembler.h delete mode 100644 src/asm_writing/icinfo.cpp delete mode 100644 src/asm_writing/icinfo.h delete mode 100644 src/asm_writing/mc_writer.cpp delete mode 100644 src/asm_writing/mc_writer.h delete mode 100644 src/asm_writing/rewriter.cpp delete mode 100644 src/asm_writing/rewriter.h delete mode 100644 src/asm_writing/rewriter2.cpp delete mode 100644 src/asm_writing/rewriter2.h delete mode 100644 src/asm_writing/types.h delete mode 100644 src/codegen/codegen.cpp delete mode 100644 src/codegen/codegen.h delete mode 100644 src/codegen/compvars.cpp delete mode 100644 src/codegen/compvars.h delete mode 100644 src/codegen/dis.cpp delete mode 100644 src/codegen/dis.h delete mode 100644 src/codegen/entry.cpp delete mode 100644 src/codegen/entry.h delete mode 100644 src/codegen/gcbuilder.cpp delete mode 100644 src/codegen/gcbuilder.h delete mode 100644 src/codegen/irgen.cpp delete mode 100644 src/codegen/irgen.h delete mode 100644 src/codegen/irgen/hooks.cpp delete mode 100644 src/codegen/irgen/hooks.h delete mode 100644 src/codegen/irgen/util.cpp delete mode 100644 src/codegen/irgen/util.h delete mode 100644 src/codegen/llvm_interpreter.cpp delete mode 100644 src/codegen/llvm_interpreter.h delete mode 100644 src/codegen/memmgr.cpp delete mode 100644 src/codegen/memmgr.h delete mode 100644 src/codegen/opt/aa.cpp delete mode 100644 src/codegen/opt/const_classes.cpp delete mode 100644 src/codegen/opt/dead_allocs.cpp delete mode 100644 src/codegen/opt/escape_analysis.cpp delete mode 100644 src/codegen/opt/escape_analysis.h delete mode 100644 src/codegen/opt/inliner.cpp delete mode 100644 src/codegen/opt/inliner.h delete mode 100644 src/codegen/opt/mallocs_nonnull.cpp delete mode 100644 src/codegen/opt/passes.h delete mode 100644 src/codegen/opt/util.cpp delete mode 100644 src/codegen/opt/util.h delete mode 100644 src/codegen/osrentry.h delete mode 100644 src/codegen/parse_ast.py delete mode 100644 src/codegen/parser.cpp delete mode 100644 src/codegen/parser.h delete mode 100644 src/codegen/patchpoints.cpp delete mode 100644 src/codegen/patchpoints.h delete mode 100644 src/codegen/profiling/dumprof.cpp delete mode 100644 src/codegen/profiling/oprofile.cpp delete mode 100644 src/codegen/profiling/pprof.cpp delete mode 100644 src/codegen/profiling/process_pprof.py delete mode 100644 src/codegen/profiling/profiling.cpp delete mode 100644 src/codegen/profiling/profiling.h delete mode 100644 src/codegen/runtime_hooks.cpp delete mode 100644 src/codegen/runtime_hooks.h delete mode 100644 src/codegen/stackmaps.cpp delete mode 100644 src/codegen/stackmaps.h delete mode 100644 src/codegen/unwinding.cpp delete mode 100644 src/core/ast.cpp delete mode 100644 src/core/ast.h delete mode 100644 src/core/cfg.cpp delete mode 100644 src/core/cfg.h delete mode 100644 src/core/common.h delete mode 100644 src/core/options.cpp delete mode 100644 src/core/options.h delete mode 100644 src/core/stats.cpp delete mode 100644 src/core/stats.h delete mode 100644 src/core/types.h delete mode 100644 src/core/util.cpp delete mode 100644 src/core/util.h delete mode 100644 src/gc/collector.cpp delete mode 100644 src/gc/collector.h delete mode 100644 src/gc/gc_alloc.h delete mode 100644 src/gc/heap.cpp delete mode 100644 src/gc/heap.h delete mode 100644 src/gc/root_finder.cpp delete mode 100644 src/gc/root_finder.h delete mode 100644 src/jit.cpp delete mode 100644 src/runtime/bool.cpp delete mode 100644 src/runtime/builtin_modules/builtins.cpp delete mode 100644 src/runtime/builtin_modules/math.cpp delete mode 100644 src/runtime/builtin_modules/time.cpp delete mode 100644 src/runtime/dict.cpp delete mode 100644 src/runtime/file.cpp delete mode 100644 src/runtime/float.cpp delete mode 100644 src/runtime/float.h delete mode 100644 src/runtime/gc_runtime.h delete mode 100644 src/runtime/importing.cpp delete mode 100644 src/runtime/importing.h delete mode 100644 src/runtime/inline/boxing.cpp delete mode 100644 src/runtime/inline/boxing.h delete mode 100644 src/runtime/inline/gc_runtime.cpp delete mode 100644 src/runtime/inline/link_forcer.cpp delete mode 100644 src/runtime/inline/list.cpp delete mode 100644 src/runtime/inline/xrange.cpp delete mode 100644 src/runtime/inline/xrange.h delete mode 100644 src/runtime/int.cpp delete mode 100644 src/runtime/int.h delete mode 100644 src/runtime/list.cpp delete mode 100644 src/runtime/list.h delete mode 100644 src/runtime/objmodel.cpp delete mode 100644 src/runtime/objmodel.h delete mode 100644 src/runtime/stacktrace.cpp delete mode 100644 src/runtime/str.cpp delete mode 100644 src/runtime/tuple.cpp delete mode 100644 src/runtime/types.cpp delete mode 100644 src/runtime/types.h delete mode 100644 src/runtime/util.cpp delete mode 100644 src/runtime/util.h delete mode 100644 test/test.c delete mode 100644 test/test.cpp delete mode 100644 test/test.s delete mode 100644 test/test_extension/setup.py delete mode 100644 test/test_extension/test.c delete mode 100644 test/tests/1.py delete mode 100644 test/tests/10.py delete mode 100644 test/tests/11.py delete mode 100644 test/tests/12.py delete mode 100644 test/tests/13.py delete mode 100644 test/tests/14.py delete mode 100644 test/tests/15.py delete mode 100644 test/tests/16.py delete mode 100644 test/tests/17.py delete mode 100644 test/tests/18.py delete mode 100644 test/tests/19.py delete mode 100644 test/tests/2.py delete mode 100644 test/tests/20.py delete mode 100644 test/tests/21.py delete mode 100644 test/tests/22.py delete mode 100644 test/tests/23.py delete mode 100644 test/tests/24.py delete mode 100644 test/tests/25.py delete mode 100644 test/tests/26.py delete mode 100644 test/tests/27.py delete mode 100644 test/tests/28.py delete mode 100644 test/tests/29.py delete mode 100644 test/tests/3.py delete mode 100644 test/tests/30.py delete mode 100644 test/tests/31.expected delete mode 100644 test/tests/31.py delete mode 100644 test/tests/32.expected delete mode 100644 test/tests/32.py delete mode 100644 test/tests/33.py delete mode 100644 test/tests/34.py delete mode 100644 test/tests/35.py delete mode 100644 test/tests/36.py delete mode 100644 test/tests/37.py delete mode 100644 test/tests/38.py delete mode 100644 test/tests/39.py delete mode 100644 test/tests/4.py delete mode 100644 test/tests/40.py delete mode 100644 test/tests/41.py delete mode 100644 test/tests/42.py delete mode 100644 test/tests/43.py delete mode 100644 test/tests/44.py delete mode 100644 test/tests/45.py delete mode 100644 test/tests/46.py delete mode 100644 test/tests/47.py delete mode 100644 test/tests/48.py delete mode 100644 test/tests/49.py delete mode 100644 test/tests/5.py delete mode 100644 test/tests/50.py delete mode 100644 test/tests/51.py delete mode 100644 test/tests/52.py delete mode 100644 test/tests/53.py delete mode 100644 test/tests/54.py delete mode 100644 test/tests/55.py delete mode 100644 test/tests/56.py delete mode 100644 test/tests/57.py delete mode 100644 test/tests/58.py delete mode 100644 test/tests/59.py delete mode 100644 test/tests/6.py delete mode 100644 test/tests/60.py delete mode 100644 test/tests/61.py delete mode 100644 test/tests/62.py delete mode 100644 test/tests/63.py delete mode 100644 test/tests/65.py delete mode 100644 test/tests/66.py delete mode 100644 test/tests/67.py delete mode 100644 test/tests/68.py delete mode 100644 test/tests/69.py delete mode 100644 test/tests/7.py delete mode 100644 test/tests/70.py delete mode 100644 test/tests/71.py delete mode 100644 test/tests/72.py delete mode 100644 test/tests/73.py delete mode 100644 test/tests/74.py delete mode 100644 test/tests/75.py delete mode 100644 test/tests/8.py delete mode 100644 test/tests/9.py delete mode 100644 test/tests/arith.py delete mode 100644 test/tests/binop_ics.py delete mode 100644 test/tests/binop_invalidation.py delete mode 100644 test/tests/binops_reverse.py delete mode 100644 test/tests/binops_subclass.py delete mode 100644 test/tests/boolops.py delete mode 100644 test/tests/break_outside_loop.py delete mode 100644 test/tests/builtins.py delete mode 100644 test/tests/call_patches.py delete mode 100644 test/tests/callattr.py delete mode 100644 test/tests/callattr_caching.py delete mode 100644 test/tests/class_changing.py delete mode 100644 test/tests/class_clsgetattr_ics.py delete mode 100644 test/tests/class_freeing.py delete mode 100644 test/tests/class_freeing_time.py delete mode 100644 test/tests/class_getattrsetattr_ics.py delete mode 100644 test/tests/class_noctor.py delete mode 100644 test/tests/classdef_arbitrary.py delete mode 100644 test/tests/classname.py delete mode 100644 test/tests/clsattr_clears_itself.py delete mode 100644 test/tests/comparisons.py delete mode 100644 test/tests/comparisons_more.py delete mode 100644 test/tests/continue_outside_loop.py delete mode 100644 test/tests/ctor_ics.py delete mode 100644 test/tests/dict.py delete mode 100644 test/tests/dict_internals.py delete mode 100644 test/tests/extension.expected delete mode 100644 test/tests/extension.py delete mode 100644 test/tests/fannkuch_small.py delete mode 100644 test/tests/fib_small.py delete mode 100644 test/tests/file.py delete mode 100644 test/tests/finalization_cycles.py delete mode 100644 test/tests/float.py delete mode 100644 test/tests/float_locals.py delete mode 100644 test/tests/float_osr.py delete mode 100644 test/tests/float_precision.py delete mode 100644 test/tests/for.py delete mode 100644 test/tests/for_iter.py delete mode 100644 test/tests/func_caching.py delete mode 100644 test/tests/getattr.py delete mode 100644 test/tests/getattr_ics.py delete mode 100644 test/tests/getattr_nonstring.py delete mode 100644 test/tests/getitem.py delete mode 100644 test/tests/global_and_local.py delete mode 100644 test/tests/global_directive.py delete mode 100644 test/tests/global_ics.py delete mode 100644 test/tests/globals.py delete mode 100644 test/tests/hash.py delete mode 100644 test/tests/icgetattr_invalid.py delete mode 100644 test/tests/im_caching.py delete mode 100644 test/tests/im_ics.py delete mode 100644 test/tests/init_must_return_none.py delete mode 100644 test/tests/instance_callable.py delete mode 100644 test/tests/int_ics.py delete mode 100644 test/tests/interp2_small.py delete mode 100644 test/tests/is.py delete mode 100644 test/tests/list.py delete mode 100644 test/tests/list_unpacking.py delete mode 100644 test/tests/longargs_stackusage.py delete mode 100644 test/tests/loops.py delete mode 100644 test/tests/many_attrs.py delete mode 100644 test/tests/many_attrs_setattr.py delete mode 100644 test/tests/math_more.py delete mode 100644 test/tests/math_test.py delete mode 100644 test/tests/metaclass_parent.py delete mode 100644 test/tests/mod.py delete mode 100644 test/tests/nbody_small.py delete mode 100644 test/tests/non_function_ctors.py delete mode 100644 test/tests/nondirectly_callable_ics.py delete mode 100644 test/tests/none_not_settable.py delete mode 100644 test/tests/nonself_resurrection.py delete mode 100644 test/tests/nonzero_patching.py delete mode 100644 test/tests/osr_big.py delete mode 100644 test/tests/osr_weird.py delete mode 100644 test/tests/patching_under.py delete mode 100644 test/tests/polymorphic_ics.py delete mode 100644 test/tests/raytrace_small.py delete mode 100644 test/tests/resurrection.py delete mode 100644 test/tests/return_in_class.py delete mode 100644 test/tests/return_outside_func.py delete mode 100644 test/tests/scoping_classes.py delete mode 100644 test/tests/setattr_patching_under.py delete mode 100644 test/tests/setitem.py delete mode 100644 test/tests/slice.py delete mode 100644 test/tests/sort_small.py delete mode 100644 test/tests/speculation_test.py delete mode 100644 test/tests/str_functions.py delete mode 100644 test/tests/string_interpolation.py delete mode 100644 test/tests/t.py delete mode 100644 test/tests/t2.py delete mode 100644 test/tests/time_test.py delete mode 100644 test/tests/tuple_depth.py delete mode 100644 test/tests/tuple_iteration.py delete mode 100644 test/tests/tuple_unpacking.py delete mode 100644 test/tests/tuple_unpacking_invalid.py delete mode 100644 test/tests/tuples.py delete mode 100644 test/tests/unaryops.py delete mode 100644 test/tests/with_exit.py delete mode 100644 test/tests/with_parsed.py delete mode 100644 test/tests/xrange.py delete mode 100644 test/unittests/gc.cpp delete mode 100644 tools/annotate.py delete mode 100755 tools/build_system/ld delete mode 100644 tools/cumulate.sh delete mode 100644 tools/demangle.cpp delete mode 100644 tools/find_problem.py delete mode 100644 tools/git_svn_gotorev.py delete mode 100644 tools/mcjitcache.cpp delete mode 100644 tools/publicize.cpp delete mode 100644 tools/tester.py diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 4fadd5d45..000000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -Makefile.local -tools/demangle -tools/mcjitcache -tools/mcjitcache_release -tools/publicize -tools/publicize_release -pyston -pyston_opt -pyston_noasserts -pyston_oprof -pyston_pprof -pyston_pprof_opt -pyston_dbg -pyston_debug -pyston_prof -pyston_profile -pyston_release -*.cache -tests/t.py -tests/t2.py -*.bc -stdlib.ll -*.o -*.d -*.o.ll -*.o.*.ll -stdlib*.ll -oprofile_data -pprof.jit -tags -*.pyc - -perf.data -perf.data.old -perf_map -gmon.out - -find_problem.status -*.expected_cache - -*.so diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 6fa782020..000000000 --- a/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2014 Dropbox, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/README b/README deleted file mode 100644 index fbedccbcd..000000000 --- a/README +++ /dev/null @@ -1,184 +0,0 @@ -# Pyston - -Pyston is a new, under-development Python implementation built using LLVM and modern JIT techniques with the goal of achieving good performance. - -### Current state - -Pyston "works", though doesn't support very much of the Python language, and currently is not very useful for end-users. - -Pyston currently targets Python 2.7, and only runs on x86_64 platforms, and has only been tested on Ubuntu. - -Benchmarks are not currently that meaningful since the supported set of benchmarks is too small to be representative; with that caveat, Pyston seems to have better performance than CPython but lags behind PyPy. - -### Getting started - -To get a full development environment for Pyston, you need pretty recent versions of various tools, since self-modifying code tends to be less well supported. The docs/INSTALLING file contains information about what the tools are, how to get them, and how to install them; currently it can take up to an hour to get them all built on a quad-core machine. - -To simply build and run Pyston, a smaller set of dependencies is required; see docs/INSTALLING, but skip the "OPTIONAL DEPENDENCIES" section. Once all the dependencies are installed, you should be able to do -``` -$ make test -j4 -``` - -And see that hopefully all of the tests will pass. - -### Running Pyston - -Pyston builds in a few different configurations; right now there is "pyston_dbg", which is the debug configuration and contains assertions and debug symbols, and "pyston", the release configuration which has no assertions or debug symbols, and has full optimizations. You can build them by saying `make pyston_dbg` or `make pyston`, respectively. If you are interested in seeing how fast Pyston can go, you should try the release configuration, but there is a good chance that it will crash, in which case you can run the debug configuration to see what is happening. - -> There are a number of other configurations useful for development: "pyston_debug" contains full LLVM debug information, but can be over 100MB. "pyston_prof" contains gprof-style profiling instrumentation; gprof can't profile JIT'd code, reducing it's usefulness in this case, but the configuration has stuck around since it gets compiled with gcc, and can expose issues with the normal clang-based build. - -You can get a simple REPL by simply typing `./pyston`; it is not very robust right now, and only supports single-line statements, but can give you an interactive view into how Pyston works. To get more functionality, you can do `./pyston -i [your_source_file.py]`, which will go into the REPL after executing the given file, letting you access all the variables you had defined. - -#### Command-line options: -
-
-n
-
Disable the Pyston interpreter. The interpreter doesn't support certain features, such as inline caches, so disabling it can expose additional bugs.
- -
-O
-
Force Pyston to always run at the highest compilation tier. This doesn't always produce the fastest running time due to the lack of type recording from lower compilation tiers, but can help stress-test the code generator.
- -
-q
-
Set verbosity to 0
-
-v
-
Increase verbosity by 1
- -
Pyston by default runs at verbosity 1, which contains a good amount of debugging information. Verbosity 0 contains no debugging information (such as the LLVM IR generated) and should produce the same results as other runtimes.
- -
-d
-
In addition to showing the generated LLVM IR, show the generated assembly code.
- -
-i
-
Go into the repl after executing the given script.
- -
-b
-
Benchmark mode: do whatever it would have been done, but do it 1000 times.
- -
-p
-
Emit profiling information: at exit, Pyston will emit a dump of the code it generated for consumption by other tools.
- -
-r
-
Use a stripped stdlib. When running pyston_dbg, the default is to use a stdlib with full debugging symbols enabled. Passing -r changes this behavior to load a slimmer, stripped stdlib.
- -### Version History - -##### v0.1: 4/2/2014 - -Initial Release. -- Working system; proof of concept of major JIT techniques. -- Fairly promising initial performance, though not fully validated. -- Missing large parts of the language - - Exceptions (planned for 0.2) - - Class inheritance (planned for 0.2) - - Default arguments, keywords, starargs, kwargs (planned for 0.2) - - Generators (planned for 0.2) - - Integer promotion (planned for 0.2) - - Threads - ---- -## Technical features - -### Compilation tiers - -Pyston currently features four compilation tiers. In increasing order of speed, but also compilation time: -1. An LLVM-IR interpreter. LLVM IR is not designed for interpretation, and isn't very well suited for the task -- it is too low level, and the interpreter spends too much time dispatching for each instruction. The interpreter is currently used for the first three times that a function is called, or the first ten iterations of a loop, before switching to the next level. -2. Baseline LLVM compilation. Runs no LLVM optimizations, and no type speculation, and simply hands off the generated code to the LLVM code generator. This tier does type recording for the final tier. -3. Improved LLVM compilation. Behaves very similarly to baseline LLVM compilation, so this tier will probably be removed in the near future. -4. Full LLVM optimization + compilation. This tier runs full LLVM optimizations, and uses type feedback from lower tiers. This tier kicks in after 10000 loop iterations, or 10000 calls to a function. (exact numbers subject to change). - -There are two main ways that Pyston can move up to higher tiers: -- If a function gets called often, it will get recompiled at a higher tier and the new version will be called instead. -- If a loop gets iterated enough times, Pyston will OSR to a higher tier within the same function. - -Currently Pyston only moves to higher tiers, and doesn't move back down to lower tiers. This will be important to add, in order to support doing additional type recording if types change. - -The current plan is to replace the interpreter with a quick code generator that doesn't use LLVM's machinery; in theory it should be possible to build a simple code generator that just uses the LLVM IR as an input. - -#### OSR - -Pyston uses OSR (which stands for On-Stack Replacement, though Pyston does not use that particular mechanism) to move up to a higher tier while inside a function -- this can be important for functions that are expensive the very first time they are called. - -OSR is implemented in Pyston by keeping a count, per backedge, of the number of times that the backedge is taken. Once a certain threshold is reached (currently 10 for the interpreter, 10000 otherwise), Pyston will compile a special OSR-entry version of the function. This function takes as arguments all the local variables for that point in the program, and continues execution where the previous function left off. - -For example, this Python function: -```python -def square(n): - r = 0 - for i in xrange(n): - r += n -``` -Will get translated to something similar to: -```C -static _backedge_trip_count = 0; -int square(int n) { - int r = 0; - for (int i = 0; i < n; i++) { - r += n; - - // OSR exit here: - _backedge_trip_count++; - if (_backedge_trip_count >= 10000) { - auto osr_entry = compileOsrEntry(); - return osr_entry(n, i, r); - } - } - return r; -} -``` - -The compiled OSR entry will look something similar to: -```C -int square_osrentry(int n, int i, int r) { - for (; i < n; i++) { - r += n; - } - return r; -} -``` - -The pseudo-C shown above doesn't look that different; the benefit of this approach is that the square() function can be compiled at a low compilation tier, but the square_osrentry can be compiled at a higher one since the compilation time is much more likely to pay off. - -This approach seems to work, but has a couple drawbacks: -- It's currently tracked per backedge rather than per backedge-target, which can lead to more OSR compilations than necessary. -- The OSR'd version can be slower due to the optimizations having less context about the source of the arguments, ie that they're local variables that haven't escaped. - -### Inlining - -Pyston can inline functions from its runtime into the code that it's JIT'ing. This only happens if, at JIT time, it can guarantee the runtime function that would end up getting called, which typically happens if it is an attribute of a guaranteed type. For instance, `[].append()` will end up resolving to the internal listAppend(), since we know what the type of `[]` is. - -Once the Python-level call is resolved to a C-level call to a runtime function, normal inlining heuristics kick in to determine if it is profitable to inline the function. As a side note, the inlining is only possible because the LLVM IR for the runtime is not only compiled to machine code to be run, but also directly embedded as LLVM IR into the pyston binary, so that the LLVM IR can be inlined. - -### Object representation - -Current Pyston uses an 'everything is boxed' model. It has some ability to deal with unboxed variants of ints, floats, and bools, but those unboxed types are not mixable with boxed types. ie if you put an integer into a list, the integer will always get boxed first. - -### Inline caches - -### Hidden classes - -### Type feedback - -Currently, tiers 2 and 3 support *type recording*, and make a record of the types seen at specifically-designated parts of the program. - -Tier 4 then looks at the type record; the current heuristic is that if the same type has been seen 100 times in a row, the compiler will speculate - -### Garbage collection - -Pyston currently utilizes a *conservative* garbage collector -- this means that GC roots aren't tracked directly, but rather all GC-managed memory is scanned for values that could point into the GC heap, and treat those conservatively as pointers that keep the pointed-to GC memory alive. - -Currently, the Pyston's GC is a non-copying, non-generational, stop-the-world GC. ie it is a simple implementation that will need to be improved in the future. - -### Aspiration: Extension modules - -CPython-style C extension modules are difficult to support efficiently in alternative Python implementations, especially non-refcounted ones. One of the most prominant overheads is the conversion between a refcounted C API and a GC-managed runtime that has to implement it. - -My hope is that by applying a conservative GC to the extension modules, the refcounting code can be eliminated and the conservative GC will be able to find the roots. Whether or not this works, and is performant, remains to be seen. - -### Aspiration: Thread-level Parallelism - -Many runtimes for dynamic languages -- including CPython and PyPy -- use a Global Interpreter Lock (GIL) to protect internal structures against concurrent modification. This works, but has the drawback of only allowing one thread at a time to run. - -The number of cores you can obtain in a single machine keeps growing, which means the performance deficit of single-threaded programs is falling vs multi-threaded ones. There has been some work to support multi-process parallelism in Python, though many people prefer multi-threaded paralellism for its (relative) ease of use. - -We have no concrete ideas or plans for how to implement this, so this section is all optimistic, but our hope is that it will be possible to implement true parallelism. - -One of the biggest challenges for this is not just protecting the internal runtime structures, but also providing the higher-level guarantees that Python programmers have become accustomed to. One example is that all builtin datastructures must be thread-safe, since they currently are. A slightly more sinister one is that Python has a very straightforward memory model, where no operations can be viewed in different orders on different threads, because all thread switching involves a lock release-then-acquire which serializes the memory accesses; performantly maintaining this memory model is likely to be a challenge. diff --git a/README.md b/README.md new file mode 100644 index 000000000..098af0390 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +Pyston is a faster and highly-compatible implementation of the Python programming language. +Version 2 is currently closed source, but you can find the old v1 source code under the [v1.0 tag](https://github.com/pyston/pyston/tree/v1.0) in this repository. + +For updates, please follow [our blog](https://blog.pyston.org/) diff --git a/benchmarks/fannkuch.py b/benchmarks/fannkuch.py deleted file mode 100644 index 57a6bec38..000000000 --- a/benchmarks/fannkuch.py +++ /dev/null @@ -1,52 +0,0 @@ -import time - -def fannkuch(n): - count = range(1, n+1) - max_flips = 0 - m = n-1 - r = n - check = 0 - perm1 = range(n) - perm = range(n) - perm1_ins = perm1.insert - perm1_pop = perm1.pop - - while 1: - if check < 30: - #print "".join(str(i+1) for i in perm1) - check = check + 1 - - while r != 1: - count[r-1] = r - r = r - 1 - - if perm1[0] != 0 and perm1[m] != m: - perm = perm1[:] - flips_count = 0 - k = perm[0] - while k: - perm[:k+1] = perm[k::-1] - flips_count = flips_count + 1 - k = perm[0] - - if flips_count > max_flips: - max_flips = flips_count - - while r != n: - perm1_ins(r, perm1_pop(0)) - count[r] = count[r] - 1 - if count[r] > 0: - break - r = r + 1 - else: - return max_flips - -DEFAULT_ARG = 9 - -def main(n): - for i in range(2, n): - t0 = time.time() - print fannkuch(i) - tk = time.time() - print tk - t0 -main(11) diff --git a/benchmarks/fannkuch_med.py b/benchmarks/fannkuch_med.py deleted file mode 100644 index 244f954f0..000000000 --- a/benchmarks/fannkuch_med.py +++ /dev/null @@ -1,53 +0,0 @@ -import time - -def fannkuch(n): - count = range(1, n+1) - max_flips = 0 - m = n-1 - r = n - check = 0 - perm1 = range(n) - perm = range(n) - perm1_ins = perm1.insert - perm1_pop = perm1.pop - - while 1: - if check < 30: - #print "".join(str(i+1) for i in perm1) - check = check + 1 - - while r != 1: - count[r-1] = r - r = r - 1 - - if perm1[0] != 0 and perm1[m] != m: - perm = perm1[:] - flips_count = 0 - k = perm[0] - while k: - perm[:k+1] = perm[k::-1] - flips_count = flips_count + 1 - k = perm[0] - - if flips_count > max_flips: - max_flips = flips_count - - while r != n: - perm1_ins(r, perm1_pop(0)) - count[r] = count[r] - 1 - if count[r] > 0: - break - r = r + 1 - else: - return max_flips - -DEFAULT_ARG = 9 - -def main(n): - for i in range(2, n): - t0 = time.time() - print fannkuch(i) - tk = time.time() - print tk - t0 -main(10) - diff --git a/benchmarks/interp.py b/benchmarks/interp.py deleted file mode 100644 index 24ede836a..000000000 --- a/benchmarks/interp.py +++ /dev/null @@ -1,128 +0,0 @@ - -class Random(object): - def __init__(self, seed): - self.cur = seed - - def next(self): - self.cur = (self.cur * 1103515245 + 12345) % (1 << 31) - return self.cur - -class AstAssign(object): - def __init__(self, name, expr): - self.name = name - self.expr = expr - -class AstWhile(object): - def __init__(self, test, body): - self.test = test - self.body = body - -class AstBinop(object): - def __init__(self, lhs, rhs, op): - self.lhs = lhs - self.rhs = rhs - self.op = op - -class AstPrint(object): - def __init__(self, expr): - self.expr = expr - -class AstIf(object): - def __init__(self, test, then, orelse): - self.test = test - self.then = then - self.orelse = orelse - -class State(object): - def __init__(self): - self.syms = {} - -def _run(state, node): - if isinstance(node, list): - for s in node: - _run(state, s) - return None - elif isinstance(node, AstAssign): - v = _run(state, node.expr) - state.syms[node.name] = v - return None - elif isinstance(node, int): - return node - elif isinstance(node, str): - return state.syms[node] - elif isinstance(node, AstPrint): - v = _run(state, node.expr) - print v - elif isinstance(node, AstBinop): - l = _run(state, node.lhs) - r = _run(state, node.rhs) - if node.op == '+': - return l + r - if node.op == '-': - return l - r - if node.op == '*': - return l * r - if node.op == '%': - return l % r - if node.op == "<": - return l < r - if node.op == "<=": - return l <= r - if node.op == "==": - return l == r - print node.op - 1/0 - elif isinstance(node, AstIf): - v = _run(state, node.test) - if v: - _run(state, node.then) - else: - _run(state, node.orelse) - elif isinstance(node, AstWhile): - while True: - v = _run(state, node.test) - if not v: - break - _run(state, node.body) - return None - else: - print type(node) - 1/0 - -def run(node): - _run(State(), node) - -prog = [ - AstAssign("x", 100000), - AstAssign("t", 0), - AstWhile("x", [ - AstAssign("t", AstBinop("t", "x", '+')), - AstAssign("x", AstBinop("x", 1, '-')), - # AstPrint("x"), - ]), - AstPrint("t"), - ] - -prog = [ - AstAssign("i", 2), - AstAssign("t", 0), - AstWhile(AstBinop("i", 10000, '<'), [ - AstAssign("j", 2), - AstAssign("good", 1), - AstWhile(AstBinop(AstBinop("j", "j", '*'), "i", "<="), [ - AstIf(AstBinop(AstBinop("i", "j", "%"), 0, "=="), [ - AstAssign("good", 0), - ], [ - ]), - AstAssign("j", AstBinop("j", 1, "+")), - ]), - AstIf("good", [ - AstPrint("i"), - AstAssign("t", AstBinop("t", "i", "+")), - ], []), - AstAssign("i", AstBinop("i", 1, "+")), - ]), - AstPrint("t"), - ] - -run(prog) diff --git a/benchmarks/interp2.py b/benchmarks/interp2.py deleted file mode 100644 index 0876b0d39..000000000 --- a/benchmarks/interp2.py +++ /dev/null @@ -1,139 +0,0 @@ -class Random(object): - def __init__(self, seed): - self.cur = seed - - def next(self): - self.cur = (self.cur * 1103515245 + 12345) % (1 << 31) - return self.cur - -class AstAssign(object): - def __init__(self, name, expr): - self.name = name - self.expr = expr - -class AstWhile(object): - def __init__(self, test, body): - self.test = test - self.body = body - -class AstBinop(object): - def __init__(self, lhs, rhs, op): - self.lhs = lhs - self.rhs = rhs - self.op = op - -class AstPrint(object): - def __init__(self, expr): - self.expr = expr - -class AstIf(object): - def __init__(self, test, then, orelse): - self.test = test - self.then = then - self.orelse = orelse - -class State(object): - def __init__(self): - self.syms = {} - -def visit(visitor, node): - if isinstance(node, list): - for s in node: - visit(visitor, s) - return None - - type_name = type(node).__name__.lower() - return getattr(visitor, "visit_" + type_name)(node) - -class InterpVisitor(object): - def __init__(self): - self.syms = {} - - def visit(self, node): - return visit(self, node) - - def visit_astassign(self, node): - v = self.visit(node.expr) - self.syms[node.name] = v - - def visit_int(self, node): - return node - - def visit_str(self, node): - return self.syms[node] - - def visit_astwhile(self, node): - while True: - v = self.visit(node.test) - if not v: - break - self.visit(node.body) - - def visit_astbinop(self, node): - l = self.visit(node.lhs) - r = self.visit(node.rhs) - if node.op == '+': - return l + r - if node.op == '-': - return l - r - if node.op == '*': - return l * r - if node.op == '%': - return l % r - if node.op == "<": - return l < r - if node.op == "<=": - return l <= r - if node.op == "==": - return l == r - print node.op - 1/0 - - def visit_astif(self, node): - v = self.visit(node.test) - if v: - self.visit(node.then) - else: - self.visit(node.orelse) - - def visit_astprint(self, node): - v = self.visit(node.expr) - print v - -def run(node): - visit(InterpVisitor(), node) - -prog = [ - AstAssign("x", 100000), - AstAssign("t", 0), - AstWhile("x", [ - AstAssign("t", AstBinop("t", "x", '+')), - AstAssign("x", AstBinop("x", 1, '-')), - # AstPrint("x"), - ]), - AstPrint("t"), - ] - -prog = [ - AstAssign("i", 2), - AstAssign("t", 0), - AstWhile(AstBinop("i", 5000, '<'), [ - AstAssign("j", 2), - AstAssign("good", 1), - AstWhile(AstBinop(AstBinop("j", "j", '*'), "i", "<="), [ - AstIf(AstBinop(AstBinop("i", "j", "%"), 0, "=="), [ - AstAssign("good", 0), - ], [ - ]), - AstAssign("j", AstBinop("j", 1, "+")), - ]), - AstIf("good", [ - AstPrint("i"), - AstAssign("t", AstBinop("t", "i", "+")), - ], []), - AstAssign("i", AstBinop("i", 1, "+")), - ]), - AstPrint("t"), - ] - -run(prog) diff --git a/benchmarks/nbody.py b/benchmarks/nbody.py deleted file mode 100644 index 8c5be56a2..000000000 --- a/benchmarks/nbody.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- -# The Computer Language Benchmarks Game -# http://shootout.alioth.debian.org/ -# -# contributed by Kevin Carson -# modified by Tupteq, Fredrik Johansson, and Daniel Nanz - -import time - -def combinations(l): - result = [] - for x in xrange(len(l) - 1): - for j in xrange(x+1, len(l)): - # ls = l[x+1:] - # for y in ls: - y = l[j] - result.append((l[x],y)) - return result - -PI = 3.14159265358979323 -SOLAR_MASS = 4 * PI * PI -DAYS_PER_YEAR = 365.24 - -BODIES = { -1: ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), - -2: ([4.84143144246472090e+00, - -1.16032004402742839e+00, - -1.03622044471123109e-01], - [1.66007664274403694e-03 * DAYS_PER_YEAR, - 7.69901118419740425e-03 * DAYS_PER_YEAR, - -6.90460016972063023e-05 * DAYS_PER_YEAR], - 9.54791938424326609e-04 * SOLAR_MASS), - -3: ([8.34336671824457987e+00, - 4.12479856412430479e+00, - -4.03523417114321381e-01], - [-2.76742510726862411e-03 * DAYS_PER_YEAR, - 4.99852801234917238e-03 * DAYS_PER_YEAR, - 2.30417297573763929e-05 * DAYS_PER_YEAR], - 2.85885980666130812e-04 * SOLAR_MASS), - -4: ([1.28943695621391310e+01, - -1.51111514016986312e+01, - -2.23307578892655734e-01], - [2.96460137564761618e-03 * DAYS_PER_YEAR, - 2.37847173959480950e-03 * DAYS_PER_YEAR, - -2.96589568540237556e-05 * DAYS_PER_YEAR], - 4.36624404335156298e-05 * SOLAR_MASS), - -5: ([1.53796971148509165e+01, - -2.59193146099879641e+01, - 1.79258772950371181e-01], - [2.68067772490389322e-03 * DAYS_PER_YEAR, - 1.62824170038242295e-03 * DAYS_PER_YEAR, - -9.51592254519715870e-05 * DAYS_PER_YEAR], - 5.15138902046611451e-05 * SOLAR_MASS) } - - -SYSTEM = BODIES.values() -PAIRS = combinations(SYSTEM) - - -def advance(dt, n): - bodies=SYSTEM - pairs=PAIRS - - for i in xrange(n): - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) - b1m = m1 * mag - b2m = m2 * mag - v1[0] = v1[0] - dx * b2m - v1[1] = v1[1] - dy * b2m - v1[2] = v1[2] - dz * b2m - v2[0] = v2[0] + dx * b1m - v2[1] = v2[1] + dy * b1m - v2[2] = v2[2] + dz * b1m - for (r, (vx, vy, vz), m) in bodies: - r[0] = r[0] + dt * vx - r[1] = r[1] + dt * vy - r[2] = r[2] + dt * vz - - -def report_energy(): - bodies=SYSTEM - pairs=PAIRS - e=0.0 - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - e = e - (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) - for (r, (vx, vy, vz), m) in bodies: - e = e + m * (vx * vx + vy * vy + vz * vz) / 2. - return e - -def offset_momentum(ref, bodies, px, py, pz): - - for (r, (vx, vy, vz), m) in bodies: - px = px - vx * m - py = py - vy * m - pz = pz - vz * m - (r, v, m) = ref - v[0] = px / m - v[1] = py / m - v[2] = pz / m - -NUMBER_OF_ITERATIONS = 20000 - -def main(n, ref): - # XXX warmup - - times = [] - for i in range(n): - t0 = time.time() - offset_momentum(BODIES[ref], SYSTEM, 0.0, 0.0, 0.0) - e1 = report_energy() - advance(0.01, NUMBER_OF_ITERATIONS) - print e1 - report_energy() - tk = time.time() - times.append(tk - t0) - return times - -main(40,2) - diff --git a/benchmarks/nbody_med.py b/benchmarks/nbody_med.py deleted file mode 100644 index 3f0fadc98..000000000 --- a/benchmarks/nbody_med.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# The Computer Language Benchmarks Game -# http://shootout.alioth.debian.org/ -# -# contributed by Kevin Carson -# modified by Tupteq, Fredrik Johansson, and Daniel Nanz - -import time - -def combinations(l): - result = [] - for x in xrange(len(l) - 1): - for j in xrange(x+1, len(l)): - # ls = l[x+1:] - # for y in ls: - y = l[j] - result.append((l[x],y)) - return result - -PI = 3.14159265358979323 -SOLAR_MASS = 4 * PI * PI -DAYS_PER_YEAR = 365.24 - -BODIES = { -1: ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), - -2: ([4.84143144246472090e+00, - -1.16032004402742839e+00, - -1.03622044471123109e-01], - [1.66007664274403694e-03 * DAYS_PER_YEAR, - 7.69901118419740425e-03 * DAYS_PER_YEAR, - -6.90460016972063023e-05 * DAYS_PER_YEAR], - 9.54791938424326609e-04 * SOLAR_MASS), - -3: ([8.34336671824457987e+00, - 4.12479856412430479e+00, - -4.03523417114321381e-01], - [-2.76742510726862411e-03 * DAYS_PER_YEAR, - 4.99852801234917238e-03 * DAYS_PER_YEAR, - 2.30417297573763929e-05 * DAYS_PER_YEAR], - 2.85885980666130812e-04 * SOLAR_MASS), - -4: ([1.28943695621391310e+01, - -1.51111514016986312e+01, - -2.23307578892655734e-01], - [2.96460137564761618e-03 * DAYS_PER_YEAR, - 2.37847173959480950e-03 * DAYS_PER_YEAR, - -2.96589568540237556e-05 * DAYS_PER_YEAR], - 4.36624404335156298e-05 * SOLAR_MASS), - -5: ([1.53796971148509165e+01, - -2.59193146099879641e+01, - 1.79258772950371181e-01], - [2.68067772490389322e-03 * DAYS_PER_YEAR, - 1.62824170038242295e-03 * DAYS_PER_YEAR, - -9.51592254519715870e-05 * DAYS_PER_YEAR], - 5.15138902046611451e-05 * SOLAR_MASS) } - - -SYSTEM = BODIES.values() -PAIRS = combinations(SYSTEM) - - -def advance(dt, n): - bodies=SYSTEM - pairs=PAIRS - - for i in xrange(n): - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) - b1m = m1 * mag - b2m = m2 * mag - v1[0] = v1[0] - dx * b2m - v1[1] = v1[1] - dy * b2m - v1[2] = v1[2] - dz * b2m - v2[0] = v2[0] + dx * b1m - v2[1] = v2[1] + dy * b1m - v2[2] = v2[2] + dz * b1m - for (r, (vx, vy, vz), m) in bodies: - r[0] = r[0] + dt * vx - r[1] = r[1] + dt * vy - r[2] = r[2] + dt * vz - - -def report_energy(): - bodies=SYSTEM - pairs=PAIRS - e=0.0 - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - e = e - (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) - for (r, (vx, vy, vz), m) in bodies: - e = e + m * (vx * vx + vy * vy + vz * vz) / 2. - return e - -def offset_momentum(ref, bodies, px, py, pz): - - for (r, (vx, vy, vz), m) in bodies: - px = px - vx * m - py = py - vy * m - pz = pz - vz * m - (r, v, m) = ref - v[0] = px / m - v[1] = py / m - v[2] = pz / m - -NUMBER_OF_ITERATIONS = 5000 - -def main(n, ref): - # XXX warmup - - times = [] - for i in range(n): - t0 = time.time() - offset_momentum(BODIES[ref], SYSTEM, 0.0, 0.0, 0.0) - e1 = report_energy() - advance(0.01, NUMBER_OF_ITERATIONS) - print e1 - report_energy() - tk = time.time() - times.append(tk - t0) - return times - -main(40,2) - - diff --git a/benchmarks/raytrace.py b/benchmarks/raytrace.py deleted file mode 100644 index c6566139a..000000000 --- a/benchmarks/raytrace.py +++ /dev/null @@ -1,385 +0,0 @@ -# This file contains definitions for a simple raytracer. -# Copyright Callum and Tony Garnock-Jones, 2008. -# This file may be freely redistributed under the MIT license, -# http://www.opensource.org/licenses/mit-license.php - -import math - -EPSILON = 0.00001 -INF = 1.0e9 - -class Vector(object): - def __init__(self, initx, inity, initz): - self.x = initx - self.y = inity - self.z = initz - - def __str__(self): - return '(%s,%s,%s)' % (self.x, self.y, self.z) - - def __repr__(self): - return 'Vector(%s,%s,%s)' % (self.x, self.y, self.z) - - def magnitude(self): - return math.sqrt(self.dot(self)) - - def __add__(self, other): - return Vector(self.x + other.x, self.y + other.y, self.z + other.z) - - def __sub__(self, other): - return Vector(self.x - other.x, self.y - other.y, self.z - other.z) - - def scale(self, factor): - return Vector(factor * self.x, factor * self.y, factor * self.z) - - def dot(self, other): - return (self.x * other.x) + (self.y * other.y) + (self.z * other.z) - - def cross(self, other): - return Vector(self.y * other.z - self.z * other.y, - self.z * other.x - self.x * other.z, - self.x * other.y - self.y * other.x) - - def normalized(self): - return self.scale(1.0 / self.magnitude()) - - def negated(self): - return self.scale(-1) - - def __eq__(self, other): - return (self.x == other.x) and (self.y == other.y) and (self.z == other.z) - - def isVector(self): - return True - - def isPoint(self): - return False - - def reflectThrough(self, normal): - d = normal.scale(self.dot(normal)) - return self - d.scale(2) - -VZERO = Vector(0,0,0) -VRIGHT = Vector(1,0,0) -VUP = Vector(0,1,0) -VOUT = Vector(0,0,1) - -if not (VRIGHT.reflectThrough(VUP) == VRIGHT): - print 1/0 -if not (Vector(-1,-1,0).reflectThrough(VUP) == Vector(-1,1,0)): - print 1/0 - -class Point(object): - def __init__(self, initx, inity, initz): - self.x = initx - self.y = inity - self.z = initz - - def __str__(self): - return '(%s,%s,%s)' % (self.x, self.y, self.z) - - def __repr__(self): - return 'Point(%s,%s,%s)' % (self.x, self.y, self.z) - - def __add__(self, other): - return Point(self.x + other.x, self.y + other.y, self.z + other.z) - - def __sub__(self, other): - return Vector(self.x - other.x, self.y - other.y, self.z - other.z) - - def isVector(self): - return False - - def isPoint(self): - return True - -class Sphere(object): - def __init__(self, centre, radius): - self.centre = centre - self.radius = radius - - def __repr__(self): - return 'Sphere(%s,%s)' % (repr(self.centre), self.radius) - - def intersectionTime(self, ray): - cp = self.centre - ray.point - v = cp.dot(ray.vector) - discriminant = (self.radius * self.radius) - (cp.dot(cp) - v*v) - if discriminant < 0: - return INF + 1 - else: - return v - math.sqrt(discriminant) - - def normalAt(self, p): - return (p - self.centre).normalized() - -class Halfspace(object): - def __init__(self, point, normal): - self.point = point - self.normal = normal.normalized() - - def __repr__(self): - return 'Halfspace(%s,%s)' % (repr(self.point), repr(self.normal)) - - def intersectionTime(self, ray): - v = ray.vector.dot(self.normal) - if v: - return 1 / -v - else: - return INF + 1 - - def normalAt(self, p): - return self.normal - -class Ray(object): - def __init__(self, point, vector): - self.point = point - self.vector = vector.normalized() - - def __repr__(self): - return 'Ray(%s,%s)' % (repr(self.point), repr(self.vector)) - - def pointAtTime(self, t): - return self.point + self.vector.scale(t) - -PZERO = Point(0,0,0) - -a = Vector(3,4,12) -b = Vector(1,1,1) - -class PpmCanvas(object): - def __init__(self, width, height, filenameBase): - self.bytes = [0] * (width * height * 3) - for i in range(width * height): - self.bytes[i * 3 + 2] = 255 - self.width = width - self.height = height - self.filenameBase = filenameBase - - def plot(self, x, y, r, g, b): - i = ((self.height - y - 1) * self.width + x) * 3 - self.bytes[i ] = max(0, min(255, int(r * 255))) - self.bytes[i+1] = max(0, min(255, int(g * 255))) - self.bytes[i+2] = max(0, min(255, int(b * 255))) - - def save(self): - with open(self.filenameBase + '.ppm', 'wb') as f: - f.write('P6 %d %d 255\n' % (self.width, self.height)) - l = [] - for c in self.bytes: - l.append(chr(c)) - f.write(''.join(l)) - -def firstIntersection(intersections): - result = intersections[0][0], INF+1, intersections[0][2] - for i in intersections: - candidateT = i[1] - if candidateT < INF and candidateT > -EPSILON: - if result[1] > INF or candidateT < result[1]: - result = i - return result - -class Scene(object): - def __init__(self): - self.objects = [] - self.lightPoints = [] - self.position = Point(0, 1.8, 10) - self.lookingAt = PZERO - self.fieldOfView = 45 - self.recursionDepth = 0 - - def lookAt(self, p): - self.lookingAt = p - - def addObject(self, on, oi, sc): - self.objects.append((on, oi, sc)) - - def addLight(self, p): - self.lightPoints.append(p) - - def render(self, canvas): - #print 'Computing field of view' - fovRadians = math.pi * (self.fieldOfView / 2.0) / 180.0 - halfWidth = math.tan(fovRadians) - halfHeight = 0.75 * halfWidth - width = halfWidth * 2 - height = halfHeight * 2 - pixelWidth = width / (canvas.width - 1) - pixelHeight = height / (canvas.height - 1) - - eye = Ray(self.position, self.lookingAt - self.position) - vpRight = eye.vector.cross(VUP).normalized() - vpUp = vpRight.cross(eye.vector).normalized() - - #print 'Looping over pixels' - previousfraction = 0.0 - for y in range(canvas.height): - currentfraction = 1.0 * y / canvas.height - if currentfraction - previousfraction > 0.05: - print '%d%% complete' % int(currentfraction * 100) - previousfraction = currentfraction - for x in range(canvas.width): - xcomp = vpRight.scale(x * pixelWidth - halfWidth) - ycomp = vpUp.scale(y * pixelHeight - halfHeight) - ray = Ray(eye.point, eye.vector + xcomp + ycomp) - colour = self.rayColour(ray) - canvas.plot(x,y,colour[0], colour[1], colour[2]) - - print 'Complete.' - canvas.save() - - def rayColour(self, ray): - if self.recursionDepth > 3: - return (0.0,0.0,0.0) - - self.recursionDepth = self.recursionDepth + 1 - intersections = [] - for on, oi, sc in self.objects: - intersections.append((on, oi(ray), sc)) - # intersections = [(on, oi(ray), sc) for (on, oi, sc) in self.objects] - i = firstIntersection(intersections) - if i[1] > INF: - self.recursionDepth = self.recursionDepth - 1 - return (0.0,0.0,0.0) ## the background colour - else: - (o, t, s) = i - p = ray.pointAtTime(t) - r = s(self, ray, p, o(p)) - self.recursionDepth = self.recursionDepth - 1 - return r - - def _lightIsVisible(self, l, p): - for (on, oi, sc) in self.objects: - t = oi(Ray(p,l - p)) - if t < INF and t > EPSILON: - return False - return True - - def visibleLights(self, p): - result = [] - for l in self.lightPoints: - if self._lightIsVisible(l, p): - result.append(l) - return result - -def addColours(a, scale, b): - return (a[0] + scale * b[0], - a[1] + scale * b[1], - a[2] + scale * b[2]) - -class SimpleSurface(object): - def __init__(self, baseColour): - self.baseColour = baseColour - self.specularCoefficient = 0.2 - self.lambertCoefficient = 0.6 - self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient - - def baseColourAt(self, p): - return self.baseColour - - def colourAt(self, scene, ray, p, normal): - b = self.baseColourAt(p) - - c = (0.0, 0.0, 0.0) - if self.specularCoefficient > 0: - reflectedRay = Ray(p, ray.vector.reflectThrough(normal)) - #print p, normal, ray.vector, reflectedRay.vector - reflectedColour = scene.rayColour(reflectedRay) - c = addColours(c, self.specularCoefficient, reflectedColour) - - if self.lambertCoefficient > 0: - lambertAmount = 0.0 - for lightPoint in scene.visibleLights(p): - contribution = (lightPoint - p).normalized().dot(normal) - if contribution > 0: - lambertAmount = lambertAmount + contribution - lambertAmount = min(1,lambertAmount) - c = addColours(c, self.lambertCoefficient * lambertAmount, b) - - if self.ambientCoefficient > 0: - c = addColours(c, self.ambientCoefficient, b) - - return c - -class CheckerboardSurface(object): - def __init__(self): - self.baseColour = (1.0, 1.0, 1.0) - self.specularCoefficient = 0.2 - self.lambertCoefficient = 0.6 - self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient - self.otherColour = (0.0, 0.0, 0.0) - self.checkSize = 1 - - def baseColourAt(self, p): - v = p - PZERO - v.scale(1.0 / self.checkSize) - if (int(abs(v.x) + 0.5) + \ - int(abs(v.y) + 0.5) + \ - int(abs(v.z) + 0.5)) \ - % 2: - return self.otherColour - else: - return self.baseColour - - def colourAt(self, scene, ray, p, normal): - b = self.baseColourAt(p) - - c = (0.0,0.0,0.0) - if self.specularCoefficient > 0: - reflectedRay = Ray(p, ray.vector.reflectThrough(normal)) - #print p, normal, ray.vector, reflectedRay.vector - reflectedColour = scene.rayColour(reflectedRay) - c = addColours(c, self.specularCoefficient, reflectedColour) - - if self.lambertCoefficient > 0: - lambertAmount = 0.0 - for lightPoint in scene.visibleLights(p): - contribution = (lightPoint - p).normalized().dot(normal) - if contribution > 0: - lambertAmount = lambertAmount + contribution - lambertAmount = min(1,lambertAmount) - c = addColours(c, self.lambertCoefficient * lambertAmount, b) - - if self.ambientCoefficient > 0: - c = addColours(c, self.ambientCoefficient, b) - - return c - -def _main(): - Canvas = PpmCanvas - # c = Canvas(4,2,'test_raytrace_tiny') - # c = Canvas(80,60,'test_raytrace_small') - # c = Canvas(160,120,'test_raytrace') - # c = Canvas(320,240,'test_raytrace') - c = Canvas(640,480,'test_raytrace_big') - s = Scene() - s.addLight(Point(30, 30, 10)) - s.addLight(Point(-10, 100, 30)) - s.lookAt(Point(0, 2, 0)) - - obj = Sphere(Point(1,3,-10), 2) - surf = SimpleSurface((1.0,1.0,0.0)) - surf.specularCoefficient = 0.5 - surf.lambertCoefficient = 0.5 - surf.ambientCoefficient = 0.0 - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - for y in range(6): - obj = Sphere(Point(-3 - y * 0.4, 2.3, -5), 0.4) - surf = SimpleSurface((y / 6.0, 1 - y / 6.0, 0.5)) - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - obj = Halfspace(Point(0,0,0), VUP) - surf = CheckerboardSurface() - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - s.render(c) - -def main(n): - import time - times = [] - for i in range(n): - t1 = time.time() - _main() - t2 = time.time() - times.append(t2 - t1) - return times - -main(1) diff --git a/docs/INSTALLING b/docs/INSTALLING deleted file mode 100644 index c9191d3ac..000000000 --- a/docs/INSTALLING +++ /dev/null @@ -1,89 +0,0 @@ -DEPENDENCIES: - -# Pyston expects to find all of its dependencies in ~/pyston_deps: -mkdir ~/pyston_deps - -GCC (assuming 4.8.2): -sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev make build-essential libtool zip gcc-multilib autogen -cd ~/pyston_deps -wget 'http://www.netgull.com/gcc/releases/gcc-4.8.2/gcc-4.8.2.tar.bz2' -tar xvf gcc-4.8.2.tar.bz2 -mkdir gcc-4.8.2-{build,install} -cd gcc-4.8.2-build -# Space-saving configuration: -../gcc-4.8.2/configure --disable-bootstrap --enable-languages=c,c++ --prefix=$HOME/pyston_deps/gcc-4.8.2-install -# full configuration: -# ../gcc-4.8.2/configure --prefix=$HOME/pyston_deps/gcc-4.8.2-install -make -j4 -make check -make install - -curses, zlib: -sudo apt-get install libncurses5-dev zlib1g-dev - -LLVM: # note: requires gcc-4.7+, and pyston by default assumes you've installed gcc-4.8.2 as above) -cd ~/pyston_deps -git clone http://llvm.org/git/llvm.git llvm-trunk -git clone http://llvm.org/git/clang.git llvm-trunk/tools/clang -cd ~/pyston/src -make llvm_up -make llvm_configure -make llvm -j4 - -libunwind: -download from http://download.savannah.gnu.org/releases/libunwind - -valgrind: -not sure exactly what version is required, but 3.7.0 doesn't seem quite good enough (can't handle 'tzcnt' instruction) -cd ~/pyston_deps -wget http://valgrind.org/downloads/valgrind-3.9.0.tar.bz2 -tar xvf valgrind-3.9.0.tar.bz2 -mkdir valgrind-3.9.0-install -cd valgrind-3.9.0 -./configure --prefix=$HOME/pyston_deps/valgrind-3.9.0-install -make -j4 -make install -# Add this line to Makefile.local: -VALGRIND := VALGRIND_LIB=$(HOME)/pyston_deps/valgrind-3.9.0-install/lib/valgrind $(HOME)/pyston_deps/valgrind-3.9.0-install/bin/valgrind -sudo apt-get install libc6-dbg - -OPTIONAL DEPENDENCIES: - -ccache, distcc: -sudo apt-get install ccache -sudo apt-get install distcc distcc-pump - -gtest: -cd ~/pyston_deps -wget https://googletest.googlecode.com/files/gtest-1.7.0.zip -unzip gtest-1.7.0.zip -cd gtest-1.7.0 -./configure -make -j4 - -gdb: -cd ~/pyston_deps -wget http://ftp.gnu.org/gnu/gdb/gdb-7.6.2.tar.gz -tar xvf gdb-7.6.2.tar.gz -cd gdb-7.6.2 -./configure -make -j4 -# then add this to Makefile.local: -GDB := $(HOME)/pyston_deps/gdb-7.6.2/gdb/gdb - -gperftools (-lprofiler): -download from http://code.google.com/p/gperftools/downloads/list -standard ./configure, make, make install - -gold, if not installed (instructions mostly from http://llvm.org/docs/GoldPlugin.html): -cd ~/pyston_deps -git clone --depth 1 git://sourceware.org/git/binutils-gdb.git binutils -mkdir binutils-build -cd binutils-build -../binutils/configure --enable-gold --enable-plugins --disable-werror -make all-gold - -perf: -sudo apt-get install linux-tools -sudo apt-get install linux-tools-`uname -r` -# may need to strip off the -generic from that last one diff --git a/docs/PROFILING b/docs/PROFILING deleted file mode 100644 index 8ea69c2db..000000000 --- a/docs/PROFILING +++ /dev/null @@ -1,5 +0,0 @@ -turning off ASLR: -$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space -gdb does this automatically, but disabling it outside of gdb can be nice to correlate runs with other runs or debugging. - -for better tracebacks, make sure that NoFramePointerElim is set to true in entry.cpp diff --git a/include/Python.h b/include/Python.h deleted file mode 100644 index e5bc0728e..000000000 --- a/include/Python.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef PYSTON_EXTINCLUDE_PYTHON_H -#define PYSTON_EXTINCLUDE_PYTHON_H - -#include -#include -#include -#include -#include - -//struct PyObject { -//}; -//typedef struct PyObject PyObject; -typedef void PyObject; - -#define Py_INCREF(x) -bool PyArg_ParseTuple(PyObject*, const char*, ...); -PyObject* Py_BuildValue(const char*, ...); - -typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); -struct PyMethodDef { - const char *ml_name; /* The name of the built-in function/method */ - PyCFunction ml_meth; /* The C function that implements it */ - int ml_flags; /* Combination of METH_xxx flags, which mostly - describe the args expected by the C func */ - const char *ml_doc; /* The __doc__ attribute, or NULL */ -}; -typedef struct PyMethodDef PyMethodDef; - -#define METH_VARARGS 0x0001 - -#ifdef __cplusplus -#define PyMODINIT_FUNC extern "C" void -#else -#define PyMODINIT_FUNC void -#endif - -#define PYTHON_API_VERSION 1013 -#define PYTHON_API_STRING "1013" - -PyObject* Py_InitModule4(const char *arg0, PyMethodDef *arg1, const char *arg2, PyObject *arg3, int arg4); -#define Py_InitModule(name, methods) \ - Py_InitModule4(name, methods, (char *)NULL, (PyObject *)NULL, \ - PYTHON_API_VERSION) - -#endif diff --git a/llvm_patches/0001-Support-emitting-stackmap-sections-for-ELF-object-fi.patch b/llvm_patches/0001-Support-emitting-stackmap-sections-for-ELF-object-fi.patch deleted file mode 100644 index 982b6910f..000000000 --- a/llvm_patches/0001-Support-emitting-stackmap-sections-for-ELF-object-fi.patch +++ /dev/null @@ -1,196 +0,0 @@ -From b370f4621298ec557e356e21fa0fa675a21d2331 Mon Sep 17 00:00:00 2001 -From: Kevin Modzelewski -Date: Fri, 21 Mar 2014 16:06:58 -0700 -Subject: [PATCH] Support emitting stackmap sections for ELF object files as - well - ---- - lib/IR/Function.cpp | 8 ++- - lib/MC/MCObjectFileInfo.cpp | 5 ++ - lib/Target/X86/X86AsmPrinter.cpp | 2 + - test/CodeGen/X86/stackmap-elf.ll | 124 ++++++++++++++++++++++++++++++++++++++ - 4 files changed, 138 insertions(+), 1 deletion(-) - create mode 100644 test/CodeGen/X86/stackmap-elf.ll - -diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp -index c1fa372..d11727d 100644 ---- a/lib/IR/Function.cpp -+++ b/lib/IR/Function.cpp -@@ -681,7 +681,13 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, - while (!TableRef.empty()) - ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context)); - -- return FunctionType::get(ResultTy, ArgTys, false); -+ bool variadic = false; -+ if (ArgTys.size() && ArgTys.back() == Type::getVoidTy(Context)) { -+ variadic = true; -+ ArgTys.pop_back(); -+ } -+ -+ return FunctionType::get(ResultTy, ArgTys, variadic); - } - - bool Intrinsic::isOverloaded(ID id) { -diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp -index 931b354..40899c1 100644 ---- a/lib/MC/MCObjectFileInfo.cpp -+++ b/lib/MC/MCObjectFileInfo.cpp -@@ -537,6 +537,11 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Triple T) { - DwarfAddrSection = - Ctx->getELFSection(".debug_addr", ELF::SHT_PROGBITS, 0, - SectionKind::getMetadata()); -+ -+ StackMapSection = -+ Ctx->getELFSection(".llvm_stackmaps", ELF::SHT_PROGBITS, -+ ELF::SHF_ALLOC, -+ SectionKind::getMetadata()); - } - - -diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp -index e6ad2f1..62f8f23 100644 ---- a/lib/Target/X86/X86AsmPrinter.cpp -+++ b/lib/Target/X86/X86AsmPrinter.cpp -@@ -723,6 +723,8 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { - } - Stubs.clear(); - } -+ -+ SM.serializeToStackMapSection(); - } - } - -diff --git a/test/CodeGen/X86/stackmap-elf.ll b/test/CodeGen/X86/stackmap-elf.ll -new file mode 100644 -index 0000000..1c838e2 ---- /dev/null -+++ b/test/CodeGen/X86/stackmap-elf.ll -@@ -0,0 +1,125 @@ -+; XFAIL: -+; RUN: llc < %s -mtriple=x86_64-linux -mcpu=corei7 -disable-fp-elim | FileCheck %s -+; -+; Note: the main stackmap tests are in stackmap.ll; this file is for -+; ensuring that the functionality transfers to ELF. -+; -+; Note: Print verbose stackmaps using -debug-only=stackmaps. -+ -+; CHECK-LABEL: .section .llvm_stackmaps -+; CHECK-NEXT: __LLVM_StackMaps: -+; CHECK-NEXT: .long 0 -+; Num LargeConstants -+; CHECK-NEXT: .long 1 -+; CHECK-NEXT: .quad 4294967296 -+; Num Callsites -+; CHECK-NEXT: .long 8 -+ -+; Constant arguments -+; -+; CHECK-NEXT: .quad 1 -+; CHECK-NEXT: .long .L{{.*}}-constantargs -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .short 2 -+; SmallConstant -+; CHECK-NEXT: .byte 4 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .long -1 -+; LargeConstant at index 0 -+; CHECK-NEXT: .byte 5 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .long 0 -+ -+define void @constantargs() { -+entry: -+ %0 = inttoptr i64 12345 to i8* -+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 1, i32 15, i8* %0, i32 0, i64 4294967295, i64 4294967296) -+ ret void -+} -+ -+; Property Read -+; CHECK-LABEL: .long .L{{.*}}-propertyRead -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .short 2 -+; CHECK-NEXT: .byte 1 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short {{[0-9]+}} -+; CHECK-NEXT: .long 0 -+; CHECK-NEXT: .byte 1 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short {{[0-9]+}} -+; CHECK-NEXT: .long 0 -+define i64 @propertyRead(i64* %obj) { -+entry: -+ %resolveRead = inttoptr i64 -559038737 to i8* -+ %result = call anyregcc i64 (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.i64(i64 5, i32 15, i8* %resolveRead, i32 1, i64* %obj) -+ %add = add i64 %result, 3 -+ ret i64 %add -+} -+ -+; i64 JS Call -+; -+; 2 live variables in registers. -+; -+; CHECK-LABEL: .long .L{{.*}}-jsIntCall -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .short 2 -+; CHECK-NEXT: .byte 1 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short {{[0-9]+}} -+; CHECK-NEXT: .long 0 -+; CHECK-NEXT: .byte 1 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short {{[0-9]+}} -+; CHECK-NEXT: .long 0 -+define i64 @jsIntCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) { -+entry: -+ %resolveCall = inttoptr i64 -559038737 to i8* -+ %result = call i64 (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.i64(i64 8, i32 15, i8* %resolveCall, i32 2, i64* %obj, i64 %arg, i64 %l1, i64 %l2) -+ %add = add i64 %result, 3 -+ ret i64 %add -+} -+ -+; Spilled stack map values. -+; -+; Verify 17 stack map entries. -+; -+; CHECK-LABEL: .long .L{{.*}}-spilledValue -+; CHECK-NEXT: .short 0 -+; CHECK-NEXT: .short 17 -+; -+; Check that at least one is a spilled entry from RBP. -+; Location: Indirect RBP + ... -+; CHECK: .byte 3 -+; CHECK-NEXT: .byte 8 -+; CHECK-NEXT: .short 6 -+define void @spilledValue(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) { -+entry: -+ call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 11, i32 15, i8* null, i32 5, i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) -+ ret void -+} -+ -+; Test a 64-bit ID. -+; -+; CHECK: .quad 4294967295 -+; CHECK-LABEL: .long .L{{.*}}-longid -+; CHECK: .quad 4294967296 -+; CHECK-LABEL: .long .L{{.*}}-longid -+; CHECK: .quad 9223372036854775807 -+; CHECK-LABEL: .long .L{{.*}}-longid -+; CHECK: .quad -1 -+; CHECK-LABEL: .long .L{{.*}}-longid -+define void @longid() { -+entry: -+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 4294967295, i32 0, i8* null, i32 0) -+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 4294967296, i32 0, i8* null, i32 0) -+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 9223372036854775807, i32 0, i8* null, i32 0) -+ tail call void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 -1, i32 0, i8* null, i32 0) -+ ret void -+} -+ -+declare void @llvm.experimental.stackmap(i64, i32, ...) -+declare void @llvm.experimental.patchpoint.void(i64, i32, i8*, i32, ...) -+declare i64 @llvm.experimental.patchpoint.i64(i64, i32, i8*, i32, ...) --- -1.7.9.5 - diff --git a/llvm_patches/0002-Stackmaps-Update-the-stackmap-format-to-use-64bit.patch b/llvm_patches/0002-Stackmaps-Update-the-stackmap-format-to-use-64bit.patch deleted file mode 100644 index 7f3abef07..000000000 --- a/llvm_patches/0002-Stackmaps-Update-the-stackmap-format-to-use-64bit.patch +++ /dev/null @@ -1,573 +0,0 @@ -From c3bb0f324eaa62996ccea2751af8dbb7a6c08368 Mon Sep 17 00:00:00 2001 -From: Juergen Ributzka -Date: Wed, 5 Feb 2014 15:06:36 -0800 -Subject: [PATCH 1/1] [Stackmaps] Update the stackmap format to use 64bit - relocations for the function address and properly align all entries. - ---- - docs/StackMaps.rst | 10 +++-- - include/llvm/CodeGen/StackMaps.h | 2 +- - lib/CodeGen/StackMaps.cpp | 49 ++++++++++++--------- - test/CodeGen/X86/anyregcc.ll | 41 ++++++++++-------- - test/CodeGen/X86/stackmap-liveness.ll | 81 ++++++++++++++++++++++++++++++----- - test/CodeGen/X86/stackmap.ll | 68 +++++++++++++++-------------- - 6 files changed, 166 insertions(+), 85 deletions(-) - -diff --git a/docs/StackMaps.rst b/docs/StackMaps.rst -index 57c37ea..dbf30ad 100644 ---- a/docs/StackMaps.rst -+++ b/docs/StackMaps.rst -@@ -315,15 +315,15 @@ format of this section follows: - - uint32 : Reserved (header) - uint32 : NumFunctions -+ uint32 : NumConstants -+ uint32 : NumRecords - StkSizeRecord[NumFunctions] { -- uint32 : Function Offset -- uint32 : Stack Size -+ uint64 : Function Address -+ uint64 : Stack Size - } -- uint32 : NumConstants - Constants[NumConstants] { - uint64 : LargeConstant - } -- uint32 : NumRecords - StkMapRecord[NumRecords] { - uint64 : PatchPoint ID - uint32 : Instruction Offset -@@ -335,12 +335,14 @@ format of this section follows: - uint16 : Dwarf RegNum - int32 : Offset or SmallConstant - } -+ uint16 : Padding - uint16 : NumLiveOuts - LiveOuts[NumLiveOuts] - uint16 : Dwarf RegNum - uint8 : Reserved - uint8 : Size in Bytes - } -+ uint32 : Padding (only if required to align to 8 byte) - } - - The first byte of each location encodes a type that indicates how to -diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h -index bd4c3db..9ea1f57 100644 ---- a/include/llvm/CodeGen/StackMaps.h -+++ b/include/llvm/CodeGen/StackMaps.h -@@ -133,7 +133,7 @@ public: - private: - typedef SmallVector LocationVec; - typedef SmallVector LiveOutVec; -- typedef MapVector FnStackSizeMap; -+ typedef MapVector FnStackSizeMap; - - struct CallsiteInfo { - const MCExpr *CSOffsetExpr; -diff --git a/lib/CodeGen/StackMaps.cpp b/lib/CodeGen/StackMaps.cpp -index 1ec2587..df649f3 100644 ---- a/lib/CodeGen/StackMaps.cpp -+++ b/lib/CodeGen/StackMaps.cpp -@@ -230,7 +230,7 @@ void StackMaps::recordStackMapOpers(const MachineInstr &MI, uint64_t ID, - // Record the stack size of the current function. - const MachineFrameInfo *MFI = AP.MF->getFrameInfo(); - FnStackSize[AP.CurrentFnSym] = -- MFI->hasVarSizedObjects() ? ~0U : MFI->getStackSize(); -+ MFI->hasVarSizedObjects() ? UINT64_MAX : MFI->getStackSize(); - } - - void StackMaps::recordStackMap(const MachineInstr &MI) { -@@ -268,13 +268,13 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) { - /// - /// uint32 : Reserved (header) - /// uint32 : NumFunctions -+/// uint32 : NumConstants -+/// uint32 : NumRecords - /// StkSizeRecord[NumFunctions] { --/// uint32 : Function Offset --/// uint32 : Stack Size -+/// uint64 : Function Address -+/// uint64 : Stack Size - /// } --/// uint32 : NumConstants - /// int64 : Constants[NumConstants] --/// uint32 : NumRecords - /// StkMapRecord[NumRecords] { - /// uint64 : PatchPoint ID - /// uint32 : Instruction Offset -@@ -286,11 +286,14 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) { - /// uint16 : Dwarf RegNum - /// int32 : Offset - /// } -+/// uint16 : Padding - /// uint16 : NumLiveOuts --/// LiveOuts[NumLiveOuts] -+/// LiveOuts[NumLiveOuts] { - /// uint16 : Dwarf RegNum - /// uint8 : Reserved - /// uint8 : Size in Bytes -+/// } -+/// uint32 : Padding (only if required to align to 8 byte) - /// } - /// - /// Location Encoding, Type, Value: -@@ -324,33 +327,33 @@ void StackMaps::serializeToStackMapSection() { - - DEBUG(dbgs() << "********** Stack Map Output **********\n"); - -- // Header. -+ /// --- Header --- - AP.OutStreamer.EmitIntValue(0, 4); -- - // Num functions. -+ DEBUG(dbgs() << WSMP << "#functions = " << FnStackSize.size() << '\n'); - AP.OutStreamer.EmitIntValue(FnStackSize.size(), 4); -+ // Num constants. -+ DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.getNumConstants() -+ << '\n'); -+ AP.OutStreamer.EmitIntValue(ConstPool.getNumConstants(), 4); -+ // Num callsites. -+ DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << '\n'); -+ AP.OutStreamer.EmitIntValue(CSInfos.size(), 4); - -- // Stack size entries. -+ // Function stack size entries. - for (FnStackSizeMap::iterator I = FnStackSize.begin(), E = FnStackSize.end(); - I != E; ++I) { -- AP.OutStreamer.EmitSymbolValue(I->first, 4); -- AP.OutStreamer.EmitIntValue(I->second, 4); -+ AP.OutStreamer.EmitSymbolValue(I->first, 8); -+ AP.OutStreamer.EmitIntValue(I->second, 8); - } - -- // Num constants. -- AP.OutStreamer.EmitIntValue(ConstPool.getNumConstants(), 4); -- - // Constant pool entries. - for (unsigned i = 0; i < ConstPool.getNumConstants(); ++i) - AP.OutStreamer.EmitIntValue(ConstPool.getConstant(i), 8); - -- DEBUG(dbgs() << WSMP << "#callsites = " << CSInfos.size() << "\n"); -- AP.OutStreamer.EmitIntValue(CSInfos.size(), 4); -- -+ // Callsite entries. - for (CallsiteInfoList::const_iterator CSII = CSInfos.begin(), -- CSIE = CSInfos.end(); -- CSII != CSIE; ++CSII) { -- -+ CSIE = CSInfos.end(); CSII != CSIE; ++CSII) { - uint64_t CallsiteID = CSII->ID; - const LocationVec &CSLocs = CSII->Locations; - const LiveOutVec &LiveOuts = CSII->LiveOuts; -@@ -366,7 +369,9 @@ void StackMaps::serializeToStackMapSection() { - AP.OutStreamer.EmitValue(CSII->CSOffsetExpr, 4); - AP.OutStreamer.EmitIntValue(0, 2); // Reserved. - AP.OutStreamer.EmitIntValue(0, 2); // 0 locations. -+ AP.OutStreamer.EmitIntValue(0, 2); // padding. - AP.OutStreamer.EmitIntValue(0, 2); // 0 live-out registers. -+ AP.OutStreamer.EmitIntValue(0, 4); // padding. - continue; - } - -@@ -447,6 +452,8 @@ void StackMaps::serializeToStackMapSection() { - DEBUG(dbgs() << WSMP << " has " << LiveOuts.size() - << " live-out registers\n"); - -+ // Num live-out registers and padding to align to 4 byte. -+ AP.OutStreamer.EmitIntValue(0, 2); - AP.OutStreamer.EmitIntValue(LiveOuts.size(), 2); - - operIdx = 0; -@@ -461,6 +468,8 @@ void StackMaps::serializeToStackMapSection() { - AP.OutStreamer.EmitIntValue(0, 1); - AP.OutStreamer.EmitIntValue(LI->Size, 1); - } -+ // Emit alignment to 8 byte. -+ AP.OutStreamer.EmitValueToAlignment(8); - } - - AP.OutStreamer.AddBlankLine(); -diff --git a/test/CodeGen/X86/anyregcc.ll b/test/CodeGen/X86/anyregcc.ll -index 23f5d43..6adbc1b 100644 ---- a/test/CodeGen/X86/anyregcc.ll -+++ b/test/CodeGen/X86/anyregcc.ll -@@ -10,27 +10,32 @@ - ; CHECK-NEXT: .long 0 - ; Num Functions - ; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _test --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _property_access1 --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _property_access2 --; CHECK-NEXT: .long 24 --; CHECK-NEXT: .long _property_access3 --; CHECK-NEXT: .long 24 --; CHECK-NEXT: .long _anyreg_test1 --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _anyreg_test2 --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _patchpoint_spilldef --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _patchpoint_spillargs --; CHECK-NEXT: .long 88 - ; Num Constants --; CHECK-NEXT: .long 0 -+; CHECK-NEXT: .long 0 - ; Num Callsites --; CHECK-NEXT: .long 8 -+; CHECK-NEXT: .long 8 -+ -+; Functions and stack size -+; CHECK-NEXT: .quad _test -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _property_access1 -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _property_access2 -+; CHECK-NEXT: .quad 24 -+; CHECK-NEXT: .quad _property_access3 -+; CHECK-NEXT: .quad 24 -+; CHECK-NEXT: .quad _anyreg_test1 -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _anyreg_test2 -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _patchpoint_spilldef -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _patchpoint_spillargs -+; CHECK-NEXT: .quad 88 -+ -+; No constants - -+; Callsites - ; test - ; CHECK-LABEL: .long L{{.*}}-_test - ; CHECK-NEXT: .short 0 -diff --git a/test/CodeGen/X86/stackmap-liveness.ll b/test/CodeGen/X86/stackmap-liveness.ll -index 570e373..2b56750 100644 ---- a/test/CodeGen/X86/stackmap-liveness.ll -+++ b/test/CodeGen/X86/stackmap-liveness.ll -@@ -6,17 +6,21 @@ - - ; CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps - ; CHECK-NEXT: __LLVM_StackMaps: -+; Header - ; CHECK-NEXT: .long 0 - ; Num Functions - ; CHECK-NEXT: .long 2 --; CHECK-NEXT: .long _stackmap_liveness --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _mixed_liveness --; CHECK-NEXT: .long 8 - ; Num LargeConstants - ; CHECK-NEXT: .long 0 - ; Num Callsites - ; CHECK-NEXT: .long 5 -+ -+; Functions and stack size -+; CHECK-NEXT: .quad _stackmap_liveness -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _mixed_liveness -+; CHECK-NEXT: .quad 8 -+ - define void @stackmap_liveness() { - entry: - %a1 = call <2 x double> asm sideeffect "", "={xmm2}"() nounwind -@@ -24,13 +28,19 @@ entry: - ; CHECK-LABEL: .long L{{.*}}-_stackmap_liveness - ; CHECK-NEXT: .short 0 - ; CHECK-NEXT: .short 0 -+; Padding -+; CHECK-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; CHECK-NEXT: .short 0 -+; Align -+; CHECK-NEXT: .align 3 - - ; StackMap 1 (stackmap liveness information enabled) - ; STACK-LABEL: .long L{{.*}}-_stackmap_liveness - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .short 0 -+; Padding -+; STACK-NEXT: .short 0 - ; Num LiveOut Entries: 2 - ; STACK-NEXT: .short 2 - ; LiveOut Entry 1: %RSP (8 bytes) -@@ -41,13 +51,19 @@ entry: - ; STACK-NEXT: .short 19 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 16 -+; Align -+; STACK-NEXT: .align 3 - - ; StackMap 1 (patchpoint liveness information enabled) - ; PATCH-LABEL: .long L{{.*}}-_stackmap_liveness - ; PATCH-NEXT: .short 0 - ; PATCH-NEXT: .short 0 -+; Padding -+; PATCH-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; PATCH-NEXT: .short 0 -+; Align -+; PATCH-NEXT: .align 3 - call void (i64, i32, ...)* @llvm.experimental.stackmap(i64 1, i32 5) - %a2 = call i64 asm sideeffect "", "={r8}"() nounwind - %a3 = call i8 asm sideeffect "", "={ah}"() nounwind -@@ -58,16 +74,22 @@ entry: - ; CHECK-LABEL: .long L{{.*}}-_stackmap_liveness - ; CHECK-NEXT: .short 0 - ; CHECK-NEXT: .short 0 -+; Padding -+; CHECK-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; CHECK-NEXT: .short 0 -+; Align -+; CHECK-NEXT: .align 3 - - ; StackMap 2 (stackmap liveness information enabled) - ; STACK-LABEL: .long L{{.*}}-_stackmap_liveness - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .short 0 -+; Padding -+; STACK-NEXT: .short 0 - ; Num LiveOut Entries: 6 - ; STACK-NEXT: .short 6 --; LiveOut Entry 2: %RAX (1 bytes) --> %AL or %AH -+; LiveOut Entry 1: %RAX (1 bytes) --> %AL or %AH - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 1 -@@ -75,29 +97,35 @@ entry: - ; STACK-NEXT: .short 7 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 8 --; LiveOut Entry 2: %R8 (8 bytes) -+; LiveOut Entry 3: %R8 (8 bytes) - ; STACK-NEXT: .short 8 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 8 --; LiveOut Entry 2: %YMM0 (32 bytes) -+; LiveOut Entry 4: %YMM0 (32 bytes) - ; STACK-NEXT: .short 17 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 32 --; LiveOut Entry 2: %YMM1 (32 bytes) -+; LiveOut Entry 5: %YMM1 (32 bytes) - ; STACK-NEXT: .short 18 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 32 --; LiveOut Entry 2: %YMM2 (16 bytes) --> %XMM2 -+; LiveOut Entry 6: %YMM2 (16 bytes) --> %XMM2 - ; STACK-NEXT: .short 19 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 16 -+; Align -+; STACK-NEXT: .align 3 - - ; StackMap 2 (patchpoint liveness information enabled) - ; PATCH-LABEL: .long L{{.*}}-_stackmap_liveness - ; PATCH-NEXT: .short 0 - ; PATCH-NEXT: .short 0 -+; Padding -+; PATCH-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; PATCH-NEXT: .short 0 -+; Align -+; PATCH-NEXT: .align 3 - call void (i64, i32, ...)* @llvm.experimental.stackmap(i64 2, i32 5) - call void asm sideeffect "", "{r8},{ah},{ymm0},{ymm1}"(i64 %a2, i8 %a3, <4 x double> %a4, <4 x double> %a5) nounwind - -@@ -105,16 +133,22 @@ entry: - ; CHECK-LABEL: .long L{{.*}}-_stackmap_liveness - ; CHECK-NEXT: .short 0 - ; CHECK-NEXT: .short 0 -+; Padding -+; CHECK-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; CHECK-NEXT: .short 0 -+; Align -+; CHECK-NEXT: .align 3 - - ; StackMap 3 (stackmap liveness information enabled) - ; STACK-LABEL: .long L{{.*}}-_stackmap_liveness - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .short 0 -+; Padding -+; STACK-NEXT: .short 0 - ; Num LiveOut Entries: 2 - ; STACK-NEXT: .short 2 --; LiveOut Entry 2: %RSP (8 bytes) -+; LiveOut Entry 1: %RSP (8 bytes) - ; STACK-NEXT: .short 7 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 8 -@@ -122,13 +156,19 @@ entry: - ; STACK-NEXT: .short 19 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 16 -+; Align -+; STACK-NEXT: .align 3 - - ; StackMap 3 (patchpoint liveness information enabled) - ; PATCH-LABEL: .long L{{.*}}-_stackmap_liveness - ; PATCH-NEXT: .short 0 - ; PATCH-NEXT: .short 0 -+; Padding -+; PATCH-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; PATCH-NEXT: .short 0 -+; Align -+; PATCH-NEXT: .align 3 - call void (i64, i32, ...)* @llvm.experimental.stackmap(i64 3, i32 5) - call void asm sideeffect "", "{xmm2}"(<2 x double> %a1) nounwind - ret void -@@ -141,39 +181,58 @@ entry: - ; STACK-LABEL: .long L{{.*}}-_mixed_liveness - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .short 0 -+; Padding -+; STACK-NEXT: .short 0 - ; Num LiveOut Entries: 1 - ; STACK-NEXT: .short 1 - ; LiveOut Entry 1: %YMM2 (16 bytes) --> %XMM2 - ; STACK-NEXT: .short 19 - ; STACK-NEXT: .byte 0 - ; STACK-NEXT: .byte 16 -+; Align -+; STACK-NEXT: .align 3 -+ -+ - ; StackMap 5 (stackmap liveness information enabled) - ; STACK-LABEL: .long L{{.*}}-_mixed_liveness - ; STACK-NEXT: .short 0 - ; STACK-NEXT: .short 0 -+; Padding -+; STACK-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; STACK-NEXT: .short 0 -+; Align -+; STACK-NEXT: .align 3 - - ; StackMap 4 (patchpoint liveness information enabled) - ; PATCH-LABEL: .long L{{.*}}-_mixed_liveness - ; PATCH-NEXT: .short 0 - ; PATCH-NEXT: .short 0 -+; Padding -+; PATCH-NEXT: .short 0 - ; Num LiveOut Entries: 0 - ; PATCH-NEXT: .short 0 -+; Align -+; PATCH-NEXT: .align 3 -+ - ; StackMap 5 (patchpoint liveness information enabled) - ; PATCH-LABEL: .long L{{.*}}-_mixed_liveness - ; PATCH-NEXT: .short 0 - ; PATCH-NEXT: .short 0 -+; Padding -+; PATCH-NEXT: .short 0 - ; Num LiveOut Entries: 2 - ; PATCH-NEXT: .short 2 - ; LiveOut Entry 1: %RSP (8 bytes) - ; PATCH-NEXT: .short 7 - ; PATCH-NEXT: .byte 0 - ; PATCH-NEXT: .byte 8 --; LiveOut Entry 1: %YMM2 (16 bytes) --> %XMM2 -+; LiveOut Entry 2: %YMM2 (16 bytes) --> %XMM2 - ; PATCH-NEXT: .short 19 - ; PATCH-NEXT: .byte 0 - ; PATCH-NEXT: .byte 16 -+; Align -+; PATCH-NEXT: .align 3 - call void (i64, i32, ...)* @llvm.experimental.stackmap(i64 4, i32 5) - call anyregcc void (i64, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i64 5, i32 0, i8* null, i32 0) - call void asm sideeffect "", "{xmm2}"(<2 x double> %a1) nounwind -diff --git a/test/CodeGen/X86/stackmap.ll b/test/CodeGen/X86/stackmap.ll -index 2b7bb18..b827cbb 100644 ---- a/test/CodeGen/X86/stackmap.ll -+++ b/test/CodeGen/X86/stackmap.ll -@@ -4,45 +4,51 @@ - - ; CHECK-LABEL: .section __LLVM_STACKMAPS,__llvm_stackmaps - ; CHECK-NEXT: __LLVM_StackMaps: -+; Header - ; CHECK-NEXT: .long 0 - ; Num Functions - ; CHECK-NEXT: .long 14 --; CHECK-NEXT: .long _constantargs --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _osrinline --; CHECK-NEXT: .long 24 --; CHECK-NEXT: .long _osrcold --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _propertyRead --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _propertyWrite --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _jsVoidCall --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _jsIntCall --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _spilledValue --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _spilledStackMapValue --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _spillSubReg --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _subRegOffset --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _liveConstant --; CHECK-NEXT: .long 8 --; CHECK-NEXT: .long _directFrameIdx --; CHECK-NEXT: .long 56 --; CHECK-NEXT: .long _longid --; CHECK-NEXT: .long 8 - ; Num LargeConstants --; CHECK-NEXT: .long 3 -+; CHECK-NEXT: .long 3 -+; Num Callsites -+; CHECK-NEXT: .long 18 -+ -+; Functions and stack size -+; CHECK-NEXT: .quad _constantargs -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _osrinline -+; CHECK-NEXT: .quad 24 -+; CHECK-NEXT: .quad _osrcold -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _propertyRead -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _propertyWrite -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _jsVoidCall -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _jsIntCall -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _spilledValue -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _spilledStackMapValue -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _spillSubReg -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _subRegOffset -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _liveConstant -+; CHECK-NEXT: .quad 8 -+; CHECK-NEXT: .quad _directFrameIdx -+; CHECK-NEXT: .quad 56 -+; CHECK-NEXT: .quad _longid -+; CHECK-NEXT: .quad 8 -+ -+; Large Constants - ; CHECK-NEXT: .quad 2147483648 - ; CHECK-NEXT: .quad 4294967295 - ; CHECK-NEXT: .quad 4294967296 --; Num Callsites --; CHECK-NEXT: .long 18 - -+; Callsites - ; Constant arguments - ; - ; CHECK-NEXT: .quad 1 --- -1.8.5.3 - diff --git a/llvm_patches/0003-Update-TailCallElim-to-avoid-making-redundant-change.patch b/llvm_patches/0003-Update-TailCallElim-to-avoid-making-redundant-change.patch deleted file mode 100644 index 21e688434..000000000 --- a/llvm_patches/0003-Update-TailCallElim-to-avoid-making-redundant-change.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 333e582e651efaf3678ed8b89cd2274f75818649 Mon Sep 17 00:00:00 2001 -From: Kevin Modzelewski -Date: Fri, 21 Mar 2014 16:56:28 -0700 -Subject: [PATCH] Update TailCallElim to avoid making redundant changes - ---- - lib/Transforms/Scalar/TailRecursionElimination.cpp | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp -index 351aee0..7300d84 100644 ---- a/lib/Transforms/Scalar/TailRecursionElimination.cpp -+++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp -@@ -252,8 +252,10 @@ bool TailCallElim::runOnFunction(Function &F) { - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - if (CallInst *CI = dyn_cast(I)) { - if (!ACT.UsesAlloca.count(CI)) { -- CI->setTailCall(); -- MadeChange = true; -+ if (!CI->isTailCall()) { -+ CI->setTailCall(); -+ MadeChange = true; -+ } - } - } - } --- -1.7.9.5 - diff --git a/llvm_revision.txt b/llvm_revision.txt deleted file mode 100644 index 8f2c9305b..000000000 --- a/llvm_revision.txt +++ /dev/null @@ -1 +0,0 @@ -202092 diff --git a/microbenchmarks/attribute_lookup.py b/microbenchmarks/attribute_lookup.py deleted file mode 100644 index bb4a1220b..000000000 --- a/microbenchmarks/attribute_lookup.py +++ /dev/null @@ -1,15 +0,0 @@ -class C(object): - pass - -def f(n): - c = C() - c.x = 1.0 - t = 2.0 - - for i in xrange(n): - t = t + (c.x * 1.0 + 1.0) - # while n: - # t = t + (c.x * 1.0 + 1.0) - # n = n - 1 - return t -print f(2000000000) diff --git a/microbenchmarks/attrs.py b/microbenchmarks/attrs.py deleted file mode 100644 index ee9fcc9da..000000000 --- a/microbenchmarks/attrs.py +++ /dev/null @@ -1,19 +0,0 @@ -# attr perf test: functions are still the only -# things that support setattr, so use those - -def p(x, p): - p.n = p.n + x.a -p.n = 0 - -def s(x, n): - x.a = n - x.b = "hello world" - -n = 1000000 -while n: - n = n - 1 - def f(): - pass - s(f, n) - p(f, p) -print p.n diff --git a/microbenchmarks/closures.py b/microbenchmarks/closures.py deleted file mode 100644 index 2ba85a34b..000000000 --- a/microbenchmarks/closures.py +++ /dev/null @@ -1,11 +0,0 @@ -def outer(n): - def inner(): - return n - return inner - -n = 1000000 -t = 0 -while n: - n = n - 1 - t = t + outer(n)() -print t diff --git a/microbenchmarks/empty_loop.py b/microbenchmarks/empty_loop.py deleted file mode 100644 index 9835cd6e1..000000000 --- a/microbenchmarks/empty_loop.py +++ /dev/null @@ -1,11 +0,0 @@ -def f(n): - for i in xrange(n): - pass -f(100000000) -print "done with first" - -_xrange = xrange -def xrange(end): - return _xrange(end-1) -f(100000000) -print "done with second" diff --git a/microbenchmarks/fib.py b/microbenchmarks/fib.py deleted file mode 100644 index 3b93e8129..000000000 --- a/microbenchmarks/fib.py +++ /dev/null @@ -1,9 +0,0 @@ -# Simple function call test. -# Uses this formulation (passing the function in to itself) to not require supporting scoped lookups. - -def fib(n, f): - if n <= 2: - return n - return f(n-1, f) + f(n-2, f) - -print fib(36, fib) diff --git a/microbenchmarks/fib2.py b/microbenchmarks/fib2.py deleted file mode 100644 index 5afd88783..000000000 --- a/microbenchmarks/fib2.py +++ /dev/null @@ -1,8 +0,0 @@ -# Same as fib.py, but I now support global lookups! - -def fib(n): - if n <= 2: - return n - return fib(n-1) + fib(n-2) - -print fib(36) diff --git a/microbenchmarks/function_calls.py b/microbenchmarks/function_calls.py deleted file mode 100644 index 83a394008..000000000 --- a/microbenchmarks/function_calls.py +++ /dev/null @@ -1,66 +0,0 @@ -# Simple function call microbenchmark. -# Not really that interesting, but useful because it does a lot of work without any control flow - -def f0(): - return 1 -def f1(): - return f0() + f0() -def f2(): - return f1() + f1() -def f3(): - return f2() + f2() -def f4(): - return f3() + f3() -def f5(): - return f4() + f4() -def f6(): - return f5() + f5() -def f7(): - return f6() + f6() -def f8(): - return f7() + f7() -def f9(): - return f8() + f8() -def f10(): - return f9() + f9() -def f11(): - return f10() + f10() -def f12(): - return f11() + f11() -def f13(): - return f12() + f12() -def f14(): - return f13() + f13() -def f15(): - return f14() + f14() -def f16(): - return f15() + f15() -def f17(): - return f16() + f16() -def f18(): - return f17() + f17() -def f19(): - return f18() + f18() -def f20(): - return f19() + f19() -def f21(): - return f20() + f20() -def f22(): - return f21() + f21() -def f23(): - return f22() + f22() -def f24(): - return f23() + f23() -def f25(): - return f24() + f24() -def f26(): - return f25() + f25() -def f27(): - return f26() + f26() -def f28(): - return f27() + f27() -def f29(): - return f28() + f28() -def f30(): - return f29() + f29() -print f25() diff --git a/microbenchmarks/iteration.py b/microbenchmarks/iteration.py deleted file mode 100644 index 25958dfc5..000000000 --- a/microbenchmarks/iteration.py +++ /dev/null @@ -1,4 +0,0 @@ -t = 0 -for i in range(1000000): - t = t + i -print t diff --git a/microbenchmarks/lcg.py b/microbenchmarks/lcg.py deleted file mode 100644 index dfce3059e..000000000 --- a/microbenchmarks/lcg.py +++ /dev/null @@ -1,15 +0,0 @@ -class Random(object): - def __init__(self, seed): - self.cur = seed - - def next(self): - self.cur = (self.cur * 1103515245 + 12345) % (1 << 31) - return self.cur - -def f(): - r = Random(0) - t = 0 - for i in xrange(10000000): - t = t + r.next() - print t -f() diff --git a/microbenchmarks/nested.py b/microbenchmarks/nested.py deleted file mode 100644 index f1374c58a..000000000 --- a/microbenchmarks/nested.py +++ /dev/null @@ -1,11 +0,0 @@ -def outer(): - def inner(n): - return n - return inner - -n = 1000000 -t = 0 -while n: - n = n - 1 - t = t + outer()(n) -print t diff --git a/microbenchmarks/prime_summing.cpp b/microbenchmarks/prime_summing.cpp deleted file mode 100644 index 239438281..000000000 --- a/microbenchmarks/prime_summing.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -int main(int argc, char** argv) { - long long total = 0; - for (long long i = 2; i < 2000000; i++) { - bool prime = true; - for (int j = 2; j * j <= i; j++) { - if (i % j == 0) { - prime = false; - break; - } - } - - if (prime) - total += i; - } - printf("%lld\n", total); - return 0; -} - diff --git a/microbenchmarks/prime_summing.py b/microbenchmarks/prime_summing.py deleted file mode 100644 index 0529ef156..000000000 --- a/microbenchmarks/prime_summing.py +++ /dev/null @@ -1,14 +0,0 @@ -def f(): - total = 0 - i = 1 - while i < 2000000: - i = i + 1 - j = 2 - while j * j <= i: - if i % j == 0: - break - j = j + 1 - else: - total = total + i - print total -f() diff --git a/microbenchmarks/repatching.py b/microbenchmarks/repatching.py deleted file mode 100644 index a00a68ab4..000000000 --- a/microbenchmarks/repatching.py +++ /dev/null @@ -1,20 +0,0 @@ -# Re-patching test: have a single callsite that frequently has different target functions: - -def a(): - return 1 - -def b(): - return 2 - -def c(f): - # The difficult callsite: - return f() - -x = 1000000 -y = 0 -while x: - y = y + c(a) - y = y + c(b) - x = x - 1 - -print y diff --git a/microbenchmarks/simple_sum.py b/microbenchmarks/simple_sum.py deleted file mode 100644 index ac226e7f7..000000000 --- a/microbenchmarks/simple_sum.py +++ /dev/null @@ -1,11 +0,0 @@ -def f(n): - t = 0 - for i in xrange(n): - t = t + n - return t -print f(1000000) - -_xrange = xrange -def xrange(end): - return _xrange(end-1) -print f(1000000) diff --git a/microbenchmarks/sort.py b/microbenchmarks/sort.py deleted file mode 100644 index 70fa5616f..000000000 --- a/microbenchmarks/sort.py +++ /dev/null @@ -1,15 +0,0 @@ -def sort(l): - n = len(l) - for i in xrange(n): - print i - for j in xrange(i): - if l[i] < l[j]: - l[i], l[j] = l[j], l[i] - return l - -l = [] -N = 5000 -for i in xrange(N): - l.append(N - i) -sort(l) -print l diff --git a/microbenchmarks/vecf_add.py b/microbenchmarks/vecf_add.py deleted file mode 100644 index 74a1bd518..000000000 --- a/microbenchmarks/vecf_add.py +++ /dev/null @@ -1,22 +0,0 @@ -class Vector(object): - def __init__(self, x, y, z): - self.x = x - self.y = y - self.z = z - - def __add__(self, rhs): - return Vector(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z) - - def __str__(self): - return "Vector(%f, %f, %f)" % (self.x, self.y, self.z) - -def f(n): - v = Vector(0,0,0) - a = Vector(1.0, 1.1, 1.2) - # b = Vector(1, -2, 1) - for i in xrange(n): - # if v.y > 0: - # v = v + b - v = v + a - return v -print f(10000000) diff --git a/microbenchmarks/vecf_dot.py b/microbenchmarks/vecf_dot.py deleted file mode 100644 index 0a28dcfce..000000000 --- a/microbenchmarks/vecf_dot.py +++ /dev/null @@ -1,21 +0,0 @@ -class Vector(object): - def __init__(self, x, y, z): - self.x = x - self.y = y - self.z = z - - def __add__(self, rhs): - return Vector(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z) - - def dot(self, rhs): - return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z - -def f(n): - v = Vector(0,0.1,0) - a = Vector(1.0, 1.1, 1.2) - t = 0 - for i in xrange(n): - t = t + v.dot(a) - return t -print f(10000000) - diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index e5da8f1b6..000000000 --- a/src/Makefile +++ /dev/null @@ -1,721 +0,0 @@ -# Disable builtin rules: -.SUFFIXES: - -USE_TEST_LLVM := 0 -DEPS_DIR := $(HOME)/pyston_deps - -LLVM_REVISION_FILE := ../llvm_revision.txt -LLVM_REVISION := $(shell cat $(LLVM_REVISION_FILE)) - -USE_CLANG := 1 -USE_CCACHE := 1 -USE_DISTCC := 0 - -VALGRIND := valgrind -GDB := gdb -GCC_DIR := $(DEPS_DIR)/gcc-4.8.2-install -GTEST_DIR := $(DEPS_DIR)/gtest-1.7.0 - -PYTHON_MAJOR_VERSION := 2 -PYTHON_MINOR_VERSION := 7 -PYTHON_MICRO_VERSION := 3 - -MAX_MEM_KB := 500000 -MAX_DBG_MEM_KB := 500000 - -TEST_THREADS := 4 - -ERROR_LIMIT := 10 -COLOR := 1 - -VERBOSE := 0 - -# Setting this to 1 will set the Makefile to use binaries from the trunk -# directory, even if USE_TEST_LLVM is set to 1. -# This is useful if clang isn't installed into the test directory, ex due -# to disk space concerns. -FORCE_TRUNK_BINARIES := 0 - -# Put any overrides in here: --include Makefile.local - - -TOOLS_DIR := ../tools -TESTS_DIR := ../test/tests - -GPP := $(GCC_DIR)/bin/g++ - -ifeq ($(VERBOSE),1) - VERB := - ECHO := @\# -else - VERB := @ - ECHO := @ echo pyston: -endif - -LLVM_TRUNK_SRC := $(DEPS_DIR)/llvm-trunk -LLVM_TEST_SRC := $(DEPS_DIR)/llvm-test -LLVM_TRUNK_BUILD := $(DEPS_DIR)/llvm-trunk-build -LLVM_TEST_BUILD := $(DEPS_DIR)/llvm-test-build -ifneq ($(USE_TEST_LLVM),0) - LLVM_SRC := $(LLVM_TEST_SRC) - LLVM_BUILD := $(LLVM_TEST_BUILD) -else - LLVM_SRC := $(LLVM_TRUNK_SRC) - LLVM_BUILD := $(LLVM_TRUNK_BUILD) -endif - -ifeq ($(FORCE_TRUNK_BINARIES),1) - LLVM_BIN := $(LLVM_TRUNK_BUILD)/Release/bin -else - LLVM_BIN := $(LLVM_BUILD)/Release/bin -endif - -LLVM_LINK_LIBS := core mcjit native bitreader ipo irreader jit debuginfo instrumentation -LLVM_CXXFLAGS := $(shell $(LLVM_BUILD)/Release+Asserts/bin/llvm-config --cxxflags) -LLVM_LDFLAGS := $(shell $(LLVM_BUILD)/Release+Asserts/bin/llvm-config --ldflags --libs $(LLVM_LINK_LIBS)) -LLVM_LIB_DEPS := $(wildcard $(LLVM_BUILD)/Release+Asserts/lib/*) - -LLVM_DEBUG_LDFLAGS := $(shell $(LLVM_BUILD)/Debug+Asserts/bin/llvm-config --ldflags --libs $(LLVM_LINK_LIBS)) -LLVM_DEBUG_LIB_DEPS := $(wildcard $(LLVM_BUILD)/Debug+Asserts/lib/*) - -LLVM_CONFIG_RELEASE := $(LLVM_BUILD)/Release/bin/llvm-config -ifneq ($(wildcard $(LLVM_CONFIG_RELEASE)),) -LLVM_RELEASE_CXXFLAGS := $(shell $(LLVM_BUILD)/Release/bin/llvm-config --cxxflags) -LLVM_RELEASE_LDFLAGS := $(shell $(LLVM_BUILD)/Release/bin/llvm-config --ldflags --libs $(LLVM_LINK_LIBS)) -LLVM_RELEASE_LIB_DEPS := $(wildcard $(LLVM_BUILD)/Release/lib/*) -else -LLVM_RELEASE_CXXFLAGS := RELEASE_NOT_BUILT -LLVM_RELEASE_LDFLAGS := RELEASE_NOT_BUILT -LLVM_RELEASE_LIB_DEPS := RELEASE_NOT_BUILT -endif - -ifneq ($(wildcard /usr/local/include/llvm),) -# Global include files can screw up the build, since if llvm moves a header file, -# the compiler will silently fall back to the global one that still exists. -# These include files are persistent because llvm's "make uninstall" does *not* -# delete them if the uninstall command is run on a revision that didn't include -# those files. -# This could probably be handled (somehow blacklist this particular folder?), -# but for now just error out: -$(error "Error: global llvm include files detected") -endif - -# Note: use lazy-expansion for these profile targets, since calling the profile llvm-config will -# actually generate a gmon.out file! -LLVM_PROFILE_CXXFLAGS = $(shell $(LLVM_BUILD)/Release+Profile/bin/llvm-config --cxxflags) -UNDEBUG -LLVM_PROFILE_LDFLAGS = $(shell $(LLVM_BUILD)/Release+Profile/bin/llvm-config --ldflags --libs $(LLVM_LINK_LIBS)) -LLVM_PROFILE_LIB_DEPS := $(wildcard $(LLVM_BUILD)/Release+Profile/lib/*) - -CLANG_EXE := $(LLVM_BIN)/clang++ - -COMMON_CXXFLAGS := -g -Werror -Wreturn-type -Woverloaded-virtual -Wall -Wno-sign-compare -Wno-unused -I. -I../include -fno-omit-frame-pointer -COMMON_CXXFLAGS += -std=c++11 -COMMON_CXXFLAGS += -I$(DEPS_DIR)/valgrind-3.9.0/include -COMMON_CXXFLAGS += -Wextra -Wno-sign-compare -COMMON_CXXFLAGS += -Wno-unused-parameter # should use the "unused" attribute -# Extra flags to enable soon: -# COMMON_CXXFLAGS += -Wold-style-cast -Wconversion -Wsign-conversion -Wnon-virtual-dtor -Winit-self -Wimplicit-int -Wmissing-include-dirs -Wswitch-enum -Wunused-variable -Wunused -Wstrict-overflow=5 -Wfloat-equal -Wtraditional-conversion -Wundef -Wunsafe-loop-optimizations -Wpointer-arith -Wtype-limits -Wwrite-strings -Wclobbered -Wconversion -Wempty-body -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-declaration -Wold-style-definition -Wmissing-parameter-type -Wmissing-field-initializers -Wredundant-decls -Wnested-externs -Winline -Wint-to-pointer-cast -Wpointer-to-int-cast -Wlong-long -Wvla -# Not sure about these: -# COMMON_CXXFLAGS += -Wbad-function-cast -Wcast-qual -Wcast-align -Wmissing-prototypes -Wunreachable-code -# Or everything: -# COMMON_CXXFLAGS += -Weverything - -COMMON_CXXFLAGS += -DGITREV=$(shell git rev-parse HEAD | head -c 12) -DLLVMREV=$(LLVM_REVISION) -COMMON_CXXFLAGS += -DDEFAULT_PYTHON_MAJOR_VERSION=$(PYTHON_MAJOR_VERSION) -DDEFAULT_PYTHON_MINOR_VERSION=$(PYTHON_MINOR_VERSION) -DDEFAULT_PYTHON_MICRO_VERSION=$(PYTHON_MICRO_VERSION) - -CXXFLAGS := $(LLVM_CXXFLAGS) $(COMMON_CXXFLAGS) -O0 -DBINARY_SUFFIX= -DBINARY_STRIPPED_SUFFIX=_stripped $(EXTRA_CXXFLAGS) -CXXFLAGS_PROFILE = $(LLVM_PROFILE_CXXFLAGS) $(COMMON_CXXFLAGS) -pg -O3 -DNDEBUG -DBINARY_SUFFIX=_release -DBINARY_STRIPPED_SUFFIX= -fno-function-sections $(EXTRA_CXXFLAGS) -CXXFLAGS_RELEASE := $(LLVM_RELEASE_CXXFLAGS) $(COMMON_CXXFLAGS) -O3 -fstrict-aliasing -enable-tbaa -DNDEBUG -DBINARY_SUFFIX=_release -DBINARY_STRIPPED_SUFFIX= $(EXTRA_CXXFLAGS) - -# Use our "custom linker" that calls gold if available -COMMON_LDFLAGS := -B../tools/build_system -L/usr/local/lib -lpthread -ldl -lcurses -lm -lunwind -lz -L$(DEPS_DIR)/gcc-4.8.2-install/lib64 -# Make sure that we put all symbols in the dynamic symbol table so that MCJIT can load them; -# TODO should probably do the linking before MCJIT -COMMON_LDFLAGS += -Wl,-E -LDFLAGS := $(LLVM_LDFLAGS) $(COMMON_LDFLAGS) -LDFLAGS_DEBUG := $(LLVM_DEBUG_LDFLAGS) $(COMMON_LDFLAGS) -LDFLAGS_PROFILE = $(LLVM_PROFILE_LDFLAGS) -pg $(COMMON_LDFLAGS) -LDFLAGS_RELEASE := $(LLVM_RELEASE_LDFLAGS) $(COMMON_LDFLAGS) -LDFLAGS_RELEASE := $(LLVM_RELEASE_LDFLAGS) $(COMMON_LDFLAGS) -# Can't add this, because there are functions in the compiler that look unused but are hooked back from the runtime: -# LDFLAGS_RELEASE += -Wl,--gc-sections - -BUILD_SYSTEM_DEPS := Makefile Makefile.local $(wildcard build_system/*) -CLANG_DEPS := $(CLANG_EXE) $(dir $(CLANG_EXE))/../../built_release - -# settings to make clang and ccache play nicely: -CLANG_CCACHE_FLAGS := -Qunused-arguments -CLANG_EXTRA_FLAGS := -Wno-mismatched-tags -ferror-limit=$(ERROR_LIMIT) $(CLANG_CCACHE_FLAGS) -ifeq ($(COLOR),1) - CLANG_EXTRA_FLAGS += -fcolor-diagnostics -else - CLANG_EXTRA_FLAGS += -fno-color-diagnostics -endif -CLANGFLAGS := $(CXXFLAGS) $(CLANG_EXTRA_FLAGS) -CLANGFLAGS_RELEASE := $(CXXFLAGS_RELEASE) $(CLANG_EXTRA_FLAGS) - -CXX := $(GPP) -CXX_PROFILE := $(GPP) -CLANG_CXX := $(CLANG_EXE) - -ifneq ($(USE_CLANG),0) - CXX := $(CLANG_CXX) - - CXXFLAGS := $(CLANGFLAGS) - CXXFLAGS_RELEASE := $(CLANGFLAGS_RELEASE) - - BUILD_SYSTEM_DEPS := $(BUILD_SYSTEM_DEPS) $(CLANG_DEPS) -endif - -ifeq ($(USE_CCACHE),1) - CXX := ccache $(CXX) - CXX_PROFILE := ccache $(CXX_PROFILE) - CLANG_CXX := ccache $(CLANG_CXX) - ifeq ($(USE_DISTCC),1) - CXX_ENV += CCACHE_PREFIX=distcc - endif -else ifeq ($(USE_DISTCC),1) - CXX := distcc $(CXX) - CXX_PROFILE := distcc $(CXX_PROFILE) - CLANG_CXX := distcc $(CLANG_CXX) - LLVM_BUILD_VARS += CXX='distcc $(GPP)' -endif -ifeq ($(USE_DISTCC),1) - LLVM_BUILD_ENV += CCACHE_PREFIX=distcc -endif -ifeq ($(USE_CCACHE),1) - LLVM_BUILD_VARS += CXX='ccache $(GPP)' -endif -CXX := $(CXX_ENV) $(CXX) -CXX_PROFILE := $(CXX_ENV) $(CXX_PROFILE) -CLANG_CXX := $(CXX_ENV) $(CLANG_CXX) -# Not sure if ccache_basedir actually helps at all (I think the generated files make them different?) -LLVM_BUILD_ENV += CCACHE_DIR=$(HOME)/.ccache_llvm CCACHE_BASEDIR=$(LLVM_SRC) - -MAIN_SRCS := $(wildcard codegen/*.cpp) $(wildcard asm_writing/*.cpp) $(wildcard codegen/irgen/*.cpp) $(wildcard codegen/opt/*.cpp) $(wildcard analysis/*.cpp) $(wildcard core/*.cpp) jit.cpp codegen/profiling/profiling.cpp codegen/profiling/dumprof.cpp $(wildcard runtime/*.cpp) $(wildcard runtime/builtin_modules/*.cpp) $(wildcard gc/*.cpp) -STDLIB_SRCS := $(wildcard runtime/inline/*.cpp) -SRCS := $(MAIN_SRCS) $(STDLIB_SRCS) -STDLIB_OBJS := stdlib.bc.o stdlib.stripped.bc.o -STDLIB_RELEASE_OBJS := stdlib.release.bc.o -# The stdlib objects have slightly longer dependency chains, -# so put them first in the list: -OBJS := $(STDLIB_OBJS) $(SRCS:.cpp=.o) -PROFILE_OBJS := $(STDLIB_RELEASE_OBJS) $(MAIN_SRCS:.cpp=.prof.o) $(STDLIB_SRCS:.cpp=.release.o) -OPT_OBJS := $(STDLIB_RELEASE_OBJS) $(SRCS:.cpp=.release.o) - -OPTIONAL_SRCS := codegen/profiling/oprofile.cpp codegen/profiling/pprof.cpp -TOOL_SRCS := $(wildcard $(TOOLS_DIR)/*.cpp) -NONSTDLIB_SRCS := $(MAIN_SRCS) $(OPTIONAL_SRCS) $(TOOL_SRCS) - -# .DEFAULT_GOAL := pyston_dbg -_ : - $(MAKE) pyston_dbg || (clear; $(MAKE) pyston_dbg -j1 ERROR_LIMIT=1) - -.PHONY: all _all -all: llvm - @# have to do this in a recursive make so that dependency is enforced: - $(MAKE) pyston_all -pyston_all: pyston_dbg pyston pyston_oprof pyston_prof $(OPTIONAL_SRCS:.cpp=.o) - -ALL_HEADERS := $(wildcard */*.h) $(wildcard */*/*.h) -tags: $(SRCS) $(OPTIONAL_SRCS) $(ALL_HEADERS) - $(ECHO) Computing tags... - $(VERB) ctags $^ - -UNITTEST_SRCS := $(wildcard unittests/*.cpp) -GC_OBJS := $(patsubst %.cpp,%.o,$(wildcard gc/*.cpp)) -$(UNITTEST_SRCS:.cpp=.o): %.o: %.cpp $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CXX) $(CXXFLAGS) -I$(GTEST_DIR)/include -MMD -MP -MF $(patsubst %.o,%.d,$@) $< -c -o $@ -unittests/gc: $(GTEST_DIR)/src/gtest-all.o $(UNITTEST_SRCS:.cpp=.o) $(BUILD_SYSTEM_DEPS) $(GC_OBJS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(GTEST_DIR)/src/gtest-all.o $(GTEST_DIR)/src/gtest_main.o $(UNITTEST_SRCS:.cpp=.o) $(GC_OBJS) $(LDFLAGS) -o $@ -dbg_gcunittests: unittests/gc - zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time gdb $(GDB_CMDS) --args ./unittests/gc --gtest_break_on_failure $(ARGS)' -run_gcunittests: unittests/gc - zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./unittests/gc $(ARGS)' -run_unittests:: run_gcunittests -dbg_unittests:: dbg_gcunittests - -.PHONY: test test_debug test_prof test_release -test_debug: pyston_dbg ext - python ../tools/tester.py -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS) -test_release: pyston ext - python ../tools/tester.py -R -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -R -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -R -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS) -test_prof: pyston_prof ext - python ../tools/tester.py -P -j$(TEST_THREADS) -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -P -j$(TEST_THREADS) -a -n -k $(TESTS_DIR) $(ARGS) - python ../tools/tester.py -P -j$(TEST_THREADS) -a -O -k $(TESTS_DIR) $(ARGS) -test: ext - $(MAKE) pyston_dbg - # $(MAKE) run_unittests - $(MAKE) test_debug - $(MAKE) test_release - @# jit_prof forces the use of GCC as the compiler, which can expose other errors, so just build it and see what happens: - # $(MAKE) test_prof - $(MAKE) pyston_prof - ./pyston_prof -q $(TESTS_DIR)/raytrace_small.py | sha1sum - - echo "All tests passed" - -define checksha - test "$$($1 | sha1sum)" = "$2 -" -endef -check: - $(MAKE) pyston_dbg - $(call checksha,./pyston_dbg -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston_dbg -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston_dbg -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(MAKE) pyston - $(call checksha,./pyston -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(MAKE) pyston_prof - $(call checksha,./pyston_prof -cq $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston_prof -cqn $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - $(call checksha,./pyston_prof -cqO $(TESTS_DIR)/raytrace_small.py,0544f4621dd45fe94205219488a2576b84dc044d) - -Makefile.local: - echo "Creating default Makefile.local" - python -c 'import sys; v = sys.version_info; print "PYTHON_MAJOR_VERSION:=%d\nPYTHON_MINOR_VERSION:=%d\nPYTHON_MICRO_VERSION:=%d" % (v[0], v[1], v[2])' > Makefile.local || (rm $@; false) - -################# -# LLVM rules: - -# -# This is probably my worst makefile hackery: -# - if you change the patch, the llvm_* targets should be rebuilt when you build a pyston target that depends on them -# - they shouldn't be rebuilt if the built_* rule doesn't indicate it -# - should rebuild the pyston targets *if and only if* one of their dependencies actually changes in the rebuild -# -- make should report them as "up to date" - -# First, specify when we need to rebuild the different targets: -$(LLVM_BUILD)/built_quick: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - $(MAKE) llvm_quick -$(LLVM_BUILD)/built_debug: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - $(MAKE) llvm_debug -$(LLVM_BUILD)/built_release: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - $(MAKE) llvm_release -$(LLVM_BUILD)/built_profile: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - $(MAKE) llvm_profile -# Now, specify that we shouldn't check the timestamps of dependencies until after -# the llvm rebuild finishes, if one is happening, but do it with order-only -# dependencies so that make doesn't consider the libraries out of date -# if they didn't get updated in the llvm rebuild: -# $(CLANG_EXE): | $(LLVM_TRUNK)/built_release -$(LLVM_LIB_DEPS): | $(LLVM_BUILD)/built_quick -$(LLVM_DEBUG_LIB_DEPS): | $(LLVM_BUILD)/built_debug -$(LLVM_RELEASE_LIB_DEPS): | $(LLVM_BUILD)/built_release -$(LLVM_PROFILE_LIB_DEPS): | $(LLVM_BUILD)/built_profile -# Now, put together some variables for later; pyston targets will have to depend on the lib_deps -# so they can be rebuilt properly, but also the built_* targets to force a rebuild if appropriate -# (because the lib_deps dependency won't cause a rebuild on their own) -LLVM_DEPS := $(LLVM_LIB_DEPS) $(LLVM_BUILD)/built_quick -LLVM_DEBUG_DEPS := $(LLVM_DEBUG_LIB_DEPS) $(LLVM_BUILD)/built_debug -LLVM_RELEASE_DEPS := $(LLVM_RELEASE_LIB_DEPS) $(LLVM_BUILD)/built_release -LLVM_PROFILE_DEPS := $(LLVM_PROFILE_LIB_DEPS) $(LLVM_BUILD)/built_profile -# end worst makefile hackery - -LLVM_BUILDS := quick release debug profile -# Tools for all builds (note: don't include llvm-config) -LLVM_TOOLS := llc opt - -ifneq (,$(findstring llvm_debug,$(MAKECMDGOALS))) -FIRST_LLVM_BUILD := debug -else ifneq (,$(findstring llvm_quick,$(MAKECMDGOALS))) -FIRST_LLVM_BUILD := quick -else -FIRST_LLVM_BUILD := release -endif -NONFIRST_LLVM_BUILDS := $(filter-out $(FIRST_LLVM_BUILD),$(LLVM_BUILDS)) -.PHONY: llvm llvm_configs $(patsubst %,llvm_%,$(LLVM_BUILDS)) llvm/% llvm_up -llvm: llvm_configs $(LLVM_BUILDS:%=llvm_%) -llvm_configs: $(LLVM_BUILDS:%=llvm/%/tools/llvm-config) -# Use the configure-created Makefile as evidence that llvm has been configured: -LLVM_CONFIGURATION := $(LLVM_BUILD)/Makefile.config -.PHONY: llvm_configure -llvm_configure: - rm -f $(LLVM_BUILD)/Makefile.config - $(MAKE) $(LLVM_CONFIGURATION) - -$(LLVM_CONFIGURATION): $(LLVM_SRC)/configure - mkdir -p $(LLVM_BUILD) - cd $(LLVM_BUILD) ; \ - CXX=$(GPP) $(LLVM_SRC)/configure --enable-targets=host --with-gcc-toolchain=$(GCC_DIR) - # CXX=ccache\ g++ ./configure --enable-targets=host - # CXX='env CCACHE_PREFIX=distcc ccache g++' ./configure --enable-targets=host - -# Use "Static Pattern Rules" instead of implicit rules to avoid needing to reuse the same implicit rule in a single chain: -define add_llvm_dep -$(eval \ -$(LLVM_BUILDS:%=llvm/%/$1): llvm/%/$1: llvm/%/$2 -) -endef - -$(call add_llvm_dep,lib/TableGen,lib/Support) -$(call add_llvm_dep,utils/TableGen,lib/TableGen) -$(call add_llvm_dep,lib/IR,utils/TableGen) -$(call add_llvm_dep,lib/Target,lib/IR) -$(call add_llvm_dep,lib/Target,utils/TableGen) -# There are some shared targets in the Target subdirectory, which will make a parallel make fail -# if you try to build multiple llvm builds at the same time. Work around this by -# serializing the non-release Target builds to after the release one: -$(NONFIRST_LLVM_BUILDS:%=llvm/%/lib/Target): llvm/%/lib/Target: llvm/$(FIRST_LLVM_BUILD)/lib/Target -$(NONFIRST_LLVM_BUILDS:%=llvm/%/tools/llvm-config): llvm/%/tools/llvm-config: llvm/$(FIRST_LLVM_BUILD)/tools/llvm-config -$(call add_llvm_dep,lib,lib/Target) -$(call add_llvm_dep,tools/llvm-config,lib/Support) -$(call add_llvm_dep,tools,lib) -$(call add_llvm_dep,tools,utils/unittest) -$(call add_llvm_dep,utils,lib) -# The tools need to individually depend on the lib directory: -$(foreach tool,$(LLVM_TOOLS),$(foreach build,$(LLVM_BUILDS),$(eval \ -llvm/$(build)/tools/$(tool): llvm/$(build)/lib \ -))) -$(LLVM_BUILDS:%=llvm_%): llvm_%: llvm/%/lib llvm/%/tools/llvm-config $(LLVM_TOOLS:%=llvm/\%/tools/%) - touch $(LLVM_BUILD)/$(patsubst llvm_%,built_%,$@) -llvm_release: llvm/release/tools llvm/release/utils -llvm_quick_clean: - $(MAKE) -C $(LLVM_BUILD) ENABLE_OPTIMIZED=1 clean -llvm_release_%: - $(MAKE) -C $(LLVM_BUILD) ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 $(patsubst llvm_release_%,%,$@) -llvm_debug_clean: - $(MAKE) -C $(LLVM_BUILD) DEBUG_RUNTIME=1 DEBUG_SYMBOLS=1 ENABLE_OPTIMIZED=0 clean -llvm_profile_clean: - $(MAKE) -C $(LLVM_BUILD) ENABLE_PROFILING=1 ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 clean -llvm_allclean: $(patsubst %,llvm_%_clean,$(LLVM_BUILDS)) - cd $(LLVM_SRC) ; git checkout . - rm -rfv $(LLVM_BUILD)/* -llvm_install: llvm_release - sudo $(MAKE) -C $(LLVM_SRC)/tools ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 install - -# Clear OPTIONAL_DIRS and OPTIONAL_PARALLEL_DIRS to make sure that clang doesn't get built+tested -llvm_test: llvm_quick - $(MAKE) -C $(LLVM_BUILD) OPTIONAL_DIRS= OPTIONAL_PARALLEL_DIRS= ENABLE_OPTIMIZED=1 check -llvm_test_all: llvm_release - $(MAKE) -C $(LLVM_BUILD) ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 check-all - -llvm/quick/%: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - mkdir -p $(patsubst llvm/quick/%,$(LLVM_BUILD)/%,$@) - $(VERB) if [ ! -f $(patsubst llvm/quick/%,$(LLVM_BUILD)/%/Makefile,$@) ]; then cp $(patsubst llvm/quick/%,$(LLVM_SRC)/%/Makefile,$@) $(patsubst llvm/quick/%,$(LLVM_BUILD)/%/,$@); fi - $(LLVM_BUILD_ENV) $(MAKE) -C $(patsubst llvm/quick/%,$(LLVM_BUILD)/%,$@) $(LLVM_BUILD_VARS) ENABLE_OPTIMIZED=1 DEBUG_RUNTIME=0 NO_DEBUG_SYMBOLS=1 -llvm/release/%: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - mkdir -p $(patsubst llvm/release/%,$(LLVM_BUILD)/%,$@) - $(VERB) if [ ! -f $(patsubst llvm/release/%,$(LLVM_BUILD)/%/Makefile,$@) ]; then cp $(patsubst llvm/release/%,$(LLVM_SRC)/%/Makefile,$@) $(patsubst llvm/release/%,$(LLVM_BUILD)/%/,$@); fi - $(LLVM_BUILD_ENV) $(MAKE) -C $(patsubst llvm/release/%,$(LLVM_BUILD)/%,$@) $(LLVM_BUILD_VARS) ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 -llvm/debug/%: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - mkdir -p $(patsubst llvm/debug/%,$(LLVM_BUILD)/%,$@) - $(VERB) if [ ! -f $(patsubst llvm/debug/%,$(LLVM_BUILD)/%/Makefile,$@) ]; then cp $(patsubst llvm/debug/%,$(LLVM_SRC)/%/Makefile,$@) $(patsubst llvm/debug/%,$(LLVM_BUILD)/%/,$@); fi - $(LLVM_BUILD_ENV) $(MAKE) -C $(patsubst llvm/debug/%,$(LLVM_BUILD)/%,$@) $(LLVM_BUILD_VARS) DEBUG_RUNTIME=1 DEBUG_SYMBOLS=1 ENABLE_OPTIMIZED=0 -llvm/profile/%: $(LLVM_SRC)/_patched $(LLVM_CONFIGURATION) - mkdir -p $(patsubst llvm/profile/%,$(LLVM_BUILD)/%,$@) - $(VERB) if [ ! -f $(patsubst llvm/profile/%,$(LLVM_BUILD)/%/Makefile,$@) ]; then cp $(patsubst llvm/profile/%,$(LLVM_SRC)/%/Makefile,$@) $(patsubst llvm/profile/%,$(LLVM_BUILD)/%/,$@); fi - $(LLVM_BUILD_ENV) $(MAKE) -C $(patsubst llvm/profile/%,$(LLVM_BUILD)/%,$@) $(LLVM_BUILD_VARS) CXXFLAGS="-fno-omit-frame-pointer -fno-function-sections" ENABLE_PROFILING=1 ENABLE_OPTIMIZED=1 DISABLE_ASSERTIONS=1 $(LLVM_MAKE_ARGS) - -$(LLVM_SRC)/_patched: $(wildcard llvm_patches/*) $(wildcard clang_patches/*) $(LLVM_REVISION_FILE) - $(MAKE) llvm_up -llvm_up: - python $(TOOLS_DIR)/git_svn_gotorev.py $(LLVM_SRC) $(LLVM_REVISION) ../llvm_patches - python $(TOOLS_DIR)/git_svn_gotorev.py $(LLVM_SRC)/tools/clang $(LLVM_REVISION) ../clang_patches - touch $(LLVM_SRC)/_patched - -# end of llvm rules -######## - -## TOOLS: - -$(TOOLS_DIR)/demangle: $(TOOLS_DIR)/demangle.cpp $(BUILD_SYSTEM_DEPS) - $(CXX) $< -o $@ -.PHONY: demangle -demangle: $(TOOLS_DIR)/demangle - $(TOOLS_DIR)/demangle $(ARGS) - -$(TOOLS_DIR)/mcjitcache: $(TOOLS_DIR)/mcjitcache.o $(LLVM_DEPS) $(BUILD_SYSTEM_DEPS) - $(CXX) $< $(LDFLAGS) -o $@ -# Build a version of mcjitcache off the llvm_release repo mostly to avoid a dependence of the opt builds -# on the llvm_quick build. -$(TOOLS_DIR)/mcjitcache_release: $(TOOLS_DIR)/mcjitcache.release.o $(LLVM_RELEASE_DEPS) $(BUILD_SYSTEM_DEPS) - $(CXX) $< $(LDFLAGS_RELEASE) -o $@ - -$(TOOLS_DIR)/publicize: $(TOOLS_DIR)/publicize.o $(LLVM_DEPS) $(BUILD_SYSTEM_DEPS) - $(ECHO) Linking $(TOOLS_DIR)/publicize - $(VERB) $(CXX) $< $(LDFLAGS) -o $@ -lLLVMBitWriter - -$(TOOLS_DIR)/publicize_release: $(TOOLS_DIR)/publicize.release.o $(LLVM_RELEASE_DEPS) $(BUILD_SYSTEM_DEPS) - $(ECHO) Linking $(TOOLS_DIR)/publicize_release - $(VERB) $(CXX) $< $(LDFLAGS_RELEASE) -o $@ -lLLVMBitWriter - -## END OF TOOLS - - -PASS_SRCS := codegen/opt/aa.cpp -PASS_OBJS := $(PASS_SRCS:.cpp=.standalone.o) - -# For NONSTDLIB sources, just compile like normal: -# TODO could use the same target but with target-specific variables? -$(NONSTDLIB_SRCS:.cpp=.o): %.o: %.cpp $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CXX) $(CXXFLAGS) -MMD -MP -MF $(patsubst %.o,%.d,$@) $< -c -o $@ -$(PASS_SRCS:.cpp=.standalone.o): %.standalone.o: %.cpp $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CXX) $(CXXFLAGS) -DSTANDALONE -MMD -MP -MF $(patsubst %.o,%.d,$@) $< -c -o $@ -$(NONSTDLIB_SRCS:.cpp=.prof.o): %.prof.o: %.cpp $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CXX_PROFILE) $(CXXFLAGS_PROFILE) -MMD -MP -MF $(patsubst %.o,%.d,$@) $< -c -o $@ -$(NONSTDLIB_SRCS:.cpp=.release.o): %.release.o: %.cpp $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CXX) $(CXXFLAGS_RELEASE) -MMD -MP -MF $(patsubst %.o,%.d,$@) $< -c -o $@ - -# For STDLIB sources, first compile to bitcode: -$(STDLIB_SRCS:.cpp=.o.bc): %.o.bc: %.cpp $(BUILD_SYSTEM_DEPS) $(CLANG_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CLANG_CXX) $(CLANGFLAGS) -MMD -MP -MF $(patsubst %.bc,%.d,$@) $< -c -o $@ -emit-llvm -g -$(STDLIB_SRCS:.cpp=.release.o.bc): %.release.o.bc: %.cpp $(BUILD_SYSTEM_DEPS) $(CLANG_DEPS) - $(ECHO) Compiling $@ - $(VERB) $(CLANG_CXX) $(CLANGFLAGS_RELEASE) -MMD -MP -MF $(patsubst %.bc,%.d,$@) $< -c -o $@ -emit-llvm -g - -# Then, publicize symbols: -%.release.o.pub.bc: %.release.o.bc $(TOOLS_DIR)/publicize - $(ECHO) Publicizing $< - $(VERB) # $(TOOLS_DIR)/publicize_release $< -o $@ - $(VERB) $(TOOLS_DIR)/publicize $< -o $@ -%.pub.bc: %.bc $(TOOLS_DIR)/publicize - $(ECHO) Publicizing $< - $(VERB) $(TOOLS_DIR)/publicize $< -o $@ - -# Then, 1) compile the publicized bitcode into normal .o files -$(STDLIB_SRCS:.cpp=.o): %.o: %.o.pub.bc $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling bitcode to $@ - $(VERB) $(LLVM_BIN)/clang $(CLANGFLAGS) -c $< -o $@ -$(STDLIB_SRCS:.cpp=.release.o): %.release.o: %.release.o.pub.bc $(BUILD_SYSTEM_DEPS) - $(ECHO) Compiling bitcode to $@ - $(VERB) $(LLVM_BIN)/clang $(CLANGFLAGS) -O3 -c $< -o $@ - - -passes.so: $(PASS_OBJS) $(BUILD_SYSTEM_DEPS) - $(CXX) -shared $(PASS_OBJS) -o $@ -shared -rdynamic -test_opt: passes.so - $(LLVM_BUILD)/Release+Asserts/bin/opt -load passes.so test.ll -S -o test.opt.ll $(ARGS) -test_dbg_opt: passes.so - $(GDB) --args $(LLVM_BUILD)/Release+Asserts/bin/opt -O3 -load passes.so test.ll -S -o test.opt.ll $(ARGS) - -# And also link it all into what we're going to embed: -stdlib.unopt.bc: $(STDLIB_SRCS:.cpp=.o.pub.bc) - $(ECHO) Linking $@ - $(VERB) $(LLVM_BIN)/llvm-link $^ -o $@ -stdlib.release.unopt.bc: $(STDLIB_SRCS:.cpp=.release.o.pub.bc) - $(ECHO) Linking $@ - $(VERB) $(LLVM_BIN)/llvm-link $^ -o $@ - -# Optimize and/or strip it: -stdlib.bc: OPT_OPTIONS=-O3 -stdlib.release.bc: OPT_OPTIONS=-O3 -strip-debug -%.bc: %.unopt.bc - $(ECHO) Optimizing $@ - $(VERB) $(LLVM_BIN)/opt $(OPT_OPTIONS) $< -o $@ -%.stripped.bc: %.bc - $(ECHO) Optimizing $@ - $(VERB) $(LLVM_BIN)/opt -strip-debug $< -o $@ - -# Then do "ld -b binary" to create a .o file for embedding into the executable -$(STDLIB_OBJS) $(STDLIB_RELEASE_OBJS): %.o: % $(BUILD_SYSTEM_DEPS) - $(VERB) ld -r -b binary $< -o $@ - -# Optionally, disassemble the bitcode files: -%.ll: %.bc - $(LLVM_BIN)/llvm-dis $< - -# Not used currently, but here's how to pre-jit the stdlib bitcode: -%.release.cache: %.release.bc mcjitcache_release - ./mcjitcache_release -p $< -o $@ -%.cache: %.bc mcjitcache - ./mcjitcache -p $< -o $@ - - -# Finally, link it all together: -pyston_dbg: $(OBJS) $(LLVM_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(OBJS) $(LDFLAGS) -o $@ -pyston_debug: $(OBJS) $(LLVM_DEBUG_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(OBJS) $(LDFLAGS_DEBUG) -o $@ -pyston: $(OPT_OBJS) $(LLVM_RELEASE_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(OPT_OBJS) $(LDFLAGS_RELEASE) -o $@ -pyston_oprof: $(OPT_OBJS) codegen/profiling/oprofile.o $(LLVM_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(OPT_OBJS) codegen/profiling/oprofile.o $(LDFLAGS_RELEASE) -lopagent -o $@ -pyston_pprof: $(OPT_OBJS) codegen/profiling/pprof.release.o $(LLVM_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(OPT_OBJS) codegen/profiling/pprof.release.o $(LDFLAGS_RELEASE) -lprofiler -o $@ -pyston_prof: $(PROFILE_OBJS) $(LLVM_RELEASE_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(PROFILE_OBJS) $(LDFLAGS) -pg -o $@ -pyston_profile: $(PROFILE_OBJS) $(LLVM_PROFILE_DEPS) - $(ECHO) Linking $@ - $(VERB) $(CXX) $(PROFILE_OBJS) $(LDFLAGS_PROFILE) -o $@ - - --include $(wildcard *.d) $(wildcard */*.d) $(wildcard */*/*.d) - -.PHONY: clean -clean: - @ find . $(TOOLS_DIR) ../test \( -name '*.o' -o -name '*.d' -o -name '*.py_cache' -o -name '*.bc' -o -name '*.o.ll' -o -name '*.pub.ll' -o -name '*.cache' -o -name 'stdlib*.ll' -o -name '*.pyc' -o -name '*.so' -o -name '*.a' -o -name '*.expected_cache' \) -print -delete - @ find \( -name 'pyston*' -executable -type f \) -print -delete - @ find $(TOOLS_DIR) -maxdepth 0 -executable -type f -print -delete - @ rm -rf oprofile_data - -# A helper function that lets me run subdirectory rules from the top level; -# ex instead of saying "make tests/run_1", I can just write "make run_1" -define make_search -$(eval \ -$1: ../test/tests/$1 ; -$1: ../microbenchmarks/$1 ; -$1: ../benchmarks/$1 ; -) -endef - -RUN_DEPS := ext - -.PHONY: run run_release profile -run: pyston_dbg $(RUN_DEPS) - ./pyston_dbg $(ARGS) -run_release: pyston $(RUN_DEPS) - ./pyston $(ARGS) -profile: pyston_profile $(RUN_DEPS) - time ./pyston_profile $(ARGS) - gprof ./pyston_profile gmon.out > $(patsubst %,%.out,$@) - -.PHONY: run_% run_release_% debug_% dbg_% dbg_release_% memcheck_% memcheck_release_% memcheck_debug_% memleaks_% -run_%: %.py pyston_dbg $(RUN_DEPS) - zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./pyston_dbg $(ARGS) $<' -$(call make_search,run_%) -run_release_%: %.py pyston $(RUN_DEPS) - zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./pyston $(ARGS) $<' -$(call make_search,run_release_%) - -override GDB_CMDS := --ex "set confirm off" --ex run --ex "bt 20" $(GDB_CMDS) -ifneq ($(BR),) - override GDB_CMDS := --ex "break $(BR)" $(GDB_CMDS) -endif -dbg_release_%: %.py pyston $(RUN_DEPS) - $(GDB) $(GDB_CMDS) --args ./pyston $(ARGS) $< -$(call make_search,dbg_release_%) -dbg_%: %.py pyston_dbg $(RUN_DEPS) - zsh -c 'ulimit -v $(MAX_DBG_MEM_KB); $(GDB) $(GDB_CMDS) --args ./pyston_dbg $(ARGS) $<' -$(call make_search,dbg_%) -debug_%: %.py pyston_debug $(RUN_DEPS) - $(GDB) $(GDB_CMDS) --args ./pyston_debug $(ARGS) $< -$(call make_search,debug_%) -memcheck_%: %.py pyston_dbg $(RUN_DEPS) - $(VALGRIND) --tool=memcheck --leak-check=no ./pyston_dbg $(ARGS) $< -$(call make_search,memcheck_%) -memcheck_gdb_%: %.py pyston_dbg $(RUN_DEPS) - set +e; $(VALGRIND) -v -v -v -v -v --tool=memcheck --leak-check=no --track-origins=yes --vgdb=yes --vgdb-error=0 ./pyston_dbg $(ARGS) $< & export PID=$$! ; \ - $(GDB) --ex "set confirm off" --ex "target remote | $(DEPS_DIR)/valgrind-3.9.0-install/bin/vgdb" --ex "continue" --ex "bt" ./pyston_dbg; kill -9 $$PID -$(call make_search,memcheck_%) -kv: - ps aux | awk '/[v]algrind/ {print $$2}' | xargs kill -9; true -memcheck_release_%: %.py pyston $(RUN_DEPS) - $(VALGRIND) --tool=memcheck --leak-check=no ./pyston $(ARGS) $< -$(call make_search,memcheck_release_%) -memcheck_debug_%: %.py pyston_debug $(RUN_DEPS) - $(VALGRIND) --tool=memcheck --leak-check=no ./pyston_debug $(ARGS) $< -$(call make_search,memcheck_debug_%) -memleaks_%: %.py pyston_dbg $(RUN_DEPS) - $(VALGRIND) --tool=memcheck --leak-check=full --leak-resolution=low --show-reachable=yes ./pyston_dbg $(ARGS) $< -$(call make_search,memleaks_%) - -# gprof-based profiling: -.PHONY: prof_% profile_% -prof_%: %.py pyston_prof - zsh -c 'time ./pyston_prof $(ARGS) $<' - gprof ./pyston_prof gmon.out > $(patsubst %,%.out,$@) -$(call make_search,prof_%) -profile_%: %.py pyston_profile - time ./pyston_profile -p $(ARGS) $< - gprof ./pyston_profile gmon.out > $(patsubst %,%.out,$@) -$(call make_search,profile_%) - -# pprof-based profiling: -.PHONY: pprof_% pprof_release_% -pprof_%: %.py pyston_pprof - CPUPROFILE_FREQUENCY=1000 CPUPROFILE=$@.out ./pyston_pprof -p $(ARGS) $< - pprof --raw pyston_pprof $@.out > $@_raw.out - python codegen/profiling/process_pprof.py $@_raw.out pprof.jit > $@_processed.out - pprof --text $@_processed.out - # rm -f pprof.out pprof.raw pprof.jit -$(call make_search,pprof_%) - -perf_%: %.py pyston - perf record -g -- ./pyston -q -p $(ARGS) $< - perf report -v -g flat,1000 | bash $(TOOLS_DIR)/cumulate.sh | less -S -$(call make_search,perf_%) -perf_dbg_%: %.py pyston_dbg - perf record -g -- ./pyston_dbg -q -p $(ARGS) $< - perf report -v -g flat,1000 | bash $(TOOLS_DIR)/cumulate.sh | less -S -$(call make_search,perf_dbg_%) - -# oprofile-based profiling: -.PHONY: oprof_% oprof_collect_% opreport -oprof_collect_%: %.py pyston_oprof - sudo opcontrol --image pyston_oprof - # sudo opcontrol --event CPU_CLK_UNHALTED:28000 - # sudo opcontrol --cpu-buffer-size=128000 --buffer-size=1048576 --buffer-watershed=1048000 - sudo opcontrol --reset - sudo opcontrol --start - time ./pyston_oprof -p $(ARGS) $< - sudo opcontrol --stop - sudo opcontrol --dump - sudo opcontrol --image all --event default --cpu-buffer-size=0 --buffer-size=0 --buffer-watershed=0 - sudo opcontrol --deinit - sudo opcontrol --init -oprof_%: oprof_collect_% - $(MAKE) opreport -$(call make_search,oprof_%) -opreport: - ! [ -d oprofile_data ] - opreport -l -t 0.2 -a pyston_oprof - # opreport lib-image:pyston_oprof -l -t 0.2 -a | head -n 25 - -.PHONY: oprofcg_% oprof_collectcg_% opreportcg -oprof_collectcg_%: %.py pyston_oprof - operf -g -e CPU_CLK_UNHALTED:90000 ./pyston_oprof -p $(ARGS) $< -oprofcg_%: oprof_collectcg_% - $(MAKE) opreportcg -$(call make_search,oprofcg_%) -opreportcg: - opreport lib-image:pyston_oprof -l -t 0.2 -a --callgraph - -watch_%: - @ ( ulimit -t 60; ulimit -d $(MAK_MEM_KB); ulimit -v $(MAK_MEM_KB); \ - TARGET=$(dir $@)$(patsubst watch_%,%,$(notdir $@)); \ - clear; $(MAKE) $$TARGET; true; \ - while inotifywait -q -e modify -e attrib -e move -e move_self -e create -e delete -e delete_self \ - Makefile $$(find \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) ); do clear; $(MAKE) $$TARGET; done ) - # Makefile $$(find \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) -o -type d ); do clear; $(MAKE) $(patsubst watch_%,%,$@); done ) - # -r . ; do clear; $(MAKE) $(patsubst watch_%,%,$@); done -wdbg_%: - $(MAKE) $(patsubst wdbg_%,watch_dbg_%,$@) GDB_CMDS="--ex quit" - -.PHONY: test_asm test_cpp_asm -test_asm: - $(CLANG_EXE) tests/test.s -c -o test - objdump -d test | less - @ rm test -test_cpp_asm: - $(CLANG_EXE) tests/test.cpp -o test -c -O3 - # $(GPP) tests/test.cpp -o test -c -O3 - objdump -d test | less - rm test - -.PHONY: ext -ext: ../test/test_extension/test.so -../test/test_extension/test.so: ../test/test_extension/test.o $(BUILD_SYSTEM_DEPS) - cc -shared $< -o $@ -g -../test/test_extension/test.o: ../test/test_extension/test.c $(wildcard ../include/*.h) $(BUILD_SYSTEM_DEPS) - cc -O2 -fPIC -Wimplicit -I../include -c $< -o $@ -g diff --git a/src/analysis/fpc.h b/src/analysis/fpc.h deleted file mode 100644 index 087a74c04..000000000 --- a/src/analysis/fpc.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ANALYSIS_FPC_H -#define PYSTON_ANALYSIS_FPC_H - -#include "core/common.h" -#include "core/options.h" - -#include "core/cfg.h" - -namespace pyston { - -template -class BBAnalyzer { - public: - typedef std::unordered_map Map; - typedef std::unordered_map AllMap; - - virtual T merge(T from, T into) const = 0; - virtual T mergeBlank(T into) const = 0; - virtual void processBB(Map &starting, CFGBlock *block) const = 0; -}; - -template -typename BBAnalyzer::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer &analyzer, bool reverse) { - assert(!reverse); - - typedef typename BBAnalyzer::Map Map; - typedef typename BBAnalyzer::AllMap AllMap; - AllMap states; - - std::vector q; - - states.insert(make_pair(cfg->blocks[0], Map())); - q.push_back(cfg->blocks[0]); - - while (q.size()) { - CFGBlock *block = q.back(); - q.pop_back(); - - Map initial = states[block]; - if (VERBOSITY("analysis") >= 2) printf("fpc on block %d - %ld entries\n", block->idx, initial.size()); - - Map ending = Map(initial); - analyzer.processBB(ending, block); - - for (int i = 0; i < block->successors.size(); i++) { - CFGBlock *next_block = block->successors[i]; - bool changed = false; - bool initial = false; - if (states.count(next_block) == 0) { - changed = true; - initial = true; - } - - Map &next = states[next_block]; - for (typename Map::iterator it = ending.begin(), end = ending.end(); it != end; ++it) { - if (next.count(it->first) == 0) { - changed = true; - if (initial) { - next[it->first] = it->second; - } else { - next[it->first] = analyzer.mergeBlank(it->second); - } - } else { - T &next_elt = next[it->first]; - - T new_elt = analyzer.merge(it->second, next_elt); - if (next_elt != new_elt) { - next_elt = new_elt; - changed = true; - } - } - } - - for (typename Map::iterator it = next.begin(), end = ending.end(); it != end; ++it) { - if (ending.count(it->first)) - continue; - - T next_elt = analyzer.mergeBlank(it->second); - if (next_elt != it->second) { - next[it->first] = next_elt; - changed = true; - } - } - - if (changed) - q.push_back(next_block); - } - - states.erase(block); - states.insert(make_pair(block, ending)); - } - - return states; -} - -} - -#endif diff --git a/src/analysis/function_analysis.cpp b/src/analysis/function_analysis.cpp deleted file mode 100644 index e740b7454..000000000 --- a/src/analysis/function_analysis.cpp +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include -#include - -#include "core/common.h" - -#include "core/ast.h" -#include "core/cfg.h" -#include "core/util.h" - -#include "analysis/fpc.h" -#include "analysis/function_analysis.h" -#include "analysis/scoping_analysis.h" - -namespace pyston { - -class LivenessBBVisitor : public NoopASTVisitor { - public: - typedef std::unordered_set StrSet; - private: - StrSet _loads; - StrSet _stores; - - void _doLoad(const std::string& name) { - if (_stores.count(name)) - return; - _loads.insert(name); - } - void _doStore(const std::string& name) { - if (_loads.count(name)) - return; - _stores.insert(name); - } - public: - LivenessBBVisitor() { - } - const StrSet& loads() { return _loads; } - const StrSet& stores() { return _stores; } - - bool visit_classdef(AST_ClassDef* node) { - _doStore(node->name); - return true; - } - bool visit_functiondef(AST_FunctionDef* node) { - _doStore(node->name); - return true; - } - bool visit_name(AST_Name* node) { - if (node->ctx_type == AST_TYPE::Load) - _doLoad(node->id); - else if (node->ctx_type == AST_TYPE::Store) - _doStore(node->id); - else { - assert(0); - abort(); - } - return true; - } -}; - -bool LivenessAnalysis::isLiveAtEnd(const std::string &name, CFGBlock *block) { - if (block->successors.size() == 0) - return false; - - // Very inefficient liveness analysis: - // for each query, trace forward through all possible control flow paths. - // if we hit a store to the name, stop tracing that path - // if we hit a load to the name, return true. - std::unordered_set visited; - std::deque q; - for (int i = 0; i < block->successors.size(); i++) { - q.push_back(block->successors[i]); - } - - while(q.size()) { - CFGBlock* thisblock = q.front(); - q.pop_front(); - if (visited.count(thisblock)) - continue; - visited.insert(thisblock); - - LivenessBBVisitor visitor; - for (int i = 0; i < thisblock->body.size(); i++) { - thisblock->body[i]->accept(&visitor); - } - if (visitor.loads().count(name)) - return true; - if (!visitor.stores().count(name)) { - for (int i = 0; i < thisblock->successors.size(); i++) { - q.push_back(thisblock->successors[i]); - } - } - } - - return false; -} - -class DefinednessBBAnalyzer : public BBAnalyzer { - private: - typedef DefinednessAnalysis::DefinitionLevel DefinitionLevel; - - AST_arguments* arguments; - public: - DefinednessBBAnalyzer(AST_arguments* arguments) : arguments(arguments) { - } - - virtual DefinitionLevel merge(DefinitionLevel from, DefinitionLevel into) const { - assert(from != DefinednessAnalysis::Undefined); - assert(into != DefinednessAnalysis::Undefined); - if (from == DefinednessAnalysis::PotentiallyDefined || into == DefinednessAnalysis::PotentiallyDefined) - return DefinednessAnalysis::PotentiallyDefined; - return DefinednessAnalysis::Defined; - } - virtual void processBB(Map &starting, CFGBlock *block) const; - virtual DefinitionLevel mergeBlank(DefinitionLevel into) const { - assert(into != DefinednessAnalysis::Undefined); - return DefinednessAnalysis::PotentiallyDefined; - } -}; -class DefinednessVisitor : public ASTVisitor { - private: - typedef DefinednessBBAnalyzer::Map Map; - Map &state; - - void _doSet(const std::string &s) { - state[s] = DefinednessAnalysis::Defined; - } - - void _doSet(AST* t) { - switch (t->type) { - case AST_TYPE::Attribute: - // doesn't affect definedness (yet?) - break; - case AST_TYPE::Name: - _doSet(((AST_Name*)t)->id); - break; - case AST_TYPE::Subscript: - break; - case AST_TYPE::Tuple: { - AST_Tuple *tt = static_cast(t); - for (int i = 0; i < tt->elts.size(); i++) { - _doSet(tt->elts[i]); - } - break; - } - default: - ASSERT(0, "Unknown type for DefinednessVisitor: %d", t->type); - } - } - public: - DefinednessVisitor(Map &state) : state(state) { - } - - virtual bool visit_branch(AST_Branch* node) { return true; } - virtual bool visit_expr(AST_Expr* node) { return true; } - virtual bool visit_global(AST_Global* node) { return true; } - virtual bool visit_jump(AST_Jump* node) { return true; } - virtual bool visit_pass(AST_Pass* node) { return true; } - virtual bool visit_print(AST_Print* node) { return true; } - virtual bool visit_return(AST_Return* node) { return true; } - - virtual bool visit_classdef(AST_ClassDef *node) { - _doSet(node->name); - return true; - } - - virtual bool visit_functiondef(AST_FunctionDef *node) { - _doSet(node->name); - return true; - } - - virtual bool visit_import(AST_Import *node) { - for (int i = 0; i < node->names.size(); i++) { - AST_alias *alias = node->names[i]; - std::string &name = alias->name; - if (alias->asname.size()) - name = alias->asname; - - _doSet(name); - } - return true; - } - - virtual bool visit_assign(AST_Assign *node) { - for (int i = 0; i < node->targets.size(); i++) { - _doSet(node->targets[i]); - } - return true; - } - - virtual bool visit_arguments(AST_arguments *node) { - if (node->kwarg) _doSet(node->kwarg); - if (node->vararg.size()) _doSet(node->vararg); - for (int i = 0; i < node->args.size(); i++) { - _doSet(node->args[i]); - } - return true; - } -}; -void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const { - DefinednessVisitor visitor(starting); - for (int i = 0; i < block->body.size(); i++) { - block->body[i]->accept(&visitor); - } - if (block->idx == 0 && arguments) { - arguments->accept(&visitor); - } -} - -DefinednessAnalysis::DefinednessAnalysis(AST_arguments *args, CFG* cfg, ScopeInfo *scope_info) : scope_info(scope_info) { - results = computeFixedPoint(cfg, DefinednessBBAnalyzer(args), false); - - for (std::unordered_map >::iterator - it = results.begin(), end = results.end(); it != end; ++it) { - RequiredSet required; - for (std::unordered_map::iterator it2 = it->second.begin(), end2 = it->second.end(); - it2 != end2; ++it2) { - if (scope_info->refersToGlobal(it2->first)) - continue; - - //printf("%d %s %d\n", it->first->idx, it2->first.c_str(), it2->second); - required.insert(it2->first); - } - defined.insert(make_pair(it->first, required)); - } -} - -DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAt(const std::string &name, CFGBlock *block) { - std::unordered_map &map = results[block]; - if (map.count(name) == 0) - return Undefined; - return map[name]; -} - -const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(CFGBlock *block) { - return defined[block]; -} - -PhiAnalysis::PhiAnalysis(AST_arguments* args, CFG* cfg, LivenessAnalysis *liveness, ScopeInfo *scope_info) : - definedness(args, cfg, scope_info), liveness(liveness) { - for (int i = 0; i < cfg->blocks.size(); i++) { - CFGBlock *block = cfg->blocks[i]; - - RequiredSet required; - if (block->predecessors.size() < 2) - continue; - - const RequiredSet& defined = definedness.getDefinedNamesAt(block); - if (defined.size()) - assert(block->predecessors.size()); - for (RequiredSet::const_iterator it = defined.begin(), end = defined.end(); it != end; ++it) { - if (liveness->isLiveAtEnd(*it, block->predecessors[0])) { - required.insert(*it); - } - } - - required_phis.insert(make_pair(block, required)); - } -} - -const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock *block) { - static RequiredSet empty; - if (block->successors.size() == 0) - return empty; - return required_phis[block->successors[0]]; -} - -const PhiAnalysis::RequiredSet& PhiAnalysis::getAllDefinedAt(CFGBlock *block) { - return definedness.getDefinedNamesAt(block); -} - -bool PhiAnalysis::isRequired(const std::string &name, CFGBlock* block) { - return required_phis[block].count(name) != 0; -} - -bool PhiAnalysis::isRequiredAfter(const std::string &name, CFGBlock* block) { - // If there are multiple successors, then none of them are allowed - // to require any phi nodes - if (block->successors.size() != 1) - return false; - - // Fall back to the other method: - return isRequired(name, block->successors[0]); -} - -bool PhiAnalysis::isPotentiallyUndefinedAfter(const std::string &name, CFGBlock* block) { - assert(block->successors.size() > 0); - DefinednessAnalysis::DefinitionLevel dlevel = definedness.isDefinedAt(name, block->successors[0]); - ASSERT(dlevel != DefinednessAnalysis::Undefined, "%s %d", name.c_str(), block->idx); - - return dlevel == DefinednessAnalysis::PotentiallyDefined; -} - -LivenessAnalysis* computeLivenessInfo(CFG*) { - return new LivenessAnalysis(); -} - -PhiAnalysis* computeRequiredPhis(AST_arguments* args, CFG* cfg, LivenessAnalysis* liveness, ScopeInfo *scope_info) { - return new PhiAnalysis(args, cfg, liveness, scope_info); -} - -} diff --git a/src/analysis/function_analysis.h b/src/analysis/function_analysis.h deleted file mode 100644 index 0c81ff69a..000000000 --- a/src/analysis/function_analysis.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ANALYSIS_FUNCTIONANALYSIS_H -#define PYSTON_ANALYSIS_FUNCTIONANALYSIS_H - -#include - -namespace pyston { - -class AST_arguments; -class AST_Jump; -class CFG; -class CFGBlock; -class ScopeInfo; - -class LivenessAnalysis { - public: - bool isLiveAtEnd(const std::string &name, CFGBlock *block); -}; -class DefinednessAnalysis { - public: - enum DefinitionLevel { - Undefined, - PotentiallyDefined, - Defined, - }; - typedef std::unordered_set RequiredSet; - - private: - std::unordered_map > results; - std::unordered_map defined; - ScopeInfo *scope_info; - - public: - DefinednessAnalysis(AST_arguments *args, CFG* cfg, ScopeInfo *scope_info); - - DefinitionLevel isDefinedAt(const std::string &name, CFGBlock *block); - const RequiredSet& getDefinedNamesAt(CFGBlock *block); -}; -class PhiAnalysis { - public: - typedef std::unordered_set RequiredSet; - - private: - DefinednessAnalysis definedness; - LivenessAnalysis *liveness; - std::unordered_map required_phis; - - public: - PhiAnalysis(AST_arguments*, CFG* cfg, LivenessAnalysis *liveness, ScopeInfo *scope_info); - - bool isRequired(const std::string &name, CFGBlock* block); - bool isRequiredAfter(const std::string &name, CFGBlock* block); - const RequiredSet& getAllRequiredAfter(CFGBlock *block); - const RequiredSet& getAllDefinedAt(CFGBlock *block); - bool isPotentiallyUndefinedAfter(const std::string &name, CFGBlock* block); -}; - -LivenessAnalysis* computeLivenessInfo(CFG*); -PhiAnalysis* computeRequiredPhis(AST_arguments*, CFG*, LivenessAnalysis*, ScopeInfo* scope_Info); - -} - -#endif - diff --git a/src/analysis/scoping_analysis.cpp b/src/analysis/scoping_analysis.cpp deleted file mode 100644 index 6e0e6976b..000000000 --- a/src/analysis/scoping_analysis.cpp +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/common.h" - -#include "core/ast.h" -#include "core/util.h" - -#include "analysis/scoping_analysis.h" - -namespace pyston { - -static bool isCompilerCreatedName(const std::string &name) { - return name[0] == '!' || name[0] == '#'; -} - -class ModuleScopeInfo : public ScopeInfo { - public: - virtual ScopeInfo* getParent() { - return NULL; - } - - virtual bool createsClosure() { - return false; - } - - virtual bool takesClosure() { - return false; - } - - virtual bool refersToGlobal(const std::string &name) { - if (isCompilerCreatedName(name)) - return false; - - //assert(name[0] != '#' && "should test this"); - return true; - } - virtual bool refersToClosure(const std::string name) { - return false; - } - virtual bool saveInClosure(const std::string name) { - return false; - } -}; - -struct ScopingAnalysis::ScopeNameUsage { - AST* node; - ScopeNameUsage* parent; - - typedef std::unordered_set StrSet; - - // Properties determined from crawling the scope: - StrSet read; - StrSet written; - StrSet forced_globals; - - // Properties determined by looking at other scopes as well: - StrSet referenced_from_nested; - StrSet got_from_closure; - - ScopeNameUsage(AST* node, ScopeNameUsage* parent) : node(node), parent(parent) { - } -}; - -class ScopeInfoBase : public ScopeInfo { - private: - ScopeInfo* parent; - ScopingAnalysis::ScopeNameUsage *usage; - public: - ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage *usage) : parent(parent), usage(usage) { - assert(parent); - assert(usage); - } - - virtual ~ScopeInfoBase() { - delete this->usage; - } - - virtual ScopeInfo* getParent() { - return parent; - } - - virtual bool createsClosure() { - assert(0); - return usage->referenced_from_nested.size() > 0; - } - - virtual bool takesClosure() { - assert(0); - return false; - } - - virtual bool refersToGlobal(const std::string &name) { - // HAX - if (isCompilerCreatedName(name)) - return false; - - if (usage->forced_globals.count(name)) - return true; - return usage->written.count(name) == 0 && usage->got_from_closure.count(name) == 0; - } - virtual bool refersToClosure(const std::string name) { - // HAX - if (isCompilerCreatedName(name)) - return false; - return usage->got_from_closure.count(name) != 0; - } - virtual bool saveInClosure(const std::string name) { - // HAX - if (isCompilerCreatedName(name)) - return false; - return usage->referenced_from_nested.count(name) != 0; - } -}; - -class NameCollectorVisitor : public ASTVisitor { - private: - AST* orig_node; - ScopingAnalysis::NameUsageMap *map; - ScopingAnalysis::ScopeNameUsage *cur; - NameCollectorVisitor(AST* node, ScopingAnalysis::NameUsageMap *map) : orig_node(node), map(map) { - assert(map); - cur = (*map)[node]; - assert(cur); - } - - public: - - void doWrite(const std::string& name) { - cur->read.insert(name); - cur->written.insert(name); - } - - void doRead(const std::string& name) { - cur->read.insert(name); - } - - virtual bool visit_name(AST_Name *node) { - switch (node->ctx_type) { - case AST_TYPE::Load: - doRead(node->id); - break; - case AST_TYPE::Param: - case AST_TYPE::Store: - doWrite(node->id); - break; - default: - RELEASE_ASSERT(0, "%d", node->ctx_type); - } - return true; - } - - virtual bool visit_arguments(AST_arguments *node) { return false; } - virtual bool visit_assign(AST_Assign *node) { return false; } - virtual bool visit_attribute(AST_Attribute *node) { return false; } - virtual bool visit_binop(AST_BinOp *node) { return false; } - virtual bool visit_boolop(AST_BoolOp *node) { return false; } - virtual bool visit_break(AST_Break *node) { return false; } - virtual bool visit_call(AST_Call *node) { return false; } - virtual bool visit_compare(AST_Compare *node) { return false; } - //virtual bool visit_classdef(AST_ClassDef *node) { return false; } - virtual bool visit_continue(AST_Continue *node) { return false; } - virtual bool visit_dict(AST_Dict *node) { return false; } - virtual bool visit_expr(AST_Expr *node) { return false; } - virtual bool visit_for(AST_For *node) { return false; } - //virtual bool visit_functiondef(AST_FunctionDef *node) { return false; } - //virtual bool visit_global(AST_Global *node) { return false; } - virtual bool visit_if(AST_If *node) { return false; } - virtual bool visit_index(AST_Index *node) { return false; } - //virtual bool visit_keyword(AST_keyword *node) { return false; } - virtual bool visit_list(AST_List *node) { return false; } - //virtual bool visit_module(AST_Module *node) { return false; } - //virtual bool visit_name(AST_Name *node) { return false; } - virtual bool visit_num(AST_Num *node) { return false; } - virtual bool visit_pass(AST_Pass *node) { return false; } - virtual bool visit_print(AST_Print *node) { return false; } - virtual bool visit_return(AST_Return *node) { return false; } - virtual bool visit_slice(AST_Slice *node) { return false; } - virtual bool visit_str(AST_Str *node) { return false; } - virtual bool visit_subscript(AST_Subscript *node) { return false; } - virtual bool visit_tuple(AST_Tuple *node) { return false; } - virtual bool visit_unaryop(AST_UnaryOp *node) { return false; } - virtual bool visit_while(AST_While *node) { return false; } - virtual bool visit_with(AST_With *node) { return false; } - - virtual bool visit_branch(AST_Branch *node) { return false; } - virtual bool visit_jump(AST_Jump *node) { return false; } - - - virtual bool visit_global(AST_Global *node) { - for (int i = 0; i < node->names.size(); i++) { - const std::string &name = node->names[i]; - cur->forced_globals.insert(name); - } - return true; - } - - virtual bool visit_classdef(AST_ClassDef *node) { - if (node == orig_node) { - return false; - } else { - doWrite(node->name); - (*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur); - collect(node, map); - return true; - } - } - - virtual bool visit_functiondef(AST_FunctionDef *node) { - if (node == orig_node) { - return false; - } else { - doWrite(node->name); - (*map)[node] = new ScopingAnalysis::ScopeNameUsage(node, cur); - collect(node, map); - return true; - } - } - - virtual bool visit_import(AST_Import *node) { - for (int i = 0; i < node->names.size(); i++) { - AST_alias *alias = node->names[i]; - if (alias->asname.size()) - doWrite(alias->asname); - else - doWrite(alias->name); - } - return true; - } - - static void collect(AST* node, ScopingAnalysis::NameUsageMap *map) { - assert(map); - assert(map->count(node)); - - NameCollectorVisitor vis(node, map); - node->accept(&vis); - } -}; - -static std::vector sortNameUsages(ScopingAnalysis::NameUsageMap* usages) { - std::vector rtn; - std::unordered_set added; - - for (ScopingAnalysis::NameUsageMap::iterator it = usages->begin(), end = usages->end(); - it != end; ++it) { - ScopingAnalysis::ScopeNameUsage *usage = it->second; - - std::vector traversed; - - while (usage && added.count(usage) == 0) { - traversed.push_back(usage); - usage = usage->parent; - } - - for (int i = traversed.size() - 1; i >= 0; i--) { - rtn.push_back(traversed[i]); - added.insert(traversed[i]); - } - } - - assert(rtn.size() == usages->size()); - - return rtn; -} - -void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) { - typedef ScopeNameUsage::StrSet StrSet; - - // Resolve name lookups: - for (ScopingAnalysis::NameUsageMap::iterator it = usages->begin(), end = usages->end(); - it != end; ++it) { - ScopeNameUsage *usage = it->second; - for (StrSet::iterator it2 = usage->read.begin(), end2 = usage->read.end(); - it2 != end2; ++it2) { - if (usage->forced_globals.count(*it2)) - continue; - if (usage->written.count(*it2)) - continue; - - ScopeNameUsage *parent = usage->parent; - while (parent) { - if (parent->node->type == AST_TYPE::ClassDef) { - parent = parent->parent; - } else if (parent->forced_globals.count(*it2)) { - break; - } else if (parent->written.count(*it2)) { - usage->got_from_closure.insert(*it2); - parent->referenced_from_nested.insert(*it2); - break; - } else { - parent = parent->parent; - } - } - } - } - - - std::vector sorted_usages = sortNameUsages(usages); - - // Construct the public-facing ScopeInfo's from the analyzed data: - for (int i = 0; i < sorted_usages.size(); i++) { - ScopeNameUsage *usage = sorted_usages[i]; - AST* node = usage->node; - - ScopeInfo *parent_info = this->scopes[(usage->parent == NULL) ? this->parent_module : usage->parent->node]; - - switch (node->type) { - case AST_TYPE::FunctionDef: - this->scopes[node] = new ScopeInfoBase(parent_info, usage); - break; - case AST_TYPE::ClassDef: - this->scopes[node] = new ScopeInfoBase(parent_info, usage); - break; - default: - RELEASE_ASSERT(0, "%d", usage->node->type); - break; - } - } -} - -ScopeInfo* ScopingAnalysis::analyzeSubtree(AST* node) { -#ifndef NDEBUG - std::vector* flattened = flatten(parent_module->body, false); - bool found = 0; - for (int i = 0; i < flattened->size(); i++) { - if ((*flattened)[i] == node) { - found = true; - break; - } - } - assert(found); - delete flattened; -#endif - - NameUsageMap usages; - usages[node] = new ScopeNameUsage(node, NULL); - NameCollectorVisitor::collect(node, &usages); - - processNameUsages(&usages); - - ScopeInfo *rtn = scopes[node]; - assert(rtn); - return rtn; -} - -ScopeInfo* ScopingAnalysis::getScopeInfoForNode(AST* node) { - assert(node); - - ScopeInfo* rtn = scopes[node]; - if (rtn) - return rtn; - - switch (node->type) { - case AST_TYPE::ClassDef: - case AST_TYPE::FunctionDef: - return analyzeSubtree(node); - // this is handled in the constructor: - //case AST_TYPE::Module: - //return new ModuleScopeInfo(); - default: - RELEASE_ASSERT(0, "%d", node->type); - } -} - -ScopingAnalysis::ScopingAnalysis(AST_Module *m) : parent_module(m) { - scopes[m] = new ModuleScopeInfo(); -} - -ScopingAnalysis* runScopingAnalysis(AST_Module* m) { - return new ScopingAnalysis(m); -} - -} diff --git a/src/analysis/scoping_analysis.h b/src/analysis/scoping_analysis.h deleted file mode 100644 index cbcea867c..000000000 --- a/src/analysis/scoping_analysis.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ANALYSIS_SCOPINGANALYSIS_H -#define PYSTON_ANALYSIS_SCOPINGANALYSIS_H - -#include "core/common.h" - -namespace pyston { - -class AST_Module; - -class ScopeInfo { - public: - virtual ~ScopeInfo() {} - virtual ScopeInfo* getParent() = 0; - - virtual bool createsClosure() = 0; - virtual bool takesClosure() = 0; - - virtual bool refersToGlobal(const std::string &name) = 0; - virtual bool refersToClosure(const std::string name) = 0; - virtual bool saveInClosure(const std::string name) = 0; -}; - -class ScopingAnalysis { - public: - struct ScopeNameUsage; - typedef std::unordered_map NameUsageMap; - - private: - - std::unordered_map scopes; - AST_Module* parent_module; - - ScopeInfo* analyzeSubtree(AST* node); - void processNameUsages(NameUsageMap* usages); - - public: - ScopingAnalysis(AST_Module *m); - ScopeInfo* getScopeInfoForNode(AST* node); -}; - -ScopingAnalysis* runScopingAnalysis(AST_Module* m); - -} - -#endif diff --git a/src/analysis/type_analysis.cpp b/src/analysis/type_analysis.cpp deleted file mode 100644 index f571f0b6a..000000000 --- a/src/analysis/type_analysis.cpp +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "core/options.h" - -#include "core/ast.h" -#include "core/cfg.h" - -#include "analysis/scoping_analysis.h" -#include "analysis/type_analysis.h" - -#include "runtime/types.h" - -//#undef VERBOSITY -//#define VERBOSITY(x) 2 - -namespace pyston { - -class NullTypeAnalysis : public TypeAnalysis { - public: - virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string &name, CFGBlock* block); - virtual ConcreteCompilerType* getTypeAtBlockEnd(const std::string &name, CFGBlock* block); -}; - -ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockStart(const std::string &name, CFGBlock *block) { - return UNKNOWN; -} - -ConcreteCompilerType* NullTypeAnalysis::getTypeAtBlockEnd(const std::string &name, CFGBlock *block) { - assert(block->successors.size() > 0); - return getTypeAtBlockStart(name, block->successors[0]); -} - - -static ConcreteCompilerType* unboxedType(ConcreteCompilerType *t) { - if (t == BOXED_INT) - return INT; - if (t == BOXED_FLOAT) - return FLOAT; - return t; -} - -static BoxedClass* simpleCallSpeculation(AST_Call* node, CompilerType* rtn_type, std::vector arg_types) { - if (rtn_type->getConcreteType()->llvmType() != g.llvm_value_type_ptr) { - //printf("Not right shape; it's %s\n", rtn_type->debugName().c_str()); - return NULL; - } - - if (node->func->type == AST_TYPE::Name && static_cast(node->func)->id == "xrange") - return xrange_cls; - - //if (node->func->type == AST_TYPE::Attribute && static_cast(node->func)->attr == "dot") - //return float_cls; - - return NULL; -} - -typedef std::unordered_map TypeMap; -typedef std::unordered_map AllTypeMap; -typedef std::unordered_map ExprTypeMap; -typedef std::unordered_map TypeSpeculations; -class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor { - private: - static const bool EXPAND_UNNEEDED = true; - - CFGBlock *block; - TypeMap &sym_table; - ExprTypeMap &expr_types; - TypeSpeculations &type_speculations; - TypeAnalysis::SpeculationLevel speculation; - ScopeInfo *scope_info; - - BasicBlockTypePropagator(CFGBlock *block, TypeMap &initial, ExprTypeMap &expr_types, TypeSpeculations &type_speculations, TypeAnalysis::SpeculationLevel speculation, ScopeInfo *scope_info) : block(block), sym_table(initial), expr_types(expr_types), type_speculations(type_speculations), speculation(speculation), scope_info(scope_info) {} - - void run() { - for (int i = 0; i < block->body.size(); i++) { - block->body[i]->accept_stmt(this); - } - } - - CompilerType* processSpeculation(BoxedClass* speculated_cls, AST_expr* node, CompilerType* old_type) { - assert(old_type); - assert(speculation != TypeAnalysis::NONE); - - if (speculated_cls != NULL) { - ConcreteCompilerType* speculated_type = unboxedType(typeFromClass(speculated_cls)); - if (VERBOSITY() >= 2) { - printf("in propagator, speculating that %s would actually be %s, at:\n", old_type->debugName().c_str(), speculated_type->debugName().c_str()); - print_ast(node); - printf("\n"); - } - - if (!old_type->canConvertTo(speculated_type)) { - type_speculations[node] = speculated_cls; - return speculated_type; - } - } - return old_type; - } - - CompilerType* getType(AST_expr* node) { - type_speculations.erase(node); - - void* raw_rtn = node->accept_expr(this); - CompilerType *rtn = static_cast(raw_rtn); - - if (VERBOSITY() >= 2) { - print_ast(node); - printf(" %s\n", rtn->debugName().c_str()); - } - - expr_types[node] = rtn; - return rtn; - } - - void _doSet(std::string target, CompilerType *t) { - if (t) - sym_table[target] = t; - } - - void _doSet(AST_expr* target, CompilerType *t) { - switch (target->type) { - case AST_TYPE::Attribute: - // doesn't affect types (yet?) - break; - case AST_TYPE::Name: - _doSet(static_cast(target)->id, t); - break; - case AST_TYPE::Subscript: - break; - case AST_TYPE::Tuple: { - AST_Tuple *tt = static_cast(target); - for (int i = 0; i < tt->elts.size(); i++) { - _doSet(tt->elts[i], UNKNOWN); - } - break; - } - default: - ASSERT(0, "Unknown type for TypePropagator: %d", target->type); - abort(); - } - } - - virtual void* visit_attribute(AST_Attribute *node) { - CompilerType *t = getType(node->value); - assert(node->ctx_type == AST_TYPE::Load); - CompilerType *rtn = t->getattrType(node->attr); - - //if (speculation != TypeAnalysis::NONE && (node->attr == "x" || node->attr == "y" || node->attr == "z")) { - //rtn = processSpeculation(float_cls, node, rtn); - //} - - if (VERBOSITY() >= 2 && rtn == UNDEF) { - printf("Think %s.%s is undefined, at %d:%d\n", t->debugName().c_str(), node->attr.c_str(), node->lineno, node->col_offset); - print_ast(node); - printf("\n"); - } - return rtn; - } - - virtual void* visit_clsattribute(AST_ClsAttribute *node) { - CompilerType *t = getType(node->value); - CompilerType *rtn = t->getattrType(node->attr); - if (VERBOSITY() >= 2 && rtn == UNDEF) { - printf("Think %s.%s is undefined, at %d:%d\n", t->debugName().c_str(), node->attr.c_str(), node->lineno, node->col_offset); - print_ast(node); - printf("\n"); - } - return rtn; - } - - virtual void* visit_binop(AST_BinOp *node) { - CompilerType *left = getType(node->left); - CompilerType *right = getType(node->right); - - // TODO this isn't the exact behavior - std::string name = getOpName(node->op_type); - CompilerType *attr_type = left->getattrType(name); - - std::vector arg_types; - arg_types.push_back(right); - CompilerType *rtn = attr_type->callType(arg_types); - - if (left == right && (left == INT || left == FLOAT)) { - ASSERT((rtn == left || rtn == UNDEF) && "not strictly required but probably something worth looking into", "%s %s", name.c_str(), rtn->debugName().c_str()); - } - - return rtn; - } - - virtual void* visit_boolop(AST_BoolOp *node) { - int n = node->values.size(); - - CompilerType* rtn = NULL; - for (int i = 0; i < n; i++) { - CompilerType* t = getType(node->values[i]); - if (rtn == NULL) - rtn = t; - else if (rtn != t) - rtn = UNKNOWN; - } - - return rtn; - } - - virtual void* visit_call(AST_Call *node) { - assert(!node->starargs); - assert(!node->kwargs); - assert(node->keywords.size() == 0); - CompilerType* func = getType(node->func); - - std::vector arg_types; - for (int i = 0; i < node->args.size(); i++) { - arg_types.push_back(getType(node->args[i])); - } - CompilerType *rtn_type = func->callType(arg_types); - - // Should be unboxing things before getting here: - ASSERT(rtn_type == unboxedType(rtn_type->getConcreteType()), "%s", rtn_type->debugName().c_str()); - rtn_type = unboxedType(rtn_type->getConcreteType()); - - if (speculation != TypeAnalysis::NONE) { - BoxedClass* speculated_rtn_cls = simpleCallSpeculation(node, rtn_type, arg_types); - rtn_type = processSpeculation(speculated_rtn_cls, node, rtn_type); - } - - return rtn_type; - } - - virtual void* visit_compare(AST_Compare *node) { - RELEASE_ASSERT(node->ops.size() == 1, "unimplemented"); - - CompilerType *left = getType(node->left); - CompilerType *right = getType(node->comparators[0]); - - if (node->ops[0] == AST_TYPE::Is || node->ops[0] == AST_TYPE::IsNot) { - assert(node->ops.size() == 1 && "I don't think this should happen"); - return BOOL; - } - std::string name = getOpName(node->ops[0]); - CompilerType *attr_type = left->getattrType(name); - std::vector arg_types; - arg_types.push_back(right); - return attr_type->callType(arg_types); - } - - virtual void* visit_dict(AST_Dict *node) { - return DICT; - } - - virtual void* visit_index(AST_Index* node) { - return getType(node->value); - } - - virtual void* visit_list(AST_List *node) { - return LIST; - } - - virtual void* visit_name(AST_Name *node) { - if (scope_info->refersToGlobal(node->id)) { - if (node->id == "xrange") { - //printf("TODO guard here and return the classobj\n"); - //return typeOfClassobj(xrange_cls); - } - return UNKNOWN; - } - - CompilerType* &t = sym_table[node->id]; - if (t == NULL) { - if (VERBOSITY() >= 2) { - printf("%s is undefined!\n", node->id.c_str()); - raise(SIGTRAP); - } - t = UNDEF; - } - return t; - } - - virtual void* visit_num(AST_Num *node) { - switch (node->num_type) { - case AST_Num::INT: - return INT; - case AST_Num::FLOAT: - return FLOAT; - } - abort(); - } - - virtual void* visit_slice(AST_Slice *node) { - return SLICE; - } - - virtual void* visit_str(AST_Str *node) { - return STR; - } - - virtual void* visit_subscript(AST_Subscript *node) { - CompilerType *val = getType(node->value); - CompilerType *slice = getType(node->slice); - CompilerType *getitem_type = val->getattrType("__getitem__"); - std::vector args; - args.push_back(slice); - return getitem_type->callType(args); - } - - virtual void* visit_tuple(AST_Tuple *node) { - std::vector elt_types; - for (int i = 0; i < node->elts.size(); i++) { - elt_types.push_back(getType(node->elts[i])); - } - return makeTupleType(elt_types); - } - - virtual void* visit_unaryop(AST_UnaryOp *node) { - CompilerType *operand = getType(node->operand); - - // TODO this isn't the exact behavior - std::string name = getOpName(node->op_type); - CompilerType *attr_type = operand->getattrType(name); - std::vector arg_types; - return attr_type->callType(arg_types); - } - - - - - virtual void visit_assign(AST_Assign* node) { - CompilerType* t = getType(node->value); - for (int i = 0; i < node->targets.size(); i++) { - _doSet(node->targets[i], t); - } - } - - virtual void visit_branch(AST_Branch* node) { - if (EXPAND_UNNEEDED) { - getType(node->test); - } - } - - virtual void visit_classdef(AST_ClassDef *node) { - CompilerType *t = typeFromClass(type_cls); - _doSet(node->name, t); - } - - virtual void visit_expr(AST_Expr* node) { - if (EXPAND_UNNEEDED) { - if (node->value != NULL) - getType(node->value); - } - } - - virtual void visit_functiondef(AST_FunctionDef *node) { - _doSet(node->name, typeFromClass(function_cls)); - } - - virtual void visit_global(AST_Global* node) { - } - - virtual void visit_import(AST_Import *node) { - for (int i = 0; i < node->names.size(); i++) { - AST_alias *alias = node->names[i]; - std::string &name = alias->name; - if (alias->asname.size()) - name = alias->asname; - - _doSet(name, UNKNOWN); - } - } - - virtual void visit_jump(AST_Jump* node) {} - virtual void visit_pass(AST_Pass* node) {} - - virtual void visit_print(AST_Print* node) { - assert(node->dest == NULL); - if (EXPAND_UNNEEDED) { - for (int i = 0; i < node->values.size(); i++) { - getType(node->values[i]); - } - } - } - - virtual void visit_return(AST_Return* node) { - if (EXPAND_UNNEEDED) { - if (node->value != NULL) - getType(node->value); - } - } - - public: - static void propagate(CFGBlock *block, const TypeMap &starting, TypeMap &ending, ExprTypeMap &expr_types, TypeSpeculations &type_speculations, TypeAnalysis::SpeculationLevel speculation, ScopeInfo *scope_info) { - ending.insert(starting.begin(), starting.end()); - BasicBlockTypePropagator(block, ending, expr_types, type_speculations, speculation, scope_info).run(); - } -}; - -class PropagatingTypeAnalysis : public TypeAnalysis { - private: - AllTypeMap starting_types; - ExprTypeMap expr_types; - TypeSpeculations type_speculations; - SpeculationLevel speculation; - - PropagatingTypeAnalysis(const AllTypeMap &starting_types, const ExprTypeMap &expr_types, TypeSpeculations &type_speculations, SpeculationLevel speculation) : starting_types(starting_types), expr_types(expr_types), type_speculations(type_speculations), speculation(speculation) {} - - public: - virtual ConcreteCompilerType* getTypeAtBlockEnd(const std::string &name, CFGBlock* block) { - assert(block->successors.size() > 0); - return getTypeAtBlockStart(name, block->successors[0]); - } - virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string &name, CFGBlock* block) { - CompilerType *base = starting_types[block->idx][name]; - ASSERT(base != NULL, "%s %d", name.c_str(), block->idx); - - ConcreteCompilerType *rtn = base->getConcreteType(); - ASSERT(rtn != NULL, "%s %d", name.c_str(), block->idx); - return rtn; - } - - virtual BoxedClass* speculatedExprClass(AST_expr* call) { - return type_speculations[call]; - } - - static bool merge(CompilerType *lhs, CompilerType* &rhs) { - assert(lhs); - if (rhs == NULL) { - rhs = lhs; - return true; - } - - if (lhs == UNDEF || rhs == UNDEF) - return false; - - if (lhs == rhs) - return false; - if (rhs == UNKNOWN) - return false; - if (lhs == UNKNOWN) { - rhs = UNKNOWN; - return true; - } - - rhs = UNKNOWN; - return true; - - ASSERT(0, "dont know how to merge these types: %s, %s", lhs->debugName().c_str(), rhs->debugName().c_str()); - abort(); - } - static bool merge(const TypeMap &ending, TypeMap &next) { - bool changed = false; - for (TypeMap::const_iterator it = ending.begin(); it != ending.end(); it++) { - CompilerType* &prev = next[it->first]; - changed = merge(it->second, prev) || changed; - } - return changed; - } - - static PropagatingTypeAnalysis* doAnalysis(CFG *cfg, const std::vector &arg_names, const std::vector &arg_types, SpeculationLevel speculation, ScopeInfo *scope_info) { - AllTypeMap starting_types; - ExprTypeMap expr_types; - TypeSpeculations type_speculations; - - assert(arg_names.size() == arg_types.size()); - - { - TypeMap &initial_types = starting_types[0]; - for (int i = 0; i < arg_names.size(); i++) { - AST_expr* arg = arg_names[i]; - assert(arg->type == AST_TYPE::Name); - AST_Name *arg_name = static_cast(arg); - initial_types[arg_name->id] = unboxedType(arg_types[i]); - } - } - - std::unordered_set in_queue; - std::deque queue; - queue.push_back(0); - - while (queue.size()) { - int block_id = queue.front(); - queue.pop_front(); - in_queue.erase(block_id); - - CFGBlock *block = cfg->blocks[block_id]; - - TypeMap ending; - - if (VERBOSITY("types")) { - printf("processing types for block %d\n", block_id); - } - if (VERBOSITY("types") >= 2) { - printf("before:\n"); - TypeMap &starting = starting_types[block_id]; - for (TypeMap::iterator it = starting.begin(), end = starting.end(); it != end; ++it) { - ASSERT(it->second, "%s", it->first.c_str()); - printf("%s: %s\n", it->first.c_str(), it->second->debugName().c_str()); - } - } - - BasicBlockTypePropagator::propagate(block, starting_types[block_id], ending, expr_types, type_speculations, speculation, scope_info); - - if (VERBOSITY("types") >= 2) { - printf("before (after):\n"); - TypeMap &starting = starting_types[block_id]; - for (TypeMap::iterator it = starting.begin(), end = starting.end(); it != end; ++it) { - ASSERT(it->second, "%s", it->first.c_str()); - printf("%s: %s\n", it->first.c_str(), it->second->debugName().c_str()); - } - printf("after:\n"); - for (TypeMap::iterator it = ending.begin(), end = ending.end(); it != end; ++it) { - ASSERT(it->second, "%s", it->first.c_str()); - printf("%s: %s\n", it->first.c_str(), it->second->debugName().c_str()); - } - } - - for (int i = 0; i < block->successors.size(); i++) { - int next_id = block->successors[i]->idx; - bool first = (starting_types.count(next_id) == 0); - bool changed = merge(ending, starting_types[next_id]); - if ((first || changed) && in_queue.insert(next_id).second) { - queue.push_back(next_id); - } - } - } - - if (VERBOSITY("types") >= 2) { - for (int i = 0; i < cfg->blocks.size(); i++) { - printf("Types at beginning of block %d:\n", i); - CFGBlock *b = cfg->blocks[i]; - - TypeMap &starting = starting_types[i]; - for (TypeMap::iterator it = starting.begin(), end = starting.end(); it != end; ++it) { - ASSERT(it->second, "%s", it->first.c_str()); - printf("%s: %s\n", it->first.c_str(), it->second->debugName().c_str()); - } - } - } - - return new PropagatingTypeAnalysis(starting_types, expr_types, type_speculations, speculation); - } -}; - - -// public entry point: -TypeAnalysis* doTypeAnalysis(CFG *cfg, const std::vector &arg_names, const std::vector &arg_types, TypeAnalysis::SpeculationLevel speculation, ScopeInfo *scope_info) { - //return new NullTypeAnalysis(); - return PropagatingTypeAnalysis::doAnalysis(cfg, arg_names, arg_types, speculation, scope_info); -} - -} diff --git a/src/analysis/type_analysis.h b/src/analysis/type_analysis.h deleted file mode 100644 index 32a0d96fe..000000000 --- a/src/analysis/type_analysis.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ANALYSIS_TYPEANALYSIS_H -#define PYSTON_ANALYSIS_TYPEANALYSIS_H - -#include -#include - -//#include "ast.h" -#include "codegen/compvars.h" - -namespace pyston { - -class ScopeInfo; - -class TypeAnalysis { - public: - enum SpeculationLevel { - NONE, - SOME, - }; - - virtual ~TypeAnalysis() {} - - virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string &name, CFGBlock* block) = 0; - virtual ConcreteCompilerType* getTypeAtBlockEnd(const std::string &name, CFGBlock* block) = 0; - virtual BoxedClass* speculatedExprClass(AST_expr*) = 0; -}; - -//TypeAnalysis* analyze(CFG *cfg, std::unordered_map arg_types); -TypeAnalysis* doTypeAnalysis(CFG *cfg, const std::vector &arg_names, const std::vector &arg_types, TypeAnalysis::SpeculationLevel speculation, ScopeInfo *scope_info); - -} - -#endif diff --git a/src/asm_writing/assembler.cpp b/src/asm_writing/assembler.cpp deleted file mode 100644 index 17b7b2c7e..000000000 --- a/src/asm_writing/assembler.cpp +++ /dev/null @@ -1,813 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/common.h" - -#include "asm_writing/assembler.h" - -namespace pyston { -namespace assembler { - -const char* regnames[] = { - "rax", - "rcx", - "rdx", - "rbx", - "rsp", - "rbp", - "rsi", - "rdi", - "r8", - "r9", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", -}; - -void Register::dump() const { - printf("%s\n", regnames[regnum]); -} - -const int dwarf_to_gp[] = { - // http://www.x86-64.org/documentation/abi.pdf#page=57 - 0, // 0 - 2, // 1 - 1, // 2 -> rcx - 3, // 3 -> rbx - 6, // 4 - 7, // 5 - 5, // 6 -> rbp - 4, // 7 - 8, // 8 -> r8 - 9, // 9 -> r9 - 10, // 10 -> r10 - 11, // 11 -> r11 - 12, // 12 -> r12 - 13, // 13 -> r13 - 14, // 14 -> r14 - 15, // 15 -> r15 - - // Others: - // 16 -> ReturnAddress RA (??) - // 17-32: xmm0-xmm15 -}; - -GenericRegister GenericRegister::fromDwarf(int dwarf_regnum) { - assert(dwarf_regnum >= 0); - - if (dwarf_regnum < 16) { - return GenericRegister(Register(dwarf_to_gp[dwarf_regnum])); - } - - if (17 <= dwarf_regnum && dwarf_regnum <= 32) { - return GenericRegister(XMMRegister(dwarf_regnum - 17)); - } - - abort(); -} - - - -void Assembler::emitArith(Immediate imm, Register r, int opcode) { - //assert(r != RSP && "This breaks unwinding, please don't use."); - - int64_t amount = imm.val; - RELEASE_ASSERT(-0x80 <= amount && amount < 0x80 && "unsupported", ""); - assert(0 <= opcode && opcode < 8); - - int rex = REX_W; - - int reg_idx = r.regnum; - if (reg_idx >= 8) { - rex |= REX_B; - reg_idx -= 8; - } - - emitRex(rex); - emitByte(0x83); - emitModRM(0b11, opcode, reg_idx); - emitByte(amount); -} - - -void Assembler::emitByte(uint8_t b) { - assert(addr < end_addr); - *addr = b; - ++addr; -} - -void Assembler::emitInt(uint64_t n, int bytes) { - assert(bytes > 0 && bytes <= 8); - for (int i = 0; i < bytes; i++) { - emitByte(n & 0xff); - n >>= 8; - } - assert(n == 0); -} - -void Assembler::emitRex(uint8_t rex) { - emitByte(rex | 0x40); -} - -void Assembler::emitModRM(uint8_t mod, uint8_t reg, uint8_t rm) { - assert(mod < 4); - assert(reg < 8); - assert(rm < 8); - emitByte((mod << 6) | (reg << 3) | rm); -} - -void Assembler::emitSIB(uint8_t scalebits, uint8_t index, uint8_t base) { - assert(scalebits < 4); - assert(index < 8); - assert(base < 8); - emitByte((scalebits << 6) | (index << 3) | base); -} - - - - -void Assembler::mov(Immediate val, Register dest) { - int rex = REX_W; - - int dest_idx = dest.regnum; - if (dest_idx >= 8) { - rex |= REX_B; - dest_idx -= 8; - } - - emitRex(rex); - emitByte(0xb8 + dest_idx); - emitInt(val.val, 8); -} - -void Assembler::movq(Immediate src, Indirect dest) { - int64_t src_val = src.val; - assert((-1L<<31) <= src_val && src_val < (1L<<31)-1); - - int rex = REX_W; - - int dest_idx = dest.base.regnum; - - if (dest_idx >= 8) { - rex |= REX_B; - dest_idx -= 8; - } - - emitRex(rex); - emitByte(0xc7); - - bool needssib = (dest_idx == 0b100); - - int mode; - if (dest.offset == 0) - mode = 0b00; - else if (-0x80 <= dest.offset && dest.offset < 0x80) - mode = 0b01; - else - mode = 0b10; - - emitModRM(mode, 0, dest_idx); - - if (needssib) - emitSIB(0b00, 0b100, dest_idx); - - if (mode == 0b01) { - emitByte(dest.offset); - } else if (mode == 0b10) { - emitInt(dest.offset, 4); - } - - emitInt(src_val, 4); -} - -void Assembler::mov(Register src, Register dest) { - ASSERT(src != dest, "probably better to avoid calling this?"); - - int src_idx = src.regnum; - int dest_idx = dest.regnum; - - uint8_t rex = REX_W; - if (dest_idx >= 8) { - rex |= REX_B; - dest_idx -= 8; - } - if (src_idx >= 8) { - rex |= REX_R; - src_idx -= 8; - } - - assert(0 <= src_idx && src_idx < 8); - assert(0 <= dest_idx && dest_idx < 8); - - emitRex(rex); - emitByte(0x89); - emitModRM(0b11, src_idx, dest_idx); -} - -void Assembler::mov(Register src, Indirect dest) { - int rex = REX_W; - - int src_idx = src.regnum; - int dest_idx = dest.base.regnum; - - assert(src_idx != dest_idx && "while valid this is almost certainly a register allocator bug"); - - if (src_idx >= 8) { - rex |= REX_R; - src_idx -= 8; - } - if (dest_idx >= 8) { - rex |= REX_B; - dest_idx -= 8; - } - - emitRex(rex); - emitByte(0x89); - - bool needssib = (dest_idx == 0b100); - - int mode; - if (dest.offset == 0) - mode = 0b00; - else if (-0x80 <= dest.offset && dest.offset < 0x80) - mode = 0b01; - else - mode = 0b10; - - emitModRM(mode, src_idx, dest_idx); - - if (needssib) - emitSIB(0b00, 0b100, dest_idx); - - if (mode == 0b01) { - emitByte(dest.offset); - } else if (mode == 0b10) { - emitInt(dest.offset, 4); - } -} - -void Assembler::mov(Indirect src, Register dest) { - int rex = REX_W; - - int src_idx = src.base.regnum; - int dest_idx = dest.regnum; - - if (src_idx >= 8) { - rex |= REX_B; - src_idx -= 8; - } - if (dest_idx >= 8) { - rex |= REX_R; - dest_idx -= 8; - } - - emitRex(rex); - emitByte(0x8b); // opcode - - bool needssib = (src_idx == 0b100); - - int mode; - if (src.offset == 0) - mode = 0b00; - else if (-0x80 <= src.offset && src.offset < 0x80) - mode = 0b01; - else - mode = 0b10; - - emitModRM(mode, dest_idx, src_idx); - - if (needssib) - emitSIB(0b00, 0b100, src_idx); - - if (mode == 0b01) { - emitByte(src.offset); - } else if (mode == 0b10) { - emitInt(src.offset, 4); - } -} - -void Assembler::movsd(XMMRegister src, XMMRegister dest) { - int rex = 0; - int src_idx = src.regnum; - int dest_idx = dest.regnum; - - if (src_idx >= 8) { - trap(); - rex |= REX_R; - src_idx -= 8; - } - if (dest_idx >= 8) { - trap(); - rex |= REX_B; - dest_idx -= 8; - } - - emitByte(0xf2); - if (rex) - emitRex(rex); - emitByte(0x0f); - emitByte(0x10); - - emitModRM(0b11, src_idx, dest_idx); -} - -void Assembler::movsd(XMMRegister src, Indirect dest) { - int rex = 0; - int src_idx = src.regnum; - int dest_idx = dest.base.regnum; - - if (src_idx >= 8) { - trap(); - rex |= REX_R; - src_idx -= 8; - } - if (dest_idx >= 8) { - trap(); - rex |= REX_B; - dest_idx -= 8; - } - - emitByte(0xf2); - if (rex) - emitRex(rex); - emitByte(0x0f); - emitByte(0x11); - - bool needssib = (dest_idx == 0b100); - - int mode; - if (dest.offset == 0) - mode = 0b00; - else if (-0x80 <= dest.offset && dest.offset < 0x80) - mode = 0b01; - else - mode = 0b10; - - emitModRM(mode, src_idx, dest_idx); - - if (needssib) - emitSIB(0b00, 0b100, dest_idx); - - if (mode == 0b01) { - emitByte(dest.offset); - } else if (mode == 0b10) { - emitInt(dest.offset, 4); - } -} - -void Assembler::movsd(Indirect src, XMMRegister dest) { - int rex = 0; - int src_idx = src.base.regnum; - int dest_idx = dest.regnum; - - if (src_idx >= 8) { - trap(); - rex |= REX_R; - src_idx -= 8; - } - if (dest_idx >= 8) { - trap(); - rex |= REX_B; - dest_idx -= 8; - } - - emitByte(0xf2); - if (rex) - emitRex(rex); - emitByte(0x0f); - emitByte(0x10); - - bool needssib = (src_idx == 0b100); - - int mode; - if (src.offset == 0) - mode = 0b00; - else if (-0x80 <= src.offset && src.offset < 0x80) - mode = 0b01; - else - mode = 0b10; - - emitModRM(mode, dest_idx, src_idx); - - if (needssib) - emitSIB(0b00, 0b100, src_idx); - - if (mode == 0b01) { - emitByte(src.offset); - } else if (mode == 0b10) { - emitInt(src.offset, 4); - } -} - - -void Assembler::push(Register reg) { - //assert(0 && "This breaks unwinding, please don't use."); - - assert(reg != RSP); // this might work but most likely a bug - - int reg_idx = reg.regnum; - if (reg_idx >= 8) { - emitRex(REX_B); - reg_idx -= 8; - } - assert(reg_idx < 8); - - emitByte(0x50 + reg_idx); -} - -void Assembler::pop(Register reg) { - //assert(0 && "This breaks unwinding, please don't use."); - - assert(reg != RSP); // this might work but most likely a bug - - int reg_idx = reg.regnum; - if (reg_idx >= 8) { - emitRex(REX_B); - reg_idx -= 8; - } - assert(reg_idx < 8); - - emitByte(0x58 + reg_idx); -} - - - -void Assembler::add(Immediate imm, Register reg) { - emitArith(imm, reg, OPCODE_ADD); -} - -void Assembler::sub(Immediate imm, Register reg) { - emitArith(imm, reg, OPCODE_SUB); -} - -void Assembler::inc(Register reg) { - UNIMPLEMENTED(); -} - -void Assembler::inc(Indirect mem) { - UNIMPLEMENTED(); -} - - - - -void Assembler::callq(Register r) { - assert(r == R11 && "untested"); - - emitRex(REX_B); - emitByte(0xff); - emitByte(0xd3); -} - - - -void Assembler::cmp(Register reg1, Register reg2) { - int reg1_idx = reg1.regnum; - int reg2_idx = reg2.regnum; - - int rex = REX_W; - if (reg1_idx >= 8) { - rex |= REX_R; - reg1_idx -= 8; - } - if (reg2_idx >= 8) { - trap(); - rex |= REX_B; - reg2_idx -= 8; - } - - assert(reg1_idx >= 0 && reg1_idx < 8); - assert(reg2_idx >= 0 && reg2_idx < 8); - - emitRex(rex); - emitByte(0x39); - emitModRM(0b11, reg1_idx, reg2_idx); -} - -void Assembler::cmp(Register reg, Immediate imm) { - int64_t val = imm.val; - assert((-1L<<31) <= val && val < (1L<<31)-1); - - int reg_idx = reg.regnum; - - int rex = REX_W; - if (reg_idx > 8) { - rex |= REX_B; - reg_idx -= 8; - } - assert(0 <= reg_idx && reg_idx < 8); - - emitRex(rex); - emitByte(0x81); - emitModRM(0b11, 7, reg_idx); - emitInt(val, 4); -} - -void Assembler::cmp(Indirect mem, Immediate imm) { - int64_t val = imm.val; - assert((-1L<<31) <= val && val < (1L<<31)-1); - - int src_idx = mem.base.regnum; - - int rex = REX_W; - if (src_idx >= 8) { - rex |= REX_B; - src_idx -= 8; - } - - assert(src_idx >= 0 && src_idx < 8); - - emitRex(rex); - emitByte(0x81); - - assert(-0x80 <= mem.offset && mem.offset < 0x80); - if (mem.offset == 0) { - emitModRM(0b00, 7, src_idx); - } else { - emitModRM(0b01, 7, src_idx); - emitByte(mem.offset); - } - - emitInt(val, 4); -} - -void Assembler::cmp(Indirect mem, Register reg) { - int mem_idx = mem.base.regnum; - int reg_idx = reg.regnum; - - int rex = REX_W; - if (mem_idx >= 8) { - rex |= REX_B; - mem_idx -= 8; - } - if (reg_idx >= 8) { - rex |= REX_R; - reg_idx -= 8; - } - - assert(mem_idx >= 0 && mem_idx < 8); - assert(reg_idx >= 0 && reg_idx < 8); - - emitRex(rex); - emitByte(0x3B); - - assert(-0x80 <= mem.offset && mem.offset < 0x80); - if (mem.offset == 0) { - emitModRM(0b00, reg_idx, mem_idx); - } else { - emitModRM(0b01, reg_idx, mem_idx); - emitByte(mem.offset); - } -} - -void Assembler::test(Register reg1, Register reg2) { - int reg1_idx = reg1.regnum; - int reg2_idx = reg2.regnum; - - int rex = REX_W; - if (reg1_idx >= 8) { - rex |= REX_R; - reg1_idx -= 8; - } - if (reg2_idx >= 8) { - trap(); - rex |= REX_B; - reg2_idx -= 8; - } - - assert(reg1_idx >= 0 && reg1_idx < 8); - assert(reg2_idx >= 0 && reg2_idx < 8); - - emitRex(rex); - emitByte(0x85); - emitModRM(0b11, reg1_idx, reg2_idx); -} - - - -void Assembler::jmp_cond(JumpDestination dest, ConditionCode condition) { - bool unlikely = false; - - assert(dest.type == JumpDestination::FROM_START); - int offset = dest.offset - (addr - start_addr) - 2; - if (unlikely) offset--; - - if (offset >= -0x80 && offset < 0x80) { - if (unlikely) - emitByte(0x2e); - - emitByte(0x70 | condition); - emitByte(offset); - } else { - offset -= 4; - - if (unlikely) - emitByte(0x2e); - - emitByte(0x0f); - emitByte(0x80 | condition); - emitInt(offset, 4); - } -} - -void Assembler::jmp(JumpDestination dest) { - assert(dest.type == JumpDestination::FROM_START); - int offset = dest.offset - (addr - start_addr) - 2; - - if (offset >= -0x80 && offset < 0x80) { - emitByte(0xeb); - emitByte(offset); - } else { - offset -= 3; - emitByte(0xe9); - emitInt(offset, 4); - } -} - -void Assembler::jne(JumpDestination dest) { - jmp_cond(dest, COND_NOT_EQUAL); -} - -void Assembler::je(JumpDestination dest) { - jmp_cond(dest, COND_EQUAL); -} - - - -void Assembler::set_cond(Register reg, ConditionCode condition) { - int reg_idx = reg.regnum; - - assert(0 <= reg_idx && reg_idx < 8); - - int rex = 0; - // Have to emit a blank REX when accessing RSP/RBP/RDI/RSI, - // since without it this instruction will refer to ah/bh/ch/dh. - if (reg_idx >= 4 || rex) - emitRex(rex); - - emitByte(0x0f); - emitByte(0x90 + condition); - emitModRM(0b11, 0, reg_idx); -} - -void Assembler::sete(Register reg) { - set_cond(reg, COND_EQUAL); -} - -void Assembler::setne(Register reg) { - set_cond(reg, COND_NOT_EQUAL); -} - -uint8_t* Assembler::emitCall(void* ptr, Register scratch) { - mov(Immediate(ptr), scratch); - callq(scratch); - return addr; -} - -void Assembler::emitBatchPush(StackInfo stack_info, const std::vector &to_push) { - assert(stack_info.has_scratch); - int offset = 0; - - for (const GenericRegister &r : to_push) { - assert(stack_info.scratch_bytes >= offset + 8); - Indirect next_slot(RBP, offset + stack_info.scratch_rbp_offset); - - if (r.type == GenericRegister::GP) { - Register gp = r.gp; - assert(gp.regnum >= 0 && gp.regnum < 16); - mov(gp, next_slot); - offset += 8; - } else if (r.type == GenericRegister::XMM) { - XMMRegister reg = r.xmm; - movsd(reg, next_slot); - offset += 8; - } else { - RELEASE_ASSERT(0, "%d", r.type); - } - } -} - -void Assembler::emitBatchPop(StackInfo stack_info, const std::vector &to_push) { - assert(stack_info.has_scratch); - int offset = 0; - - for (const GenericRegister &r : to_push) { - assert(stack_info.scratch_bytes >= offset + 8); - Indirect next_slot(RBP, offset + stack_info.scratch_rbp_offset); - - if (r.type == GenericRegister::GP) { - Register gp = r.gp; - assert(gp.regnum >= 0 && gp.regnum < 16); - mov(next_slot, gp); - offset += 8; - } else if (r.type == GenericRegister::XMM) { - XMMRegister reg = r.xmm; - movsd(next_slot, reg); - offset += 8; - } else { - RELEASE_ASSERT(0, "%d", r.type); - } - } -} - -void Assembler::fillWithNops() { - assert(addr <= end_addr); - memset(addr, 0x90, end_addr - addr); - addr = end_addr; -} - -void Assembler::fillWithNopsExcept(int bytes) { - assert(end_addr - addr >= bytes); - memset(addr, 0x90, end_addr - addr - bytes); - addr = end_addr - bytes; -} - -void Assembler::emitAnnotation(int num) { - nop(); - cmp(RAX, Immediate(num)); - nop(); -} - - - -uint8_t* initializePatchpoint2(uint8_t* start_addr, uint8_t* slowpath_start, uint8_t* end_addr, StackInfo stack_info, const std::unordered_set &live_outs) { - assert(start_addr < slowpath_start); - static const int INITIAL_CALL_SIZE = 13; - assert(end_addr > slowpath_start + INITIAL_CALL_SIZE); -#ifndef NDEBUG - //if (VERBOSITY()) printf("initializing patchpoint at %p - %p\n", addr, addr + size); - //for (int i = 0; i < size; i++) { - //printf("%02x ", *(addr + i)); - //} - //printf("\n"); - - // Check the exact form of the patchpoint call. - // It's important to make sure that the only live registers - // are the ones that are used as arguments; ie it wouldn't - // matter if the call happened on %r10 instead of %r11, - // but it would matter if there wasn't a mov immediately before - // the call, since then %r11 would be live and we couldn't - // use it as a temporary. - - // mov $imm, %r11: - ASSERT(start_addr[0] == 0x49, "%x", start_addr[0]); - assert(start_addr[1] == 0xbb); - // 8 bytes of the addr - - // callq *%r11: - assert(start_addr[10] == 0x41); - assert(start_addr[11] == 0xff); - assert(start_addr[12] == 0xd3); - - int i = INITIAL_CALL_SIZE; - while (*(start_addr + i) == 0x66 || *(start_addr + i) == 0x0f || *(start_addr + i) == 0x2e) - i++; - assert(*(start_addr + i) == 0x90 || *(start_addr + i) == 0x1f); -#endif - - void* call_addr = *(void**)&start_addr[2]; - - Assembler(start_addr, slowpath_start - start_addr).fillWithNops(); - - std::vector regs_to_spill; - for (int dwarf_regnum : live_outs) { - GenericRegister ru = GenericRegister::fromDwarf(dwarf_regnum); - - if (ru.type == GenericRegister::GP) { - if (ru.gp == RSP || ru.gp.isCalleeSave()) - continue; - } - - regs_to_spill.push_back(ru); - } - - Assembler assem(slowpath_start, end_addr - slowpath_start); - - //if (regs_to_spill.size()) - //assem.trap(); - assem.emitBatchPush(stack_info, regs_to_spill); - uint8_t* rtn = assem.emitCall(call_addr, R11); - assem.emitBatchPop(stack_info, regs_to_spill); - assem.fillWithNops(); - - return rtn; -} - -} -} diff --git a/src/asm_writing/assembler.h b/src/asm_writing/assembler.h deleted file mode 100644 index d1d661b72..000000000 --- a/src/asm_writing/assembler.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_ASSEMBLER_H -#define PYSTON_ASMWRITING_ASSEMBLER_H - -#include - -#include "core/ast.h" - -#include "asm_writing/types.h" - -namespace pyston { -namespace assembler { - -class BoxedClass; - -enum ConditionCode { - COND_OVERFLOW = 0, // OF=1: O - COND_NOT_OVERFLOW = 1, // OF=0: NO - // next 4 are unsigned: - COND_BELOW = 2, // CF=1: B/NAE/C - COND_NOT_BELOW = 3, // CF=0: NB/AE/C - COND_EQUAL = 4, // ZF=0: Z/E - COND_NOT_EQUAL = 5, // ZF=1: NZ/NE - COND_NOT_ZERO = 5, // ZF=1: NZ/NE - COND_NOT_ABOVE = 6, // CF=1: ZF=1: BE/NA - COND_ABOVE = 7, // CF=0: ZF=0: NBE/A - COND_SIGN = 8, // SF=1: S - COND_NOT_SIGN = 9, // SF=0: NS - COND_PARITY_EVEN = 0xA, // PF=1: P/PE - COND_PARITY_ODD = 0xB, // PF=0: NP/PO - // next 4 are signed: - COND_LESS = 0xC, // SF!=OF: L/NGE - COND_NOT_LESS = 0xD, // SF==OF: NL/GE - COND_NOT_GREATER = 0xE, // ZF=1 || SF!=OF: LE/NG - COND_GREATER = 0xF, // ZF=0 && SF==OF: NLE/G -}; - -class Assembler { - private: - uint8_t *const start_addr, *const end_addr; - uint8_t *addr; - - static const uint8_t OPCODE_ADD = 0b000, OPCODE_SUB = 0b101; - static const uint8_t REX_B = 1, REX_X = 2, REX_R = 4, REX_W = 8; - private: - void emitByte(uint8_t b); - void emitInt(uint64_t n, int bytes); - void emitRex(uint8_t rex); - void emitModRM(uint8_t mod, uint8_t reg, uint8_t rm); - void emitSIB(uint8_t scalebits, uint8_t index, uint8_t base); - void emitArith(Immediate imm, Register reg, int opcode); - - public: - Assembler(uint8_t* start, int size) : start_addr(start), end_addr(start + size), addr(start_addr) {} - - void nop() { emitByte(0x90); } - void trap() { emitByte(0xcc); } - - // some things (such as objdump) call this "movabs" if the immediate is 64-bit - void mov(Immediate imm, Register dest); - // not sure if we should use the 'q' suffix here, but this is the most ambiguous one; - // this does a 64-bit store of a 32-bit value. - void movq(Immediate imm, Indirect dest); - void mov(Register src, Register dest); - void mov(Register src, Indirect dest); - void mov(Indirect src, Register dest); - void movsd(XMMRegister src, XMMRegister dest); - void movsd(XMMRegister src, Indirect dest); - void movsd(Indirect src, XMMRegister dest); - - void push(Register reg); - void pop(Register reg); - - void add(Immediate imm, Register reg); - void sub(Immediate imm, Register reg); - void inc(Register reg); - void inc(Indirect mem); - - void callq(Register reg); - - void cmp(Register reg1, Register reg2); - void cmp(Register reg, Immediate imm); - void cmp(Indirect mem, Immediate imm); - void cmp(Indirect mem, Register reg); - - void test(Register reg1, Register reg2); - - void jmp_cond(JumpDestination dest, ConditionCode condition); - void jmp(JumpDestination dest); - void je(JumpDestination dest); - void jne(JumpDestination dest); - - void set_cond(Register reg, ConditionCode condition); - void sete(Register reg); - void setz(Register reg) { sete(reg); } - void setne(Register reg); - void setnz(Register reg) { setne(reg); } - - - // Macros: - uint8_t* emitCall(void* func_addr, Register scratch); - void emitBatchPop(StackInfo stack_info, const std::vector &to_push); - void emitBatchPush(StackInfo stack_info, const std::vector &to_push); - void fillWithNops(); - void fillWithNopsExcept(int bytes); - void emitAnnotation(int num); - - bool isExactlyFull() { return addr == end_addr; } -}; - -uint8_t* initializePatchpoint2(uint8_t* start_addr, uint8_t* slowpath_start, uint8_t* end_addr, StackInfo stack_info, const std::unordered_set &live_outs); - -} -} - -#endif diff --git a/src/asm_writing/icinfo.cpp b/src/asm_writing/icinfo.cpp deleted file mode 100644 index 0f91e1b1c..000000000 --- a/src/asm_writing/icinfo.cpp +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/Support/Memory.h" - -#include "codegen/patchpoints.h" - -#include "core/common.h" -#include "core/options.h" -#include "core/types.h" - -#include "asm_writing/assembler.h" -#include "asm_writing/icinfo.h" -#include "asm_writing/mc_writer.h" - -namespace pyston { - -using namespace pyston::assembler; - -// TODO not right place for this... -int64_t ICInvalidator::version() { - return cur_version; -} - -void ICInvalidator::addDependent(ICSlotInfo* entry_info) { - dependents.insert(entry_info); -} - -void ICInvalidator::invalidateAll() { - cur_version++; - for (std::unordered_set::iterator it = dependents.begin(), end = dependents.end(); - it != end; ++it) { - (*it)->clear(); - } - dependents.clear(); -} - - - -void ICSlotInfo::clear() { - ic->clear(this); -} - -ICSlotRewrite::ICSlotRewrite(ICInfo* ic, const char* debug_name) : ic(ic), debug_name(debug_name) { - buf = (uint8_t*)malloc(ic->getSlotSize()); - assembler = new Assembler(buf, ic->getSlotSize()); - assembler->nop(); - - if (VERBOSITY()) printf("starting %s icentry\n", debug_name); -} - -ICSlotRewrite::~ICSlotRewrite() { - delete assembler; - free(buf); -} - -void ICSlotRewrite::commit(uint64_t decision_path, CommitHook *hook) { - bool still_valid = true; - for (int i = 0; i < dependencies.size(); i++) { - int orig_version = dependencies[i].second; - ICInvalidator *invalidator = dependencies[i].first; - if (orig_version != invalidator->version()) { - still_valid = false; - break; - } - } - if (!still_valid) { - if (VERBOSITY()) printf("not committing %s icentry since a dependency got updated before commit\n", debug_name); - return; - } - - ICSlotInfo *ic_entry = ic->pickEntryForRewrite(decision_path, debug_name); - if (ic_entry == NULL) - return; - - for (int i = 0; i < dependencies.size(); i++) { - ICInvalidator *invalidator = dependencies[i].first; - invalidator->addDependent(ic_entry); - } - - uint8_t* slot_start = (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize(); - uint8_t* continue_point = (uint8_t*)ic->continue_addr; - - hook->finishAssembly(continue_point - slot_start); - - assert(assembler->isExactlyFull()); - - //if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size); - memcpy(slot_start, buf, ic->getSlotSize()); - - llvm::sys::Memory::InvalidateInstructionCache(slot_start, ic->getSlotSize()); -} - -void ICSlotRewrite::addDependenceOn(ICInvalidator &invalidator) { - dependencies.push_back(std::make_pair(&invalidator, invalidator.version())); -} - -int ICSlotRewrite::getSlotSize() { - return ic->getSlotSize(); -} - -int ICSlotRewrite::getFuncStackSize() { - return ic->stack_info.stack_size; -} - -int ICSlotRewrite::getScratchRbpOffset() { - assert(ic->stack_info.has_scratch); - assert(ic->stack_info.scratch_bytes); - return ic->stack_info.scratch_rbp_offset; -} - -int ICSlotRewrite::getScratchBytes() { - assert(ic->stack_info.has_scratch); - assert(ic->stack_info.scratch_bytes); - return ic->stack_info.scratch_bytes; -} - -assembler::GenericRegister ICSlotRewrite::returnRegister() { - return ic->return_register; -} - - - -ICSlotRewrite* ICInfo::startRewrite(const char* debug_name) { - return new ICSlotRewrite(this, debug_name); -} - -ICSlotInfo* ICInfo::pickEntryForRewrite(uint64_t decision_path, const char* debug_name) { - for (int i = 0; i < getNumSlots(); i++) { - SlotInfo &sinfo = slots[i]; - if (!sinfo.is_patched) { - if (VERBOSITY()) { - printf("committing %s icentry to unused slot %d at %p\n", debug_name, i, start_addr); - } - - sinfo.is_patched = true; - sinfo.decision_path = decision_path; - return &sinfo.entry; - } - } - - for (int i = 0; i < getNumSlots(); i++) { - SlotInfo &sinfo = slots[i]; - if (sinfo.is_patched && sinfo.decision_path != decision_path) { - continue; - } - - if (VERBOSITY()) { - printf("committing %s icentry to in-use slot %d at %p\n", debug_name, i, start_addr); - } - - sinfo.is_patched = true; - sinfo.decision_path = decision_path; - return &sinfo.entry; - } - if (VERBOSITY()) printf("not committing %s icentry since it is not compatible (%lx)\n", debug_name, decision_path); - return NULL; -} - - - -ICInfo::ICInfo(void* start_addr, void* continue_addr, StackInfo stack_info, int num_slots, int slot_size, llvm::CallingConv::ID calling_conv, const std::unordered_set &live_outs, assembler::GenericRegister return_register) : stack_info(stack_info), num_slots(num_slots), slot_size(slot_size), calling_conv(calling_conv), live_outs(live_outs.begin(), live_outs.end()), return_register(return_register), start_addr(start_addr), continue_addr(continue_addr) { - for (int i = 0; i < num_slots; i++) { - slots.push_back(SlotInfo(this, i)); - } -} - -static std::unordered_map ics_by_return_addr; -void registerCompiledPatchpoint(uint8_t* start_addr, PatchpointSetupInfo* pp, StackInfo stack_info, std::unordered_set live_outs) { - int size = pp->totalSize(); - uint8_t* end_addr = start_addr + size; - void* slowpath_addr = end_addr; - - uint8_t* rtn_addr; - - assembler::GenericRegister return_register; - assert(pp->getCallingConvention() == llvm::CallingConv::C || pp->getCallingConvention() == llvm::CallingConv::PreserveAll); - if (pp->hasReturnValue()) { - static const int DWARF_RAX = 0; - // It's possible that the return value doesn't get used, in which case - // we can avoid copying back into RAX at the end - if (live_outs.count(DWARF_RAX)) { - live_outs.erase(DWARF_RAX); - } - - // TODO we only need to do this if 0 was in live_outs, since if it wasn't, that indicates - // the return value won't be used and we can optimize based on that. - return_register = assembler::RAX; - } - - if (pp->getCallingConvention() != llvm::CallingConv::C) { - uint8_t* slowpath_start = start_addr + pp->num_slots * pp->slot_size; - rtn_addr = initializePatchpoint2(start_addr, slowpath_start, (uint8_t*)end_addr, stack_info, live_outs); - } else { - //for (int regnum : live_outs) { - //// LLVM has a bug where it incorrectly determines the set of liveouts; - //// so far it only seems to add additional ones to the set, which should - //// hopefully be safe. - //// Otherwise, I'd like to test here that it's only the registers - //// that we'd expect to be saved... - //ASSERT(regnum == 0 || regnum == 3 || regnum == 6 || regnum == 12 || regnum == 13 || regnum == 14 || regnum == 15 || regnum == 7, "%d", regnum); - //} - - initializePatchpoint(start_addr, size); - rtn_addr = end_addr; - } - - // we can let the user just slide down the nop section, but instead - // emit jumps to the end. - // Not sure if this is worth it or not? - for (int i = 0; i < pp->num_slots; i++) { - uint8_t* start = start_addr + i * pp->slot_size; - //std::unique_ptr writer(createMCWriter(start, pp->slot_size * (pp->num_slots - i), 0)); - //writer->emitNop(); - //writer->emitGuardFalse(); - - std::unique_ptr writer(new Assembler(start, pp->slot_size)); - writer->nop(); - //writer->trap(); - writer->jmp(JumpDestination::fromStart(pp->slot_size * (pp->num_slots - i))); - } - - ics_by_return_addr[rtn_addr] = new ICInfo(start_addr, end_addr, stack_info, pp->num_slots, pp->slot_size, pp->getCallingConvention(), live_outs, return_register); -} - -ICInfo* getICInfo(void* rtn_addr) { - std::unordered_map::iterator it = ics_by_return_addr.find(rtn_addr); - if (it == ics_by_return_addr.end()) - return NULL; - return it->second; -} - -void ICInfo::clear(ICSlotInfo* icentry) { - assert(icentry); - - uint8_t* start = (uint8_t*)start_addr + icentry->idx * getSlotSize(); - - if (VERBOSITY()) printf("clearing patchpoint %p, slot at %p\n", start_addr, start); - - std::unique_ptr writer(new Assembler(start, getSlotSize())); - writer->nop(); - writer->jmp(JumpDestination::fromStart(getSlotSize())); - //std::unique_ptr writer(createMCWriter(start, getSlotSize(), 0)); - //writer->emitNop(); - //writer->emitGuardFalse(); - - //writer->endWithSlowpath(); - llvm::sys::Memory::InvalidateInstructionCache(start, getSlotSize()); -} - -} diff --git a/src/asm_writing/icinfo.h b/src/asm_writing/icinfo.h deleted file mode 100644 index 7ebd1d94d..000000000 --- a/src/asm_writing/icinfo.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_ICINFO_H -#define PYSTON_ASMWRITING_ICINFO_H - -#include -#include - -#include "llvm/IR/CallingConv.h" - -#include "asm_writing/types.h" - -namespace pyston { - -class ICInfo; -class ICInvalidator; - -struct ICSlotInfo { - public: - ICSlotInfo(ICInfo* ic, int idx) : ic(ic), idx(idx) {} - - ICInfo *ic; - int idx; - - void clear(); -}; - -class ICSlotRewrite { - public: - class CommitHook { - public: - virtual void finishAssembly(int fastpath_offset) = 0; - }; - private: - ICInfo* ic; - assembler::Assembler* assembler; - const char* debug_name; - - uint8_t *buf; - - std::vector > dependencies; - - ICSlotRewrite(ICInfo* ic, const char* debug_name); - - public: - ~ICSlotRewrite(); - - assembler::Assembler* getAssembler() { return assembler; } - int getSlotSize(); - int getFuncStackSize(); - int getScratchRbpOffset(); - int getScratchBytes(); - - assembler::GenericRegister returnRegister(); - - void addDependenceOn(ICInvalidator&); - void commit(uint64_t decision_path, CommitHook *hook); - - friend class ICInfo; -}; - -class ICInfo { - private: - struct SlotInfo { - bool is_patched; - uint64_t decision_path; - ICSlotInfo entry; - - SlotInfo(ICInfo* ic, int idx) : is_patched(false), decision_path(0), entry(ic, idx) {} - }; - std::vector slots; - - const StackInfo stack_info; - const int num_slots; - const int slot_size; - const llvm::CallingConv::ID calling_conv; - const std::vector live_outs; - const assembler::GenericRegister return_register; - - // for ICSlotRewrite: - ICSlotInfo *pickEntryForRewrite(uint64_t decision_path, const char* debug_name); - - void* getSlowpathStart(); - - public: - ICInfo(void* start_addr, void* continue_addr, StackInfo stack_info, int num_slots, int slot_size, llvm::CallingConv::ID calling_conv, const std::unordered_set &live_outs, assembler::GenericRegister return_register); - void *const start_addr, *const continue_addr; - - int getSlotSize() { return slot_size; } - int getNumSlots() { return num_slots; } - llvm::CallingConv::ID getCallingConvention() { return calling_conv; } - const std::vector& getLiveOuts() { return live_outs; } - - ICSlotRewrite* startRewrite(const char* debug_name); - void clear(ICSlotInfo *entry); - - friend class ICSlotRewrite; -}; - -class PatchpointSetupInfo; -void registerCompiledPatchpoint(uint8_t* start_addr, PatchpointSetupInfo*, StackInfo stack_info, std::unordered_set live_outs); - -ICInfo* getICInfo(void* rtn_addr); - - -} - -#endif diff --git a/src/asm_writing/mc_writer.cpp b/src/asm_writing/mc_writer.cpp deleted file mode 100644 index e385821af..000000000 --- a/src/asm_writing/mc_writer.cpp +++ /dev/null @@ -1,898 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/common.h" -#include "core/options.h" - -#include "core/ast.h" - -#include "asm_writing/mc_writer.h" - -namespace pyston { - -#if !1 -#define POINTER_SIZE 8 - -namespace X86 { - const char* regnames[] = { - "rax", - "rcx", - "rdx", - "rbx", - "rsp", - "rbp", - "rsi", - "rdi", - "r8", - "r9", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - }; - - const bool is_callee_save[] = { - false, - true, // %rbx - false, - false, - false, - true, // %rbp - false, - false, - - false, - false, - false, - false, - true, - true, - true, - true, - }; - - const int DwarfRegToX86[] = { - 0, // 0 - 2, // 1 - 1, // 2 -> rcx - 3, // 3 -> rbx - 6, // 4 - 7, // 5 - 5, // 6 - 4, // 7 - 8, // 8 -> r8 - 9, // 9 -> r9 - 10, // 10 -> r10 - 11, // 11 -> r11 - 12, // 12 -> r12 - 13, // 13 -> r13 - 14, // 14 -> r14 - 15, // 15 -> r15 - - // http://www.x86-64.org/documentation/abi.pdf#page=57 - // 16 -> ReturnAddress RA (??) - // 17-32: xmm0-xmm15 - }; - - const int NUM_ARG_REGS = 6; - const int arg_regs[] = { - 7, // rdi - 6, // rsi - 2, // rdx - 1, // rcx - 8, // r8 - 9, // r9 - }; - - const uint8_t REX_B = 1, REX_X = 2, REX_R = 4, REX_W = 8; - - const int REG_RTN = 0; - const int REG_STACK_POINTER = 4; - //enum RexFlags { - //REX_B = 1, REX_X = 2, REX_R = 4, REX_W = 8 - //}; - - const int BYTES_PER_POP = 1; - - // Any time we emit a call, make sure that we align the stack to a multiple of this. - // Required to be a multiple of 16 to support SSE: - const int CALL_STACK_ALIGNMENT = 16; - // The consequence is we need a multiple of this many pushes: - const int PUSH_MULT = CALL_STACK_ALIGNMENT / POINTER_SIZE; - - enum ConditionCode { - COND_OVERFLOW = 0, // OF=1: O - COND_NOT_OVERFLOW = 1, // OF=0: NO - // next 4 are unsigned: - COND_BELOW = 2, // CF=1: B/NAE/C - COND_NOT_BELOW = 3, // CF=0: NB/AE/C - COND_EQUAL = 4, // ZF=0: Z/E - COND_NOT_EQUAL = 5, // ZF=1: NZ/NE - COND_NOT_ZERO = 5, // ZF=1: NZ/NE - COND_NOT_ABOVE = 6, // CF=1: ZF=1: BE/NA - COND_ABOVE = 7, // CF=0: ZF=0: NBE/A - COND_SIGN = 8, // SF=1: S - COND_NOT_SIGN = 9, // SF=0: NS - COND_PARITY_EVEN = 0xA, // PF=1: P/PE - COND_PARITY_ODD = 0xB, // PF=0: NP/PO - // next 4 are signed: - COND_LESS = 0xC, // SF!=OF: L/NGE - COND_NOT_LESS = 0xD, // SF==OF: NL/GE - COND_NOT_GREATER = 0xE, // ZF=1 || SF!=OF: LE/NG - COND_GREATER = 0xF, // ZF=0 && SF==OF: NLE/G - }; - - const int OPCODE_ADD = 0b000, OPCODE_SUB = 0b101; -} - -#define CALL_SIZE 13 - -class X86MCWriter : public MCWriter { - private: - uint8_t* addr; - uint8_t *const start_addr, *const end_addr; - int pops_required; - - inline void _emitByte(uint8_t b) { - if (TRAP) { - printf(" %02x", b); - fflush(stdout); - } - assert(addr < end_addr); - *addr++ = b; - } - - inline void _emitRex(uint8_t flags) { - assert(0 <= flags && flags < 16); - _emitByte(0x40 | flags); - } - - inline void _emitModRM(uint8_t mod, uint8_t reg, uint8_t rm) { - assert(mod < 4); - assert(reg < 8); - assert(rm < 8); - _emitByte((mod << 6) | (reg << 3) | rm); - } - - inline void _emitSIB(uint8_t scalebits, uint8_t index, uint8_t base) { - assert(scalebits < 4); - assert(index < 8); - assert(base < 8); - _emitByte((scalebits << 6) | (index << 3) | base); - } - - inline void _emitPush(uint8_t reg) { - assert(reg != X86::REG_STACK_POINTER); // this might work but most likely a bug - assert(0 <= reg && reg < 16); - - if (reg >= 8) { - _emitRex(X86::REX_B); - reg -= 8; - } - assert(reg < 8); - _emitByte(0x50 + reg); - } - - inline void _emitPop(uint8_t reg) { - assert(reg != X86::REG_STACK_POINTER); // this might work but most likely a bug - assert(0 <= reg && reg < 16); - - if (reg >= 8) { - _emitRex(X86::REX_B); - reg -= 8; - } - assert(reg < 8); - _emitByte(0x58 + reg); - } - - /// mov %source, $displacement(%dest) - inline void _emitStoreRegIndirect(int source, int dest, int displacement) { - bool usesib = false; - if (dest == 0b100 || dest == 0b1100) { - usesib = true; - } - - uint8_t flags = X86::REX_W; - if (dest >= 8) { - flags |= X86::REX_B; - dest &= 0b111; - } - if (source >= 8) { - flags |= X86::REX_R; - source &= 0b111; - } - - _emitRex(flags); - _emitByte(0x89); - - int mode; - if (displacement == 0) - mode = 0b00; - else if (-0x80 <= displacement && displacement < 0x79) - mode = 0b01; - else - mode = 0b10; - - _emitModRM(mode, source, dest); - if (usesib) - _emitSIB(0b00, 0b100, dest); - if (mode == 0b01) { - _emitByte(displacement); - } else if (mode == 0b10) { - for (int i = 0; i < 4; i++) { - _emitByte(displacement & 0xff); - displacement >>= 8; - } - } - } - - // incq offset(%reg) - virtual void _emitIncattr(int reg, int offset) { - assert(offset >= -0x80 && offset < 0x80); - - int rex = X86::REX_W; - if (reg >= 8) { - rex |= X86::REX_B; - reg -= 8; - } - - _emitRex(rex); - _emitByte(0xff); - _emitModRM(0b01, 0b000, reg); - _emitByte(offset); - } - - /// mov $displacement(%source) %dest - inline void _emitLoadRegIndirect(int source, int displacement, int dest) { - bool usesib = false; - if (source == 0b100 || dest == 0b1100) { - usesib = true; - } - - uint8_t flags = X86::REX_W; - if (dest >= 8) { - flags |= X86::REX_R; - dest &= 0b111; - } - if (source >= 8) { - flags |= X86::REX_B; - source &= 0b111; - } - - _emitRex(flags); - _emitByte(0x8b); - - int mode; - if (displacement == 0) - mode = 0b00; - else if (-0x80 <= displacement && displacement < 0x79) - mode = 0b01; - else - mode = 0b10; - - _emitModRM(mode, dest, source); - if (usesib) - _emitSIB(0b00, 0b100, source); - - if (mode == 0b01) { - _emitByte(displacement); - } else if (mode == 0b10) { - for (int i = 0; i < 4; i++) { - _emitByte(displacement & 0xff); - displacement >>= 8; - } - } - } - - inline void _emitMoveReg(int source, int dest) { - uint8_t flags = 0; - flags |= X86::REX_W; - if (dest >= 8) { - flags |= X86::REX_B; - dest &= 0b111; - } - if (source >= 8) { - flags |= X86::REX_R; - source &= 0b111; - } - - _emitRex(flags); - _emitByte(0x89); - _emitModRM(0b11, source, dest); - } - - inline void _emitMoveImm64(uint8_t reg, uint64_t value) { - assert(reg >= 0 && reg < 8); - _emitRex(X86::REX_W); - _emitByte(0xb8 + reg); - - for (int i = 0; i < 8; i++) { - _emitByte(value & 0xff); - value >>= 8; - } - } - - // TODO verify that the arguments are being compared in the right order - // cmpq %reg1, %reg2 # or maybe they're reversed? - inline void _emitCmp(int reg1, int reg2) { - int rex = X86::REX_W; - if (reg1 >= 8) { - rex |= X86::REX_R; - reg1 -= 8; - } - - assert(reg1 >= 0 && reg1 < 8); - assert(reg2 >= 0 && reg2 < 8); - - _emitRex(rex); - _emitByte(0x39); - _emitModRM(0b11, reg1, reg2); - } - - // TODO verify that the arguments are being compared in the right order - // cmp $val, %reg - inline void _emitCmpImm(int reg, int64_t val) { - assert((-1L<<31) <= val && val < (1L<<31)-1); - - int rex = X86::REX_W; - if (reg > 8) { - rex |= X86::REX_B; - reg -= 8; - } - assert(0 <= reg && reg < 8); - - _emitRex(rex); - _emitByte(0x81); - _emitModRM(0b11, 7, reg); - for (int i = 0; i < 4; i++) { - _emitByte(val & 0xff); - val >>= 8; - } - } - - // TODO verify that the arguments are being compared in the right order - // cmpq offset(%reg1), %reg2 - inline void _emitAttrCmp(int reg1, int reg1_offset, int reg2) { - int rex = X86::REX_W; - if (reg1 >= 8) { - rex |= X86::REX_B; - reg1 -= 8; - } - - assert(reg1 >= 0 && reg1 < 8); - assert(reg2 >= 0 && reg2 < 8); - - _emitRex(rex); - _emitByte(0x3B); - - assert(-0x80 <= reg1_offset && reg1_offset < 0x80); - if (reg1_offset == 0) { - _emitModRM(0b00, reg2, reg1); - } else { - _emitModRM(0b01, reg2, reg1); - _emitByte(reg1_offset); - } - } - - // TODO verify that the arguments are being compared in the right order - // cmpq offset(%reg), $imm - inline void _emitAttrCmpImm(int reg, int offset, int64_t val) { - assert((-1L<<31) <= val && val < (1L<<31)-1); - - int rex = X86::REX_W; - if (reg >= 8) { - rex |= X86::REX_B; - reg -= 8; - } - - assert(reg >= 0 && reg < 8); - - _emitRex(rex); - _emitByte(0x81); - - assert(-0x80 <= offset && offset < 0x80); - if (offset == 0) { - _emitModRM(0b00, 7, reg); - } else { - _emitModRM(0b01, 7, reg); - _emitByte(offset); - } - - for (int i = 0; i < 4; i++) { - _emitByte(val & 0xff); - val >>= 8; - } - } - - // test[q] %reg1, %reg2 - inline void _emitTest(int reg1, int reg2) { - assert(reg1 >= 0 && reg1 < 8); - assert(reg2 >= 0 && reg2 < 8); - - _emitRex(X86::REX_W); - _emitByte(0x85); - _emitModRM(0b11, reg1, reg2); - } - - inline void _emitCmpDisplacement(uint8_t reg1, uint64_t reg2, int displacement) { - // TODO if it's bigger, we could use a larger scale since - // things are most likely aligned - assert(displacement >= -0x80 && displacement < 0x80); - - uint8_t flags = 0; - flags |= X86::REX_W; - - if (reg1 >= 8) { - flags |= X86::REX_R; - reg1 &= 0b111; - } - if (reg2 >= 8) { - flags |= X86::REX_B; - reg2 &= 0b111; - } - - _emitRex(flags); - _emitByte(0x39); - if (displacement == 0) { - // Since we're emitting into a fixed-size section I guess there might not be - // too much benifit to the more compact encoding, but it makes me feel better: - _emitModRM(0b00, reg1, reg2); - } else { - _emitModRM(0b01, reg1, reg2); - _emitByte(displacement); - } - } - - inline void _emitJmpCond(uint8_t* dest_addr, X86::ConditionCode condition, bool unlikely) { - int offset = dest_addr - addr - 2; - if (unlikely) offset -= 1; - - if (offset >= -0x80 && offset < 0x80) { - if (unlikely) - _emitByte(0x2e); - _emitByte(0x75); - _emitByte(offset); - } else { - offset -= 4; - - if (unlikely) - _emitByte(0x2e); - - _emitByte(0x0f); - _emitByte(0x80 | condition); - for (int i = 0; i < 4; i++) { - _emitByte(offset & 0xff); - offset >>= 8; - } - } - } - - inline void _emitJne(uint8_t* dest_addr, bool unlikely) { - _emitJmpCond(dest_addr, X86::COND_NOT_EQUAL, unlikely); - int offset = dest_addr - addr - 2; - if (unlikely) offset -= 1; - - if (offset >= -0x80 && offset < 0x80) { - if (unlikely) - _emitByte(0x2e); - _emitByte(0x75); - _emitByte(offset); - } else { - offset -= 4; - - if (unlikely) - _emitByte(0x2e); - - _emitByte(0x0f); - _emitByte(0x85); - for (int i = 0; i < 4; i++) { - _emitByte(offset & 0xff); - offset >>= 8; - } - } - } - - /// "op $val, %reg" - inline void _emitArith(int reg, int val, int opcode) { - assert(val >= -0x80 && val < 0x80); - assert(opcode < 8); - - uint8_t flags = 0; - flags |= X86::REX_W; - - if (reg >= 8) { - flags |= X86::REX_B; - reg &= 0b111; - } - - _emitRex(flags); - _emitByte(0x83); - _emitModRM(0b11, opcode, reg); - _emitByte(val); - } - - /// "add $val, %reg" - inline void _emitAdd(int reg, int val) { - _emitArith(reg, val, X86::OPCODE_ADD); - } - - /// "sub %val, %reg" - inline void _emitSub(int reg, int val) { - _emitArith(reg, val, X86::OPCODE_SUB); - } - - int convertArgnum(int argnum) { - ASSERT(argnum >= -3 && argnum < X86::NUM_ARG_REGS, "%d", argnum); - if (argnum == -1) - return X86::REG_RTN; - else if (argnum == -2) - return 10; - else if (argnum == -3) - return 11; - else - return X86::arg_regs[argnum]; - } - - void _emitJmp(void* dest_addr) { - long offset = (uint8_t*)dest_addr - addr - 2; - if (offset >= -0x80 && offset < 0x80) { - _emitByte(0xeb); - _emitByte(offset); - } else { - assert(offset >= -1L<<31 && offset < 1L<<31); - - offset -= 3; - _emitByte(0xe9); - for (int i = 0; i < 4; i++) { - _emitByte(offset & 0xff); - offset >>= 8; - } - } - } - - void _emitCondSet(int dest_reg, int cond_code) { - assert(0 <= dest_reg && dest_reg < 8); - assert(0 <= cond_code && cond_code < 16); - - if (dest_reg >= 4) - _emitRex(0); - _emitByte(0x0f); - _emitByte(0x90 + cond_code); - _emitModRM(0b11, 0, dest_reg); - } - - // movzbq %src_reg, %dest_reg - void _emitZeroExtend(int src_reg, int dest_reg) { - assert(0 <= src_reg && src_reg < 8); - assert(0 <= dest_reg && dest_reg < 8); - - _emitRex(X86::REX_W); - _emitByte(0x0f); - _emitByte(0xb6); - _emitModRM(0b11, dest_reg, src_reg); - } - - virtual void _emitGuard(int argnum, int64_t value, int npops, X86::ConditionCode slowpath_condition) { - assert(slowpath_condition == X86::COND_EQUAL || slowpath_condition == X86::COND_NOT_EQUAL && "not sure if the cmp operands are in the right order"); - - assert(argnum <= X86::NUM_ARG_REGS); - int argreg = convertArgnum(argnum); - - if (value < (-1l << 31) || value >= (1l << 31)) { - //assert(0 && "can use r10 or r11"); - int cmpreg = 5; - assert(argreg != cmpreg); - - _emitPush(cmpreg); - _emitMoveImm64(cmpreg, value); - _emitCmp(argreg, cmpreg); - _emitPop(cmpreg); - } else { - _emitCmpImm(argreg, value); - } - - this->pops_required = std::max(this->pops_required, npops); - _emitJmpCond(end_addr - X86::BYTES_PER_POP * npops, slowpath_condition, true); - } - - virtual void _emitAttrGuard(int argnum, int offset, int64_t value, int npops, X86::ConditionCode slowpath_condition) { - assert(slowpath_condition == X86::COND_EQUAL || slowpath_condition == X86::COND_NOT_EQUAL && "not sure if the cmp operands are in the right order"); - - assert(argnum <= X86::NUM_ARG_REGS); - int argreg = convertArgnum(argnum); - - if (value < (-1l << 31) || value >= (1l << 31)) { - //assert(0 && "can use r10 or r11"); - int cmpreg = 5; - assert(argreg != cmpreg); - - _emitPush(cmpreg); - _emitMoveImm64(cmpreg, value); - _emitAttrCmp(argreg, offset, cmpreg); - _emitPop(cmpreg); - } else { - _emitAttrCmpImm(argreg, offset, value); - } - - this->pops_required = std::max(this->pops_required, npops); - _emitJmpCond(end_addr - X86::BYTES_PER_POP * npops, slowpath_condition, true); - } - - public: - X86MCWriter(uint8_t* addr, int size) : addr(addr), start_addr(addr), end_addr(addr+size), pops_required(0) { - } - - virtual int numArgRegs() { - return X86::NUM_ARG_REGS; - } - - virtual int numTempRegs() { - return 2; - } - - virtual void emitNop() { - _emitByte(0x90); - } - - virtual void emitTrap() { - _emitByte(0xcc); - } - - virtual void emitAnnotation(int num) { - emitNop(); - _emitCmpImm(0, num); - emitNop(); - //_emitAdd(0, num); - //_emitSub(0, num); - } - - // TODO this is unclear - virtual void endFastPath(void* success_dest, void* will_relocate_to) { - void* dest = ((uint8_t*)success_dest - (uint8_t*)will_relocate_to) + start_addr; - _emitJmp(dest); - } - - // TODO this is unclear - virtual void endWithSlowpath() { - int pop_bytes = pops_required * X86::BYTES_PER_POP; - uint8_t* pop_start = end_addr - pop_bytes; - - //printf("end addr is %p; pop_start is %p for %d pops\n", end_addr, pop_start, pops_required); - - assert(addr <= pop_start); - memset(addr, 0x90, pop_start - addr); - addr = pop_start; - - // We don't havy any result to return, so clobber %rax: - const int POP_REG = 0; // %rax - assert(!X86::is_callee_save[POP_REG]); - for (int i = 0; i < pops_required; i++) { - _emitPop(POP_REG); - } - assert(addr == end_addr); - - addr = NULL; - } - - virtual void emitGuard(int argnum, int64_t value, int npops) { - _emitGuard(argnum, value, npops, X86::COND_NOT_EQUAL); - } - - virtual void emitAttrGuard(int argnum, int offset, int64_t value, int npops) { - _emitAttrGuard(argnum, offset, value, npops, X86::COND_NOT_EQUAL); - } - - virtual void emitGuardFalse() { - _emitJmp(end_addr); - } - - virtual void emitGuardNotEq(int argnum, int64_t value, int npops) { - _emitGuard(argnum, value, npops, X86::COND_EQUAL); - } - - virtual uint8_t* emitCall(void* new_addr, int npushes) { - // Use pushes and pops to align the stack. There could be a better way, but - // realistically we'll only be pushing or popping once at a time. - assert(npushes >= 0); - // The pushes can come from any reg; for pops, - // use %rdi, or arg0, since the arguments should be safe to clobber - // after the call: - const int POP_REG = 7; - int pushes_needed = X86::PUSH_MULT - (npushes + X86::PUSH_MULT - 1) % X86::PUSH_MULT - 1; - //printf("emitting %d pushes to align to %d bytes\n", pushes_needed, X86::CALL_STACK_ALIGNMENT); - for (int i = 0; i < pushes_needed; i++) { - _emitPush(POP_REG); - } - - assert(new_addr); - _emitRex(X86::REX_W | X86::REX_B); - _emitByte(0xbb); - - uint8_t* rtn = addr; - uintptr_t addr_int = (uintptr_t)new_addr; - for (int i = 0; i < POINTER_SIZE; i++) { - _emitByte(addr_int & 0xff); - addr_int >>= 8; - } - //printf("\n"); - - _emitRex(X86::REX_B); - _emitByte(0xff); - _emitByte(0xd3); - - for (int i = 0; i < pushes_needed; i++) { - _emitPop(POP_REG); - } - - return rtn; - } - - virtual void emitAlloca(int bytes, int dest_argnum) { - int destreg = convertArgnum(dest_argnum); - - assert(bytes); - _emitSub(X86::REG_STACK_POINTER, bytes); - _emitMoveReg(X86::REG_STACK_POINTER, destreg); - } - - virtual void emitMove(int src_argnum, int dest_argnum, int npushed) { - if (src_argnum >= X86::NUM_ARG_REGS) { - // Note: no function call happened so rip didn't get pushed - int orig_offset = (src_argnum - X86::NUM_ARG_REGS) * POINTER_SIZE; - int offset = orig_offset + npushed * POINTER_SIZE; - int destreg = convertArgnum(dest_argnum); - _emitLoadRegIndirect(X86::REG_STACK_POINTER, offset, destreg); - } else { - int srcreg = convertArgnum(src_argnum); - int destreg = convertArgnum(dest_argnum); - _emitMoveReg(srcreg, destreg); - } - } - - virtual void emitGetattr(int src_argnum, int src_offset, - int dest_argnum) { - int srcreg = convertArgnum(src_argnum); - int destreg = convertArgnum(dest_argnum); - _emitLoadRegIndirect(srcreg, src_offset, destreg); - } - - virtual void emitIncattr(int argnum, int offset) { - int reg = convertArgnum(argnum); - _emitIncattr(reg, offset); - } - - virtual void emitSetattr(int src_argnum, int dest_argnum, - int dest_offset) { - int srcreg = convertArgnum(src_argnum); - int destreg = convertArgnum(dest_argnum); - _emitStoreRegIndirect(srcreg, destreg, dest_offset); - } - - virtual void emitPush(int argnum) { - _emitPush(convertArgnum(argnum)); - } - - virtual void emitPop(int argnum) { - _emitPop(convertArgnum(argnum)); - } - - virtual void emitLoadConst(int argnum, int64_t val) { - int reg = convertArgnum(argnum); - _emitMoveImm64(reg, val); - } - - virtual void emitCmp(AST_TYPE::AST_TYPE cmp_type, int lhs_argnum, int rhs_argnum, int dest_argnum) { - int lhs_reg = convertArgnum(lhs_argnum); - int rhs_reg = convertArgnum(rhs_argnum); - int dest_reg = convertArgnum(dest_argnum); - - _emitCmp(lhs_reg, rhs_reg); - - int condition_code; - switch (cmp_type) { - case AST_TYPE::Eq: - case AST_TYPE::Is: - condition_code = X86::COND_EQUAL; - break; - case AST_TYPE::NotEq: - case AST_TYPE::IsNot: - condition_code = X86::COND_NOT_EQUAL; - break; - default: - RELEASE_ASSERT(0, "%d", cmp_type); - } - - // TODO if we do this on rdi/rsi, which will be common, - // it'd be more efficient to clobber rax/rbx/rcx or rdx - // as a temporary, since it would save the two REX bytes. - // For now, let's just emit the lower-efficiency but - // easier-to-maintain code. - _emitCondSet(dest_reg, condition_code); - _emitZeroExtend(dest_reg, dest_reg); - } - - virtual void emitToBool(int argnum, int dest_argnum) { - int reg = convertArgnum(argnum); - int dest_reg = convertArgnum(dest_argnum); - - _emitTest(reg, reg); - _emitCondSet(dest_reg, X86::COND_NOT_ZERO); - } -}; -#endif - -void initializePatchpoint(uint8_t* addr, int size) { -#define CALL_SIZE 13 -#ifndef NDEBUG - assert(size >= CALL_SIZE); - - //if (VERBOSITY()) printf("initializing patchpoint at %p - %p\n", addr, addr + size); - //for (int i = 0; i < size; i++) { - //printf("%02x ", *(addr + i)); - //} - //printf("\n"); - - // Check the exact form of the patchpoint call. - // It's important to make sure that the only live registers - // are the ones that are used as arguments; ie it wouldn't - // matter if the call happened on %r10 instead of %r11, - // but it would matter if there wasn't a mov immediately before - // the call, since then %r11 would be live and we couldn't - // use it as a temporary. - - // mov $imm, %r11: - ASSERT(addr[0] == 0x49, "%x", addr[0]); - assert(addr[1] == 0xbb); - // 8 bytes of the addr - - // callq *%r11: - assert(addr[10] == 0x41); - assert(addr[11] == 0xff); - assert(addr[12] == 0xd3); - - int i = CALL_SIZE; - while (*(addr + i) == 0x66 || *(addr + i) == 0x0f || *(addr + i) == 0x2e) - i++; - assert(*(addr + i) == 0x90 || *(addr + i) == 0x1f); -#endif - - memcpy(addr + size - CALL_SIZE, addr, CALL_SIZE); - memset(addr, 0x90, size - CALL_SIZE); - //addr[0] = 0xcc; - - //// Move the call to the end of the region: - //char scratch[CALL_SIZE]; - //memcpy(scratch, addr, CALL_SIZE); - //std::memmove(addr, addr + CALL_SIZE, size - CALL_SIZE); - //memcpy(addr + size - CALL_SIZE, scratch, CALL_SIZE); -} - -/* -MCWriter* createMCWriter(uint8_t* addr, int size, int num_temp_regs) { - assert(num_temp_regs >= 0); - - // The X86MCWriter will automatically use %r10 and %r11, so don't need - // to pass that along. But if the client requested more than two - // temporaries, err out. - assert(num_temp_regs <= 2 && "unsupported"); - - return new X86MCWriter(addr, size); -} -*/ - -} diff --git a/src/asm_writing/mc_writer.h b/src/asm_writing/mc_writer.h deleted file mode 100644 index d95959b57..000000000 --- a/src/asm_writing/mc_writer.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_MCWRITER_H -#define PYSTON_ASMWRITING_MCWRITER_H - -#include "core/ast.h" - -namespace pyston { - -class BoxedClass; - -class MCWriter { - public: - virtual ~MCWriter() {} - - virtual int numArgRegs() = 0; - virtual int numTempRegs() = 0; - - // TODO I don't like this method, could be broken down into simpler things - virtual void emitAlloca(int bytes, int dest_argnum) = 0; - - virtual void emitNop() = 0; - virtual void emitTrap() = 0; - virtual void emitAnnotation(int num) = 0; - virtual void endFastPath(void* success_dest, void* will_relocate_to) = 0; - virtual void endWithSlowpath() = 0; - virtual uint8_t* emitCall(void* target, int npushes) = 0; - virtual void emitGuardFalse() = 0; - virtual void emitAttrGuard(int argnum, int offset, int64_t val, int npops) = 0; - virtual void emitGuard(int argnum, int64_t val, int npops) = 0; - virtual void emitGuardNotEq(int argnum, int64_t val, int npops) = 0; - virtual void emitMove(int src_argnum, int dest_argnum, int npushed) = 0; - virtual void emitSetattr(int src_argnum, int dest_argnum, int dest_offset) = 0; - virtual void emitGetattr(int src_argnum, int src_offset, int dest_argnum) = 0; - virtual void emitIncattr(int argnum, int offset) = 0; - virtual void emitPush(int reg) = 0; - virtual void emitPop(int reg) = 0; - virtual void emitLoadConst(int reg, int64_t value) = 0; - virtual void emitCmp(AST_TYPE::AST_TYPE cmp_type, int lhs_argnum, int rhs_argnum, int dest_argnum) = 0; - virtual void emitToBool(int argnum, int dest_argnum) = 0; - -}; - -void initializePatchpoint(uint8_t* addr, int size); -MCWriter* createMCWriter(uint8_t* addr, int size, int num_temp_regs); - -} - -#endif diff --git a/src/asm_writing/rewriter.cpp b/src/asm_writing/rewriter.cpp deleted file mode 100644 index 79a84a6ef..000000000 --- a/src/asm_writing/rewriter.cpp +++ /dev/null @@ -1,430 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/common.h" - -#include "core/stats.h" - -#include "asm_writing/assembler.h" -#include "asm_writing/icinfo.h" -#include "asm_writing/rewriter.h" - -namespace pyston { - -using namespace pyston::assembler; - -#define MAX_ARGS 16 - -Register fromArgnum(int argnum) { - switch (argnum) { - case -3: - return R11; - case -2: - return R10; - case -1: - return RAX; - case 0: - return RDI; - case 1: - return RSI; - case 2: - return RDX; - case 3: - return RCX; - case 4: - return R8; - case 5: - return R9; - } - RELEASE_ASSERT(0, "%d", argnum); -} - -RewriterVar::RewriterVar(Rewriter *rewriter, int argnum, int version) : rewriter(rewriter), argnum(argnum), version(version) { - //assert(rewriter.icentry.get()); -} - -RewriterVar& RewriterVar::operator=(const RewriterVar &rhs) { - assert(rewriter == NULL || rewriter == rhs.rewriter); - rhs.assertValid(); - rewriter = rhs.rewriter; - argnum = rhs.argnum; - version = rhs.version; - return *this; -} - -#ifndef NDEBUG -void RewriterVar::assertValid() const { - assert(rewriter); - rewriter->checkVersion(argnum, version); -} - -void RewriterVar::lock() { - assertValid(); - rewriter->lock(argnum); -} - -void RewriterVar::unlock() { - assertValid(); - rewriter->unlock(argnum); -} -#endif - -int RewriterVar::getArgnum() { - //assert(rewriter); - return argnum; -} - -RewriterVar RewriterVar::getAttr(int offset, int dest) { - assertValid(); - - rewriter->assembler->mov(Indirect(fromArgnum(this->argnum), offset), fromArgnum(dest)); - int version = rewriter->mutate(dest); - return RewriterVar(rewriter, dest, version); -} - -void RewriterVar::incAttr(int offset) { - assertValid(); - - rewriter->assembler->inc(Indirect(fromArgnum(this->argnum), offset)); - -#ifndef NDEBUG - rewriter->changed_something = true; -#endif -} - -void RewriterVar::setAttr(int offset, const RewriterVar& val, bool user_visible) { - assertValid(); - val.assertValid(); - - rewriter->assembler->mov(fromArgnum(val.argnum), Indirect(fromArgnum(this->argnum), offset)); - -#ifndef NDEBUG - if (user_visible) - rewriter->changed_something = true; -#endif -} - -RewriterVar RewriterVar::move(int dest_argnum) { - assertValid(); - - int version; - if (dest_argnum != this->argnum) { - assert(dest_argnum < 6); - - if (this->argnum >= 6) { - if (1) { - int offset = (this->argnum - 6) * 8 + rewriter->pushes.size() * 8 + rewriter->alloca_bytes; - rewriter->assembler->mov(Indirect(RSP, offset), fromArgnum(dest_argnum)); - } else { - int stack_size = rewriter->rewrite->getFuncStackSize(); - ASSERT(stack_size > 0 && stack_size < (1<<30), "%d", stack_size); - int offset = (this->argnum - 6) * 8 - (stack_size - 8); - rewriter->assembler->mov(Indirect(RBP, offset), fromArgnum(dest_argnum)); - } - } else { - rewriter->assembler->mov(fromArgnum(this->argnum), fromArgnum(dest_argnum)); - } - - version = rewriter->mutate(dest_argnum); - } else { - version = this->version; - } - return RewriterVar(rewriter, dest_argnum, version); -} - -void RewriterVar::addGuard(intptr_t val) { - assert(!rewriter->changed_something && "too late to add a guard!"); - assertValid(); - - rewriter->checkArgsValid(); - - int bytes = 8 * rewriter->pushes.size() + rewriter->alloca_bytes; - - if (val < (-1L<<31) || val >= (1L<<31) - 1) { - rewriter->assembler->push(RBP); - rewriter->assembler->mov(Immediate(val), RBP); - rewriter->assembler->cmp(fromArgnum(this->argnum), RBP); - rewriter->assembler->pop(RBP); - } else { - rewriter->assembler->cmp(fromArgnum(this->argnum), Immediate(val)); - } - rewriter->assembler->jne(JumpDestination::fromStart(rewriter->rewrite->getSlotSize() - bytes/8)); -} - -void RewriterVar::addAttrGuard(int offset, intptr_t val) { - assert(!rewriter->changed_something && "too late to add a guard!"); - assertValid(); - - rewriter->checkArgsValid(); - - int bytes = 8 * rewriter->pushes.size() + rewriter->alloca_bytes; - - if (val < (-1L<<31) || val >= (1L<<31) - 1) { - rewriter->assembler->push(RBP); - rewriter->assembler->mov(Immediate(val), RBP); - rewriter->assembler->cmp(Indirect(fromArgnum(this->argnum), offset), RBP); - rewriter->assembler->pop(RBP); - } else { - rewriter->assembler->cmp(Indirect(fromArgnum(this->argnum), offset), Immediate(val)); - } - rewriter->assembler->jne(JumpDestination::fromStart(rewriter->rewrite->getSlotSize() - bytes/8)); -} - -void RewriterVar::addGuardNotEq(intptr_t val) { - assert(!rewriter->changed_something && "too late to add a guard!"); - assertValid(); - - rewriter->checkArgsValid(); - - int bytes = 8 * rewriter->pushes.size() + rewriter->alloca_bytes; - rewriter->assembler->cmp(fromArgnum(this->argnum), Immediate(val)); - rewriter->assembler->je(JumpDestination::fromStart(rewriter->rewrite->getSlotSize() - bytes/8)); -} - -bool RewriterVar::isInReg() { - int num_arg_regs = 6; - return argnum < num_arg_regs; -} - -void RewriterVar::push() { - assertValid(); - assert(isInReg()); - - rewriter->assembler->push(fromArgnum(this->argnum)); - rewriter->addPush(this->version); -} - -RewriterVar RewriterVar::cmp(AST_TYPE::AST_TYPE cmp_type, const RewriterVar &val, int dest) { - assertValid(); - - rewriter->assembler->cmp(fromArgnum(this->argnum), fromArgnum(val.argnum)); - switch (cmp_type) { - case AST_TYPE::Eq: - rewriter->assembler->sete(fromArgnum(dest)); - break; - case AST_TYPE::NotEq: - rewriter->assembler->setne(fromArgnum(dest)); - break; - default: - RELEASE_ASSERT(0, "%d", cmp_type); - } - - int version = rewriter->mutate(dest); - return RewriterVar(rewriter, dest, version); -} - -RewriterVar RewriterVar::toBool(int dest) { - assertValid(); - - rewriter->assembler->test(fromArgnum(this->argnum), fromArgnum(this->argnum)); - rewriter->assembler->setnz(fromArgnum(dest)); - - int version = rewriter->mutate(dest); - return RewriterVar(rewriter, dest, version); -} - -Rewriter* Rewriter::createRewriter(void* ic_rtn_addr, int num_orig_args, int num_temp_regs, const char* debug_name) { - assert(num_temp_regs <= 2 && "unsupported"); - - static StatCounter rewriter_nopatch("rewriter_nopatch"); - - ICInfo *ic = getICInfo(ic_rtn_addr); - if (ic == NULL) { - rewriter_nopatch.log(); - return NULL; - } - - assert(ic->getCallingConvention() == llvm::CallingConv::C && "Rewriter[1] only supports the C calling convention!"); - return new Rewriter(ic->startRewrite(debug_name), num_orig_args, num_temp_regs); -} - -Rewriter::Rewriter(ICSlotRewrite* rewrite, int num_orig_args, int num_temp_regs) : - rewrite(rewrite), assembler(rewrite->getAssembler()), - num_orig_args(num_orig_args), num_temp_regs(num_temp_regs), alloca_bytes(0), max_pushes(0) -#ifndef NDEBUG - , next_version(2), changed_something(false) -#endif - , ndecisions(0), decision_path(1) - { - - //printf("trapping here\n"); - //assembler->trap(); - - //for (int i = 0; i < num_temp_regs; i++) { - //icentry->push(-2 - i); - //} - -#ifndef NDEBUG - for (int i = -3; i < MAX_ARGS; i++) { - versions[i] = next_version++; - } -#endif -} - -void Rewriter::addPush(int version) { - pushes.push_back(version); - max_pushes = std::max(max_pushes, (int)pushes.size()); -} - -RewriterVar Rewriter::alloca_(int bytes, int dest_argnum) { - // TODO should check to make sure we aren't crossing push+pops and allocas - //printf("alloca()ing %d bytes\n", bytes); - assert(bytes % sizeof(void*) == 0); - alloca_bytes += bytes; - - assembler->sub(Immediate(bytes), RSP); - assembler->mov(RSP, fromArgnum(dest_argnum)); - - int version = mutate(dest_argnum); - return RewriterVar(this, dest_argnum, version); -} - -RewriterVar Rewriter::getArg(int argnum) { - assert(argnum >= -1); - assert(argnum < MAX_ARGS); -#ifndef NDEBUG - int version = versions[argnum]; - assert(version); - assert(version == argnum + 5); -#else - int version = 0; -#endif - return RewriterVar(this, argnum, version); -} - -#ifndef NDEBUG -void Rewriter::checkArgsValid() { - for (int i = 0; i < num_orig_args; i++) - checkVersion(i, i + 5); -} - -int Rewriter::mutate(int argnum) { - ASSERT(locked.count(argnum) == 0, "arg %d is locked!", argnum); - assert(versions.count(argnum)); - - int rtn_version = ++next_version; - //printf("mutating %d to %d\n", argnum, rtn_version); - versions[argnum] = rtn_version; - return rtn_version; -} - -void Rewriter::lock(int argnum) { - assert(locked.count(argnum) == 0); - locked.insert(argnum); -} - -void Rewriter::unlock(int argnum) { - assert(locked.count(argnum) == 1); - locked.erase(argnum); -} - -void Rewriter::checkVersion(int argnum, int version) { - assert(version > 0); - ASSERT(version == versions[argnum], "arg %d got updated from %d to %d", argnum, version, versions[argnum]); -} -#endif - -void Rewriter::trap() { - assembler->trap(); -} - -void Rewriter::nop() { - assembler->nop(); -} - -void Rewriter::annotate(int num) { - assembler->emitAnnotation(num); -} - -RewriterVar Rewriter::loadConst(int argnum, intptr_t val) { - assembler->mov(Immediate(val), fromArgnum(argnum)); - int version = mutate(argnum); - return RewriterVar(this, argnum, version); -} - -RewriterVar Rewriter::call(void* func_addr) { -#ifndef NDEBUG - changed_something = true; -#endif - //printf("%ld pushes, %d alloca bytes\n", pushes.size(), alloca_bytes); - - int bytes = 8 * pushes.size() + alloca_bytes; - bool didpush; - if (bytes % 16 == 8) { - assembler->push(RDI); - didpush = true; - } else { - assert(bytes % 16 == 0); - didpush = false; - } - - assembler->emitCall(func_addr, R11); - - if (didpush) - assembler->pop(RDI); - -#ifndef NDEBUG - int num_arg_regs = 6; - for (int i = -3; i < num_arg_regs; i++) { - mutate(i); - } -#endif - return RewriterVar(this, -1, mutate(-1)); -} - -RewriterVar Rewriter::pop(int argnum) { - assert(pushes.size() > 0); - - int version = pushes.back(); - pushes.pop_back(); -#ifndef NDEBUG - versions[argnum] = version; -#endif - //printf("popping %d to %d\n", version, argnum); - - assembler->pop(fromArgnum(argnum)); - return RewriterVar(this, argnum, version); -} - -void Rewriter::addDecision(int way) { - assert(ndecisions < 60); - ndecisions++; - decision_path = (decision_path << 1) | way; -} - -void Rewriter::addDependenceOn(ICInvalidator &invalidator) { - rewrite->addDependenceOn(invalidator); -} - -void Rewriter::commit() { - static StatCounter rewriter_commits("rewriter_commits"); - rewriter_commits.log(); - - // make sure we left the stack the way we found it: - assert(pushes.size() == 0); - assert(alloca_bytes == 0); - - rewrite->commit(decision_path, this); -} - -void Rewriter::finishAssembly(int continue_offset) { - assembler->jmp(JumpDestination::fromStart(continue_offset)); - - assembler->fillWithNopsExcept(max_pushes); - for (int i = 0; i < max_pushes; i++) { - assembler->pop(RAX); - } -} - -} diff --git a/src/asm_writing/rewriter.h b/src/asm_writing/rewriter.h deleted file mode 100644 index 5980064fd..000000000 --- a/src/asm_writing/rewriter.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_REWRITER_H -#define PYSTON_ASMWRITING_REWRITER_H - -#include -#include -#include - -#include "core/ast.h" - -namespace pyston { - -class ICInfo; -class ICSlotInfo; -class ICInvalidator; -class Rewriter; - -namespace assembler { -class Assembler; -} - -// TODO Maybe should make these classes abstract and then pick between a debug implementation -// and a release one, instead of trying to make one class do both? - -class RewriterVar { - private: - Rewriter *rewriter; - int argnum; - int version; - - public: - RewriterVar() : rewriter(NULL), argnum(-100), version(-100) {} - RewriterVar(Rewriter *rewriter, int argnum, int version); - RewriterVar& operator=(const RewriterVar &rhs); - -#ifndef NDEBUG - void assertValid() const; - void lock(); - void unlock(); -#else - inline void assertValid() const {} - inline void lock() {} - inline void unlock() {} -#endif - int getArgnum(); - - void addGuard(intptr_t val); - void addGuardNotEq(intptr_t val); - // More efficient than getAttr().addGuard(), but less efficient than addGuard() if the value is already available: - void addAttrGuard(int offset, intptr_t val); - - RewriterVar getAttr(int offset, int dest); - void incAttr(int offset); - void setAttr(int offset, const RewriterVar &val, bool user_visible=true); - RewriterVar move(int argnum); - bool isInReg(); - void push(); - RewriterVar cmp(AST_TYPE::AST_TYPE cmp_type, const RewriterVar &val, int dest); - RewriterVar toBool(int dest); - - friend class Rewriter; -}; - -class Rewriter : public ICSlotRewrite::CommitHook { - private: - std::unique_ptr rewrite; - assembler::Assembler *assembler; - const int num_orig_args; - const int num_temp_regs; - - void finishAssembly(int continue_offset); - - int alloca_bytes; - int max_pushes; - std::vector pushes; -#ifndef NDEBUG - std::unordered_map versions; - int next_version; - bool changed_something; - std::unordered_set locked; -#endif - int ndecisions; - uint64_t decision_path; - - Rewriter(ICSlotRewrite* rewrite, int num_orig_args, int num_temp_regs); - - void addPush(int version); - public: - static Rewriter* createRewriter(void* ic_rtn_addr, int num_orig_args, int num_temp_regs, const char* debug_name); - -#ifndef NDEBUG - int mutate(int argnum); - void lock(int argnum); - void unlock(int argnum); - void checkVersion(int argnum, int version); - void checkArgsValid(); -#else - inline int mutate(int argnum) { return 0; } - inline void lock(int argnum) {} - inline void unlock(int argnum) {} - inline void checkVersion(int argnum, int version) {} - inline void checkArgsValid() {} -#endif - - void addDecision(int way); - - RewriterVar alloca_(int bytes, int dest_argnum); - RewriterVar getArg(int argnum); - - void trap(); - void nop(); - void annotate(int num); - RewriterVar pop(int argnum); - RewriterVar call(void* func_addr); - RewriterVar loadConst(int argnum, intptr_t val); - - void addDependenceOn(ICInvalidator&); - void commit(); - - friend class RewriterVar; -}; - -} - -#endif diff --git a/src/asm_writing/rewriter2.cpp b/src/asm_writing/rewriter2.cpp deleted file mode 100644 index 3a1aa3dc7..000000000 --- a/src/asm_writing/rewriter2.cpp +++ /dev/null @@ -1,749 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/common.h" -#include "core/stats.h" - -#include "asm_writing/icinfo.h" -#include "asm_writing/rewriter2.h" - -namespace pyston { - - -static const assembler::Register allocatable_regs[] = { - assembler::RAX, - assembler::RCX, - assembler::RBX, - assembler::RDX, - // no RSP - // no RBP - assembler::RDI, - assembler::RSI, - assembler::R8, - assembler::R9, - assembler::R10, - assembler::R11, - assembler::R12, - assembler::R13, - assembler::R14, - assembler::R15, -}; - - - -Location Location::forArg(int argnum) { - assert(argnum >= 0); - switch (argnum) { - case 0: - return assembler::RDI; - case 1: - return assembler::RSI; - case 2: - return assembler::RDX; - case 3: - return assembler::RCX; - case 4: - return assembler::R8; - case 5: - return assembler::R9; - default: - break; - } - RELEASE_ASSERT(0, "the following is untested"); - //int offset = (argnum - 6) * 8; - //return Location(Stack, offset); -} - -assembler::Register Location::asRegister() const { - assert(type == Register); - return assembler::Register(regnum); -} - -assembler::XMMRegister Location::asXMMRegister() const { - assert(type == XMMRegister); - return assembler::XMMRegister(regnum); -} - -bool Location::isClobberedByCall() const { - if (type == Register) { - return !asRegister().isCalleeSave(); - } - - if (type == XMMRegister) - return true; - - if (type == Scratch) - return false; - - RELEASE_ASSERT(0, "%d", type); -} - -void Location::dump() const { - if (type == Register) { - asRegister().dump(); - return; - } - - if (type == XMMRegister) { - printf("%%xmm%d\n", regnum); - return; - } - - if (type == Scratch) { - printf("scratch(%d)\n", stack_offset); - return; - } - - RELEASE_ASSERT(0, "%d", type); -} - - - -RewriterVarUsage2::RewriterVarUsage2(RewriterVar2 *var) : var(var), done_using(false) { - assert(var->rewriter); -} - -void RewriterVarUsage2::addAttrGuard(int offset, uint64_t val) { - Rewriter2* rewriter = var->rewriter; - assembler::Assembler* assembler = rewriter->assembler; - - assert(!rewriter->done_guarding && "too late to add a guard!"); - assertValid(); - - assembler::Register this_reg = var->getInReg(); - if (val < (-1L<<31) || val >= (1L<<31) - 1) { - assembler::Register reg = rewriter->allocReg(Location::any()); - assembler->mov(assembler::Immediate(val), reg); - assembler->cmp(assembler::Indirect(this_reg, offset), reg); - } else { - assembler->cmp(assembler::Indirect(this_reg, offset), assembler::Immediate(val)); - } - assembler->jne(assembler::JumpDestination::fromStart(rewriter->rewrite->getSlotSize())); -} - -RewriterVarUsage2 RewriterVarUsage2::getAttr(int offset, KillFlag kill, Location dest) { - assertValid(); - - // Save these, since if we kill this register the var might disappear: - assembler::Register this_reg = var->getInReg(); - Rewriter2* rewriter = var->rewriter; - - if (kill) { - setDoneUsing(); - } - - assembler::Register newvar_reg = rewriter->allocReg(dest); - RewriterVarUsage2 newvar = rewriter->createNewVar(newvar_reg); - rewriter->assembler->mov(assembler::Indirect(this_reg, offset), newvar_reg); - return std::move(newvar); -} - -void RewriterVarUsage2::setAttr(int offset, RewriterVarUsage2 val) { - assertValid(); - var->rewriter->assertChangesOk(); - - assembler::Register this_reg = var->getInReg(); - - bool is_immediate; - assembler::Immediate imm = val.var->tryGetAsImmediate(&is_immediate); - - if (is_immediate) { - var->rewriter->assembler->movq(imm, assembler::Indirect(this_reg, offset)); - } else { - assembler::Register other_reg = val.var->getInReg(); - - // TODO the allocator could choose to spill this_reg in order to load other_reg... - // Hopefuly it won't make that decision, so we should just be able to guard on it for now: - assert(this_reg != other_reg); - - var->rewriter->assembler->mov(other_reg, assembler::Indirect(this_reg, offset)); - } - - val.setDoneUsing(); -} - -void RewriterVarUsage2::setDoneUsing() { - assertValid(); - done_using = true; - var->decUse(); -} - -RewriterVarUsage2::RewriterVarUsage2(RewriterVarUsage2 &&usage) { - assert(!usage.done_using); - assert(usage.var != NULL); - - var = usage.var; - done_using = usage.done_using; - - usage.var = NULL; - usage.done_using = true; -} - -RewriterVarUsage2& RewriterVarUsage2::operator=(RewriterVarUsage2 &&usage) { - assert(done_using); - assert(var == NULL); - assert(!usage.done_using); - assert(usage.var != NULL); - - var = usage.var; - done_using = usage.done_using; - - usage.var = NULL; - usage.done_using = true; - - return *this; -} - -assembler::Immediate RewriterVar2::tryGetAsImmediate(bool *is_immediate) { - for (Location l : locations) { - if (l.type == Location::Constant) { - *is_immediate = true; - return assembler::Immediate(l.constant_val); - } - } - *is_immediate = false; - return assembler::Immediate((uint64_t)0); -} - -assembler::Register RewriterVar2::getInReg(Location dest) { - assert(dest.type == Location::Register || dest.type == Location::AnyReg); - - //assembler::Register reg = var->rewriter->allocReg(l); - //var->rewriter->addLocationToVar(var, reg); - //return reg; - assert(locations.size()); -#ifndef NDEBUG - for (Location l : locations) { - ASSERT(l.type != Location::Constant, "why do you want this in a register?"); - } -#endif - - // Not sure if this is worth it, - // but first try to see if we're already in this specific register - for (Location l : locations) { - if (l == dest) - return l.asRegister(); - } - - // Then, see if we're in another register - for (Location l : locations) { - if (l.type == Location::Register) { - assembler::Register reg = l.asRegister(); - if (dest.type != Location::AnyReg) { - assembler::Register dest_reg = dest.asRegister(); - assert(dest_reg != reg); // should have been caught by the previous case - - rewriter->assembler->mov(reg, dest_reg); - rewriter->addLocationToVar(this, dest_reg); - return dest_reg; - } - return reg; - } - } - - assert(locations.size() == 1); - Location l(*locations.begin()); - assert(l.type == Location::Scratch); - - - assembler::Register reg = rewriter->allocReg(dest); - assert(rewriter->vars_by_location.count(reg) == 0); - - assembler::Indirect mem = rewriter->indirectFor(l); - rewriter->assembler->mov(mem, reg); - rewriter->addLocationToVar(this, reg); - return reg; -} - -assembler::XMMRegister RewriterVar2::getInXMMReg(Location dest) { - assert(dest.type == Location::XMMRegister || dest.type == Location::AnyReg); - - assert(locations.size()); -#ifndef NDEBUG - for (Location l : locations) { - ASSERT(l.type != Location::Constant, "why do you want this in a register?"); - } -#endif - - // Not sure if this is worth it, - // but first try to see if we're already in this specific register - for (Location l : locations) { - if (l == dest) - return l.asXMMRegister(); - } - - // Then, see if we're in another register - for (Location l : locations) { - if (l.type == Location::XMMRegister) { - assembler::XMMRegister reg = l.asXMMRegister(); - if (dest.type != Location::AnyReg) { - assembler::XMMRegister dest_reg = dest.asXMMRegister(); - assert(dest_reg != reg); // should have been caught by the previous case - - rewriter->assembler->movsd(reg, dest_reg); - rewriter->addLocationToVar(this, dest_reg); - return dest_reg; - } - return reg; - } - } - - assert(locations.size() == 1); - Location l(*locations.begin()); - assert(l.type == Location::Scratch); - - - assert(dest.type == Location::XMMRegister); - assembler::XMMRegister reg = dest.asXMMRegister(); - assert(rewriter->vars_by_location.count(reg) == 0); - - assembler::Indirect mem = rewriter->indirectFor(l); - rewriter->assembler->movsd(mem, reg); - rewriter->addLocationToVar(this, reg); - return reg; -} - -RewriterVarUsage2::RewriterVarUsage2() : var(NULL), done_using(true) { -} - -RewriterVarUsage2 RewriterVarUsage2::empty() { - return RewriterVarUsage2(); -} - - - -void RewriterVar2::decUse() { - num_uses--; - if (num_uses == 0) { - rewriter->kill(this); - delete this; - } -} - -void RewriterVar2::incUse() { - num_uses++; -} - -bool RewriterVar2::isInLocation(Location l) { - return locations.count(l) != 0; -} - - - -void Rewriter2::setDoneGuarding() { - assert(!done_guarding); - done_guarding = true; - - for (RewriterVar2 *var : args) { - var->decUse(); - } - args.clear(); -} - -RewriterVarUsage2 Rewriter2::getArg(int argnum) { - assert(!done_guarding); - assert(argnum >= 0 && argnum < args.size()); - - RewriterVar2* var = args[argnum]; - var->incUse(); - return RewriterVarUsage2(var); -} - -Location Rewriter2::getReturnDestination() { - return return_location; -} - -void Rewriter2::trap() { - assembler->trap(); -} - -RewriterVarUsage2 Rewriter2::loadConst(int64_t val, Location dest) { - if (val >= (-1L<<31) && val < (1L<<31) - 1) { - Location l(Location::Constant, val); - return createNewVar(l); - } - - assembler::Register reg = allocReg(dest); - RewriterVarUsage2 var = createNewVar(reg); - assembler->mov(assembler::Immediate(val), reg); - // I guess you don't need std::move here: - return var; -} - -RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0) { - std::vector args; - args.push_back(std::move(arg0)); - return call(can_call_into_python, func_addr, std::move(args)); -} - -RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0, RewriterVarUsage2 arg1) { - std::vector args; - args.push_back(std::move(arg0)); - args.push_back(std::move(arg1)); - return call(can_call_into_python, func_addr, std::move(args)); -} - -static const Location caller_save_registers[] { - assembler::RAX, - assembler::RCX, - assembler::RDX, - assembler::RSI, - assembler::RDI, - assembler::R8, - assembler::R9, - assembler::R10, - assembler::R11, - - assembler::XMM0, - assembler::XMM1, - assembler::XMM2, - assembler::XMM3, - assembler::XMM4, - assembler::XMM5, - assembler::XMM6, - assembler::XMM7, - assembler::XMM8, - assembler::XMM9, - assembler::XMM10, - assembler::XMM11, - assembler::XMM12, - assembler::XMM13, - assembler::XMM14, - assembler::XMM15, -}; - -RewriterVarUsage2 Rewriter2::call(bool can_call_into_python, void* func_addr, std::vector args) { - assert(!can_call_into_python); - - assertChangesOk(); - - //RewriterVarUsage2 scratch = createNewVar(Location::any()); - assembler::Register r = allocReg(assembler::R11); - - for (int i = 0; i < args.size(); i++) { - Location l(Location::forArg(i)); - RewriterVar2 *var = args[i].var; - if (!var->isInLocation(l)) { - assembler::Register r = l.asRegister(); - - assembler::Register r2 = allocReg(l); - assert(r == r2); - assert(vars_by_location.count(l) == 0); - - bool is_immediate; - assembler::Immediate imm = var->tryGetAsImmediate(&is_immediate); - - assert(is_immediate); - assembler->mov(imm, r); - addLocationToVar(var, l); - } - - assert(var->isInLocation(Location::forArg(i))); - args[i].setDoneUsing(); - } - - // Spill caller-saved registers: - for (auto check_reg : caller_save_registers) { - //check_reg.dump(); - assert(check_reg.isClobberedByCall()); - - auto it = vars_by_location.find(check_reg); - if (it == vars_by_location.end()) - continue; - - RewriterVar2 *var = it->second; - bool need_to_spill = true; - for (Location l : var->locations) { - if (!l.isClobberedByCall()) { - need_to_spill = false; - break; - } - } - - if (need_to_spill) { - if (check_reg.type == Location::Register) { - spillRegister(check_reg.asRegister()); - } else { - assert(check_reg.type == Location::XMMRegister); - assert(var->locations.size() == 1); - spillRegister(check_reg.asXMMRegister()); - } - } else { - removeLocationFromVar(var, check_reg); - } - } - -#ifndef NDEBUG - for (auto p : vars_by_location) { - Location l = p.first; - //l.dump(); - assert(!l.isClobberedByCall()); - } -#endif - - - assembler->mov(assembler::Immediate(func_addr), r); - assembler->callq(r); - - assert(vars_by_location.count(assembler::RAX) == 0); - RewriterVar2* var = vars_by_location[assembler::RAX] = new RewriterVar2(this, assembler::RAX); - return RewriterVarUsage2(var); -} - -void Rewriter2::commit() { - static StatCounter rewriter2_commits("rewriter2_commits"); - rewriter2_commits.log(); - - assert(done_guarding && "Could call setDoneGuarding for you, but probably best to do it yourself"); - //if (!done_guarding) - //setDoneGuarding(); - - assert(live_out_regs.size() == live_outs.size()); - for (int i = 0; i < live_outs.size(); i++) { - assembler::GenericRegister ru = assembler::GenericRegister::fromDwarf(live_out_regs[i]); - Location expected(ru); - - RewriterVar2 *var = live_outs[i]; - //for (Location l : var->locations) { - //printf("%d %d\n", l.type, l._data); - //} - if (!var->isInLocation(expected)) { - assert(vars_by_location.count(expected) == 0); - - if (ru.type == assembler::GenericRegister::GP) { - assembler::Register reg = var->getInReg(ru.gp); - assert(reg == ru.gp); - } else if (ru.type == assembler::GenericRegister::XMM) { - assembler::XMMRegister reg = var->getInXMMReg(ru.xmm); - assert(reg == ru.xmm); - } else { - RELEASE_ASSERT(0, "%d", ru.type); - } - } - - assert(var->isInLocation(ru)); - var->decUse(); - } - - assert(vars_by_location.size() == 0); - - rewrite->commit(0, this); -} - -void Rewriter2::finishAssembly(int continue_offset) { - assembler->jmp(assembler::JumpDestination::fromStart(continue_offset)); - - assembler->fillWithNops(); -} - -void Rewriter2::commitReturning(RewriterVarUsage2 usage) { - assert(usage.var->isInLocation(getReturnDestination())); - - /* - Location l = usage.var->location; - Location expected = getReturnDestination(); - - if (l != expected) { - assert(l.type == Location::Register); - assert(expected.type == Location::Register); - - assembler->mov(l.asRegister(), expected.asRegister()); - } - */ - - usage.setDoneUsing(); - commit(); -} - -void Rewriter2::addDependenceOn(ICInvalidator &invalidator) { - rewrite->addDependenceOn(invalidator); -} - -void Rewriter2::kill(RewriterVar2 *var) { - for (Location l : var->locations) { - assert(vars_by_location[l] == var); - vars_by_location.erase(l); - } -} - -Location Rewriter2::allocScratch() { - int scratch_bytes = rewrite->getScratchBytes(); - for (int i = 0; i < scratch_bytes; i += 8) { - Location l(Location::Scratch, i); - if (vars_by_location.count(l) == 0) - return l; - } - RELEASE_ASSERT(0, "Using all %d bytes of scratch!", scratch_bytes); -} - -assembler::Indirect Rewriter2::indirectFor(Location l) { - assert(l.type == Location::Scratch); - - // TODO it can sometimes be more efficient to do RSP-relative addressing? - int rbp_offset = rewrite->getScratchRbpOffset() + l.scratch_offset; - return assembler::Indirect(assembler::RBP, rbp_offset); -} - -void Rewriter2::spillRegister(assembler::Register reg) { - assert(done_guarding); - - RewriterVar2 *var = vars_by_location[reg]; - assert(var); - - // First, try to spill into a callee-save register: - for (assembler::Register new_reg : allocatable_regs) { - if (!new_reg.isCalleeSave()) - continue; - if (vars_by_location.count(new_reg)) - continue; - - assembler->mov(reg, new_reg); - addLocationToVar(var, new_reg); - removeLocationFromVar(var, reg); - return; - } - - Location scratch = allocScratch(); - assembler::Indirect mem = indirectFor(scratch); - assembler->mov(reg, mem); - addLocationToVar(var, scratch); - removeLocationFromVar(var, reg); -} - -void Rewriter2::spillRegister(assembler::XMMRegister reg) { - assert(done_guarding); - - RewriterVar2 *var = vars_by_location[reg]; - assert(var); - - assert(var->locations.size() == 1); - - Location scratch = allocScratch(); - assembler::Indirect mem = indirectFor(scratch); - assembler->movsd(reg, mem); - addLocationToVar(var, scratch); - removeLocationFromVar(var, reg); -} - -assembler::Register Rewriter2::allocReg(Location dest) { - if (dest.type == Location::AnyReg) { - for (assembler::Register reg : allocatable_regs) { - if (vars_by_location.count(reg) == 0) - return reg; - } - RELEASE_ASSERT(0, "couldn't find a reg to allocate and haven't added spilling"); - } else if (dest.type == Location::Register) { - assembler::Register reg(dest.regnum); - - if (vars_by_location.count(reg)) { - spillRegister(reg); - } - - assert(vars_by_location.count(reg) == 0); - return reg; - } else { - RELEASE_ASSERT(0, "%d", dest.type); - } -} - -void Rewriter2::addLocationToVar(RewriterVar2 *var, Location l) { - assert(!var->isInLocation(l)); - assert(vars_by_location.count(l) == 0); - - var->locations.insert(l); - vars_by_location[l] = var; -} - -void Rewriter2::removeLocationFromVar(RewriterVar2 *var, Location l) { - assert(var->isInLocation(l)); - assert(vars_by_location[l] = var); - - vars_by_location.erase(l); - var->locations.erase(l); -} - -RewriterVarUsage2 Rewriter2::createNewVar(Location dest) { - RewriterVar2* &var = vars_by_location[dest]; - assert(!var); - - var = new RewriterVar2(this, dest); - return var; -} - -Rewriter2::Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector &live_outs) : - rewrite(rewrite), assembler(rewrite->getAssembler()), - return_location(rewrite->returnRegister()), done_guarding(false) { - //assembler->trap(); - - for (int i = 0; i < num_args; i++) { - Location l = Location::forArg(i); - RewriterVar2 *var = new RewriterVar2(this, l); - vars_by_location[l] = var; - - args.push_back(var); - } - - static StatCounter rewriter_starts("rewriter2_starts"); - rewriter_starts.log(); - static StatCounter rewriter_spillsavoided("rewriter2_spillsavoided"); - - // Calculate the list of live-ins based off the live-outs list, - // and create a Use of them so that they get preserved - for (int dwarf_regnum : live_outs) { - assembler::GenericRegister ru = assembler::GenericRegister::fromDwarf(dwarf_regnum); - - Location l(ru); - - // We could handle this here, but for now we're assuming that the return destination - // will get removed from this list before it gets handed to us. - assert(l != getReturnDestination()); - - //// The return register is the only live-out that is not also a live-in. - //if (l == getReturnDestination()) { - //l.dump(); - //continue; - //} - - if (l.isClobberedByCall()) { - rewriter_spillsavoided.log(); - } - - RewriterVar2* &var = vars_by_location[l]; - if (var) { - var->incUse(); - } else { - var = new RewriterVar2(this, l); - } - - this->live_outs.push_back(var); - this->live_out_regs.push_back(dwarf_regnum); - } -} - -Rewriter2* Rewriter2::createRewriter(void* rtn_addr, int num_args, const char* debug_name) { - ICInfo *ic = getICInfo(rtn_addr); - - static StatCounter rewriter_nopatch("rewriter_nopatch"); - - if (!ic) { - rewriter_nopatch.log(); - return NULL; - } - - return new Rewriter2(ic->startRewrite(debug_name), num_args, ic->getLiveOuts()); -} - -} diff --git a/src/asm_writing/rewriter2.h b/src/asm_writing/rewriter2.h deleted file mode 100644 index 6b7502884..000000000 --- a/src/asm_writing/rewriter2.h +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_REWRITER2_H -#define PYSTON_ASMWRITING_REWRITER2_H - -#include - -#include "asm_writing/assembler.h" - -namespace pyston { - -class ICInfo; -class ICSlotInfo; -class ICSlotRewrite; -class ICInvalidator; - -class RewriterVar2; - -struct Location { - public: - enum LocationType : uint8_t { - Register, - XMMRegister, - //Stack, - Scratch, // stack location, relative to the scratch start - - // For representing constants that fit in 32-bits, that can be encoded as immediates - Constant, - - AnyReg, // special type for use when specifying a location as a destination - None, // special type that represents the lack of a location, ex where a "ret void" gets returned - }; - - public: - const LocationType type; - - union { - // only valid if type==Register; uses X86 numbering, not dwarf numbering. - // also valid if type==XMMRegister - const int32_t regnum; - // only valid if type==Stack; this is the offset from bottom of the original frame. - // ie argument #6 will have a stack_offset of 0, #7 will have a stack offset of 8, etc - const int32_t stack_offset; - // only valid if type == Scratch; offset from the beginning of the scratch area - const int32_t scratch_offset; - - // only valid if type==Constant - const int32_t constant_val; - - const int32_t _data; - }; - - constexpr Location(LocationType type, int32_t data) : type(type), _data(data) { - } - - constexpr Location(assembler::Register reg) : type(Register), regnum(reg.regnum) { - } - - constexpr Location(assembler::XMMRegister reg) : type(XMMRegister), regnum(reg.regnum) { - } - - constexpr Location(assembler::GenericRegister reg) : type(reg.type == assembler::GenericRegister::GP ? Register : reg.type == assembler::GenericRegister::XMM ? XMMRegister : None), regnum(reg.type == assembler::GenericRegister::GP ? reg.gp.regnum : reg.xmm.regnum) { - } - - assembler::Register asRegister() const; - assembler::XMMRegister asXMMRegister() const; - bool isClobberedByCall() const; - - static constexpr Location any() { return Location(AnyReg, 0); } - static constexpr Location none() { return Location(None, 0); } - static Location forArg(int argnum); - - bool operator==(const Location rhs) const { - return this->asInt() == rhs.asInt(); - } - - bool operator!=(const Location rhs) const { - return !(*this == rhs); - } - - uint64_t asInt() const { - return (int)type + ((uint64_t)_data << 4); - } - - void dump() const; -}; -static_assert(sizeof(Location) <= 8, ""); - -} - -namespace std { - template <> struct hash { - size_t operator() (const pyston::Location p) const { - return p.asInt(); - } - }; -} - -namespace pyston { - -class RewriterVarUsage2 { - public: - enum KillFlag { - NoKill, - Kill, - }; - - private: - RewriterVar2 *var; - bool done_using; - - RewriterVarUsage2(); - RewriterVarUsage2(const RewriterVarUsage2&) = delete; - RewriterVarUsage2& operator=(const RewriterVarUsage2&) = delete; - - void assertValid() { - assert(var); - assert(!done_using); - } - - public: - // Creates a new Usage object of this var; ownership of - // one use of the var gets passed to this new object. - RewriterVarUsage2(RewriterVar2 *var); - - // Move constructor; don't need it for performance reasons, but because - // semantically we have to pass the ownership of the use. - RewriterVarUsage2(RewriterVarUsage2 &&usage); - RewriterVarUsage2& operator=(RewriterVarUsage2 &&usage); - // assert(this->var == NULL) - // assert(this->done_using) - // assert(usage->var != NULL) - // assert(!usage->done_using) - - static RewriterVarUsage2 empty(); - -#ifndef NDEBUG - ~RewriterVarUsage2() { - assert(done_using); - } -#endif - - void setDoneUsing(); - //void setDoneUsing() { - //assert(!done_using); - //done_using = true; -// - //var->delUse(); - //} - - //RewriterVarUsage2 addUse() { return var->addUse(); } - RewriterVarUsage2 addUse(); - - void addAttrGuard(int offset, uint64_t val); - RewriterVarUsage2 getAttr(int offset, KillFlag kill, Location loc=Location::any()); - void setAttr(int offset, RewriterVarUsage2 other); - - friend class Rewriter2; -}; - -class Rewriter2; -// This might make more sense as an inner class of Rewriter2, but -// you can't forward-declare that :/ -class RewriterVar2 { - private: - Rewriter2 *rewriter; - int num_uses; - - std::unordered_set locations; - bool isInLocation(Location l); - - // Gets a copy of this variable in a register, spilling/reloading if necessary. - // TODO have to be careful with the result since the interface doesn't guarantee - // that the register will still contain your value when you go to use it - assembler::Register getInReg(Location l=Location::any()); - assembler::XMMRegister getInXMMReg(Location l=Location::any()); - - // If this is an immediate, try getting it as one - assembler::Immediate tryGetAsImmediate(bool *is_immediate); - - public: - void incUse(); - void decUse(); - - RewriterVar2(Rewriter2* rewriter, Location location) : rewriter(rewriter), num_uses(1) { - assert(rewriter); - locations.insert(location); - } - - friend class RewriterVarUsage2; - friend class Rewriter2; -}; - -class Rewriter2 : public ICSlotRewrite::CommitHook { - private: - std::unique_ptr rewrite; - assembler::Assembler* assembler; - - const Location return_location; - - bool done_guarding; - - std::vector live_out_regs; - - std::unordered_map vars_by_location; - std::vector args; - std::vector live_outs; - - Rewriter2(ICSlotRewrite* rewrite, int num_args, const std::vector& live_outs); - - void assertChangesOk() { assert(done_guarding); } - - void kill(RewriterVar2 *var); - - // Allocates a register. dest must be of type Register or AnyReg - assembler::Register allocReg(Location dest); - // Allocates an 8-byte region in the scratch space - Location allocScratch(); - assembler::Indirect indirectFor(Location l); - // Spills a specified register. - // If there are open callee-save registers, takes one of those, otherwise goes on the stack - void spillRegister(assembler::Register reg); - // Similar, but for XMM registers (always go on the stack) - void spillRegister(assembler::XMMRegister reg); - - // Given an empty location, do the internal bookkeeping to create a new var out of that location. - RewriterVarUsage2 createNewVar(Location dest); - // Do the bookkeeping to say that var is now also in location l - void addLocationToVar(RewriterVar2 *var, Location l); - // Do the bookkeeping to say that var is no longer in location l - void removeLocationFromVar(RewriterVar2 *var, Location l); - - void finishAssembly(int continue_offset) override; - - public: - // This should be called exactly once for each argument - RewriterVarUsage2 getArg(int argnum); - - Location getReturnDestination(); - - bool isDoneGuarding() { return done_guarding; } - void setDoneGuarding(); - - void trap(); - RewriterVarUsage2 loadConst(int64_t val, Location loc=Location::any()); - RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, std::vector args); - RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0); - RewriterVarUsage2 call(bool can_call_into_python, void* func_addr, RewriterVarUsage2 arg0, RewriterVarUsage2 arg1); - - void commit(); - void commitReturning(RewriterVarUsage2 rtn); - - void addDependenceOn(ICInvalidator&); - - static Rewriter2* createRewriter(void* rtn_addr, int num_args, const char* debug_name); - - friend class RewriterVar2; - friend class RewriterVarUsage2; -}; - -} - -#endif diff --git a/src/asm_writing/types.h b/src/asm_writing/types.h deleted file mode 100644 index d234df334..000000000 --- a/src/asm_writing/types.h +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_ASMWRITING_TYPES_H -#define PYSTON_ASMWRITING_TYPES_H - -namespace pyston { - -struct StackInfo { - int stack_size; - - bool has_scratch; - int scratch_bytes; - int scratch_rbp_offset; -}; - -namespace assembler { - -class Assembler; - -struct Register { - int regnum; - - explicit constexpr Register(int regnum) : regnum(regnum) {} - - bool isCalleeSave(); - - bool operator==(const Register &rhs) const { - return regnum == rhs.regnum; - } - - bool operator!=(const Register &rhs) const { - return !(*this == rhs); - } - - void dump() const; -}; - -const Register RAX(0); -const Register RCX(1); -const Register RDX(2); -const Register RBX(3); -const Register RSP(4); -const Register RBP(5); -const Register RSI(6); -const Register RDI(7); -const Register R8(8); -const Register R9(9); -const Register R10(10); -const Register R11(11); -const Register R12(12); -const Register R13(13); -const Register R14(14); -const Register R15(15); - -inline bool Register::isCalleeSave() { - return *this == RBX || *this == RSP || *this == RBP || regnum >= 12; -} - -struct Indirect { - public: - const Register base; - const int offset; - - Indirect(const Register base, int offset) : base(base), offset(offset) {} -}; - -struct XMMRegister { - int regnum; - - explicit constexpr XMMRegister(int regnum) : regnum(regnum) {} - - bool operator==(const XMMRegister &rhs) const { - return regnum == rhs.regnum; - } - - bool operator!=(const XMMRegister &rhs) const { - return !(*this == rhs); - } -}; - -const XMMRegister XMM0(0); -const XMMRegister XMM1(1); -const XMMRegister XMM2(2); -const XMMRegister XMM3(3); -const XMMRegister XMM4(4); -const XMMRegister XMM5(5); -const XMMRegister XMM6(6); -const XMMRegister XMM7(7); -const XMMRegister XMM8(8); -const XMMRegister XMM9(9); -const XMMRegister XMM10(10); -const XMMRegister XMM11(11); -const XMMRegister XMM12(12); -const XMMRegister XMM13(13); -const XMMRegister XMM14(14); -const XMMRegister XMM15(15); - -struct GenericRegister { - union { - Register gp; - XMMRegister xmm; - }; - - enum Type { - GP, - XMM, - None, - } type; - - /* - int size() const { - switch (type) { - case GP: - return Register::SIZE; - case XMM: - return XMMRegister::SIZE; - default: - assert(0); - } - abort(); - } - */ - - explicit constexpr GenericRegister() : gp(0), type(None) {} - constexpr GenericRegister(const Register r) : gp(r), type(GP) {} - constexpr GenericRegister(const XMMRegister r) : xmm(r), type(XMM) {} - - static GenericRegister fromDwarf(int dwarf_regnum); -}; - -struct Immediate { - uint64_t val; - - explicit Immediate(uint64_t val) : val(val) {} - explicit Immediate(void* val) : val((uint64_t)val) {} -}; - -struct JumpDestination { - enum OffsetType { - FROM_START, - } type; - - int offset; - - constexpr JumpDestination(OffsetType type, int offset) : type(type), offset(offset) {} - static JumpDestination fromStart(int offset) { return JumpDestination(FROM_START, offset); } -}; - -} -} - -#endif diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp deleted file mode 100644 index 2f56a2afc..000000000 --- a/src/codegen/codegen.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -#include "core/util.h" - -#include "codegen/codegen.h" - -namespace pyston { - -void FunctionAddressRegistry::registerFunction(const std::string& name, void* addr, int length, llvm::Function* llvm_func) { - assert(addr); - assert(functions.count(addr) == 0); - functions.insert(std::make_pair(addr, FuncInfo(name, length, llvm_func))); -} - -void FunctionAddressRegistry::dumpPerfMap() { - std::string out_path = "perf_map"; - removeDirectoryIfExists(out_path); - - llvm::error_code code; - code = llvm::sys::fs::create_directory(out_path, false); - assert(!code); - - FILE *index_f = fopen((out_path + "/index.txt").c_str(), "w"); - - char buf[80]; - snprintf(buf, 80, "/tmp/perf-%d.map", getpid()); - FILE *f = fopen(buf, "w"); - for (FuncMap::iterator it = functions.begin(), end = functions.end(); - it != end; ++it) { - const FuncInfo& info = it->second; - fprintf(f, "%lx %x %s\n", (uintptr_t)it->first, info.length, info.name.c_str()); - - if (info.length > 0) { - fprintf(index_f, "%lx %s\n", (uintptr_t)it->first, info.name.c_str()); - - FILE *data_f = fopen((out_path + "/" + info.name).c_str(), "wb"); - - int written = fwrite((void*)it->first, 1, info.length, data_f); - assert(written == info.length); - fclose(data_f); - } - } - fclose(f); -} - -llvm::Function* FunctionAddressRegistry::getLLVMFuncAtAddress(void* addr) { - FuncMap::iterator it = functions.find(addr); - if (it == functions.end()) { - if (lookup_neg_cache.count(addr)) - return NULL; - - bool success; - std::string name = getFuncNameAtAddress(addr, false, &success); - if (!success) { - lookup_neg_cache.insert(addr); - return NULL; - } - - llvm::Function *r = g.stdlib_module->getFunction(name); - - if (!r) { - lookup_neg_cache.insert(addr); - return NULL; - } - - registerFunction(name, addr, 0, r); - return r; - } - return it->second.llvm_func; -} - -static std::string tryDemangle(const char* s) { - int status; - char* demangled = abi::__cxa_demangle(s, NULL, NULL, &status); - if (!demangled) { - return s; - } - std::string rtn = demangled; - free(demangled); - return rtn; -} - -std::string FunctionAddressRegistry::getFuncNameAtAddress(void* addr, bool demangle, bool *out_success) { - FuncMap::iterator it = functions.find(addr); - if (it == functions.end()) { - Dl_info info; - int success = dladdr(addr, &info); - - if (success && info.dli_sname == NULL) - success = false; - - if (out_success) *out_success = success; - //if (success && info.dli_saddr == addr) { - if (success) { - if (demangle) - return tryDemangle(info.dli_sname); - return info.dli_sname; - } - - return ""; - } - - if (out_success) *out_success = true; - if (!demangle) - return it->second.name; - - return tryDemangle(it->second.name.c_str()); -} - -class RegistryEventListener : public llvm::JITEventListener { - public: - void NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - static StatCounter code_bytes("code_bytes"); - code_bytes.log(Obj.getData().size()); - - llvm::error_code code; - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E; -#if LLVMREV < 200442 - I = I.increment(code) -#else - ++I -#endif - ) { - llvm::object::section_iterator section(Obj.end_sections()); - code = I->getSection(section); - assert(!code); - bool is_text; - code = section->isText(is_text); - assert(!code); - if (!is_text) - continue; - - llvm::StringRef name; - uint64_t addr, size, offset; - code = I->getName(name); - assert(!code); - code = I->getAddress(addr); - assert(!code); - code = I->getSize(size); - assert(!code); - code = I->getFileOffset(offset); - assert(!code); - - if (name == ".text") - continue; - - //printf("%lx %lx %lx %s\n", addr, addr + size, offset, name.data()); - g.func_addr_registry.registerFunction(name.data(), (void*)addr, size, NULL); - } - } -}; - -llvm::JITEventListener* makeRegistryListener() { - return new RegistryEventListener(); -} - -} diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h deleted file mode 100644 index 96750b784..000000000 --- a/src/codegen/codegen.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_CODEGEN_H -#define PYSTON_CODEGEN_CODEGEN_H - -#include - -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" - -#include "core/types.h" - -#include "codegen/gcbuilder.h" -#include "codegen/runtime_hooks.h" - -namespace pyston { - -class PystonJITEventListener; - -class FunctionAddressRegistry { - private: - struct FuncInfo { - std::string name; - int length; - llvm::Function *llvm_func; - FuncInfo(const std::string& name, int length, llvm::Function *llvm_func) : - name(name), length(length), llvm_func(llvm_func) { - } - }; - typedef std::unordered_map FuncMap; - FuncMap functions; - std::unordered_set lookup_neg_cache; - - public: - std::string getFuncNameAtAddress(void* addr, bool demangle, bool *out_success=NULL); - llvm::Function* getLLVMFuncAtAddress(void* addr); - void registerFunction(const std::string &name, void *addr, int length, llvm::Function* llvm_func); - void dumpPerfMap(); -}; - -llvm::JITEventListener* makeRegistryListener(); -llvm::JITEventListener* makeTracebacksListener(); - -struct GlobalState { - llvm::LLVMContext &context; - llvm::Module *stdlib_module, *cur_module; - llvm::TargetMachine *tm; - llvm::ExecutionEngine *engine; - - std::vector jit_listeners; - - FunctionAddressRegistry func_addr_registry; - llvm::Type *llvm_value_type, *llvm_value_type_ptr; - llvm::Type *llvm_class_type, *llvm_class_type_ptr; - llvm::Type *llvm_flavor_type, *llvm_flavor_type_ptr; - llvm::Type *llvm_opaque_type; - llvm::Type *llvm_str_type_ptr; - llvm::Type *llvm_clfunction_type_ptr; - llvm::Type *llvm_module_type_ptr, *llvm_bool_type_ptr; - llvm::Type *i1, *i8, *i8_ptr, *i32, *i64, *void_, *double_; - - GlobalFuncs funcs; - - GlobalState() : context(llvm::getGlobalContext()) { - }; -}; - -extern GlobalState g; - -// in runtime_hooks.cpp: -void initGlobalFuncs(GlobalState &g); - -} - -#endif diff --git a/src/codegen/compvars.cpp b/src/codegen/compvars.cpp deleted file mode 100644 index b359d2b31..000000000 --- a/src/codegen/compvars.cpp +++ /dev/null @@ -1,1346 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/IR/IntrinsicInst.h" - -#include "core/options.h" -#include "core/types.h" - -#include "codegen/compvars.h" -#include "codegen/patchpoints.h" -#include "codegen/irgen.h" -#include "codegen/irgen/util.h" - -#include "runtime/objmodel.h" -#include "runtime/int.h" -#include "runtime/float.h" -#include "runtime/types.h" - -namespace pyston { - -struct RawInstanceMethod { - CompilerVariable *obj, *func; - - RawInstanceMethod(CompilerVariable *obj, CompilerVariable *func) : obj(obj), func(func) { - obj->incvref(); - func->incvref(); - } -}; - -class InstanceMethodType : public ValuedCompilerType { - private: - static std::unordered_map, InstanceMethodType*> made; - - CompilerType *obj_type, *function_type; - InstanceMethodType(CompilerType *obj_type, CompilerType *function_type) : obj_type(obj_type), function_type(function_type) { - } - - void checkVar(VAR *var) { -#ifndef NDEBUG - RawInstanceMethod *val = var->getValue(); - assert(val->obj->getType() == obj_type); - assert(val->func->getType() == function_type); -#endif - } - - public: - static InstanceMethodType* get(CompilerType* obj_type, CompilerType* function_type) { - InstanceMethodType* rtn = made[std::make_pair(obj_type, function_type)]; - if (rtn == NULL) - rtn = new InstanceMethodType(obj_type, function_type); - return rtn; - } - - static CompilerVariable* makeIM(CompilerVariable* obj, CompilerVariable* func) { - CompilerVariable* rtn = new ValuedCompilerVariable(InstanceMethodType::get(obj->getType(), func->getType()), new RawInstanceMethod(obj, func), true); - return rtn; - } - - virtual CompilerType* callType(std::vector &arg_types) { - std::vector new_args(arg_types); - new_args.insert(new_args.begin(), obj_type); - return function_type->callType(new_args); - } - - std::string debugName() { - return "instanceMethod(" + obj_type->debugName() + " ; " + function_type->debugName() + ")"; - } - virtual void drop(IREmitter &emitter, VAR *var) { - checkVar(var); - RawInstanceMethod *val = var->getValue(); - val->obj->decvref(emitter); - val->func->decvref(emitter); - delete val; - } - virtual CompilerVariable* call(IREmitter &emitter, ValuedCompilerVariable *var, const std::vector& args) { - std::vector new_args; - new_args.push_back(var->getValue()->obj); - new_args.insert(new_args.end(), args.begin(), args.end()); - return var->getValue()->func->call(emitter, new_args); - } - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - return other_type == UNKNOWN; - } - virtual ConcreteCompilerType* getConcreteType() { - return typeFromClass(instancemethod_cls); - } - virtual ConcreteCompilerType* getBoxType() { - return getConcreteType(); - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, VAR* var, ConcreteCompilerType* other_type) { - checkVar(var); - assert(other_type == UNKNOWN || other_type == typeFromClass(instancemethod_cls)); - - RawInstanceMethod *im = var->getValue(); - assert(im->obj); - assert(im->func); - ConcreteCompilerVariable *obj = im->obj->makeConverted(emitter, UNKNOWN); - ConcreteCompilerVariable *func = im->func->makeConverted(emitter, UNKNOWN); - - llvm::Value *boxed = emitter.getBuilder()->CreateCall2(g.funcs.boxInstanceMethod, obj->getValue(), func->getValue()); - - obj->decvref(emitter); - func->decvref(emitter); - - return new ConcreteCompilerVariable(other_type, boxed, true); - } - virtual CompilerVariable* dup(VAR *var, DupCache &cache) { - checkVar(var); - - CompilerVariable *rtn = cache[var]; - if (rtn == NULL) { - RawInstanceMethod *im = var->getValue(); - RawInstanceMethod *new_im = new RawInstanceMethod(im->obj->dup(cache), im->func->dup(cache)); - rtn = new VAR(this, new_im, var->isGrabbed()); - } - return rtn; - } -}; -std::unordered_map, InstanceMethodType*> InstanceMethodType::made; - -ConcreteCompilerVariable* ConcreteCompilerType::makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType* other_type) { - if (other_type == this) { - var->incvref(); - return var; - } - printf("makeConverted not defined for %s\n", debugName().c_str()); - abort(); -} -CompilerVariable* ConcreteCompilerType::dup(ConcreteCompilerVariable *v, DupCache &cache) { - auto &rtn = cache[v]; - if (rtn == NULL) { - rtn = new ConcreteCompilerVariable(this, v->getValue(), v->isGrabbed()); - while (rtn->getVrefs() < v->getVrefs()) - rtn->incvref(); - } - return rtn; -} - -class UnknownType : public ConcreteCompilerType { - public: - llvm::Type* llvmType() { return g.llvm_value_type_ptr; } - - virtual std::string debugName() { - return "AnyBox"; - } - - virtual void drop(IREmitter &emitter, VAR *var) { - emitter.getGC()->dropPointer(emitter, var->getValue()); - } - virtual void grab(IREmitter &emitter, VAR *var) { - emitter.getGC()->grabPointer(emitter, var->getValue()); - } - - virtual bool isFitBy(BoxedClass *c) { - return true; - } - - // XXX should get rid of this implementation and have it just do print o.__repr__() - virtual void print(IREmitter &emitter, ConcreteCompilerVariable *var) { - emitter.getBuilder()->CreateCall(g.funcs.print, var->getValue()); - } - - virtual CompilerVariable* getattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr); - virtual CompilerVariable* call(IREmitter &emitter, ConcreteCompilerVariable *var, const std::vector &args); - virtual CompilerVariable* callattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, bool clsonly, const std::vector &args); - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, ConcreteCompilerVariable *var); - - void setattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, CompilerVariable *v) { - llvm::Constant* ptr = getStringConstantPtr(attr + '\0'); - ConcreteCompilerVariable *converted = v->makeConverted(emitter, UNKNOWN); - //g.funcs.setattr->dump(); - //var->getValue()->dump(); llvm::errs() << '\n'; - //ptr->dump(); llvm::errs() << '\n'; - //converted->getValue()->dump(); llvm::errs() << '\n'; - bool do_patchpoint = ENABLE_ICSETATTRS && emitter.getTarget() != IREmitter::INTERPRETER; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createSetattrPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(var->getValue()); - llvm_args.push_back(ptr); - llvm_args.push_back(converted->getValue()); - - emitter.createPatchpoint(pp, (void*)pyston::setattr, llvm_args); - } else { - emitter.getBuilder()->CreateCall3(g.funcs.setattr, var->getValue(), ptr, converted->getValue()); - } - converted->decvref(emitter); - } - - virtual llvm::Value* makeClassCheck(IREmitter &emitter, ConcreteCompilerVariable *var, BoxedClass *cls) { - assert(var->getValue()->getType() == g.llvm_value_type_ptr); - // TODO this is brittle: directly embeds the position of the class object: - llvm::Value* cls_ptr = emitter.getBuilder()->CreateConstInBoundsGEP2_32(var->getValue(), 0, 1); - llvm::Value* cls_value = emitter.getBuilder()->CreateLoad(cls_ptr); - assert(cls_value->getType() == g.llvm_class_type_ptr); - llvm::Value* rtn = emitter.getBuilder()->CreateICmpEQ(cls_value, embedConstantPtr(cls, g.llvm_class_type_ptr)); - return rtn; - } - - virtual CompilerType* getattrType(const std::string &attr) { - return UNKNOWN; - } - virtual CompilerType* callType(std::vector &arg_types) { - return UNKNOWN; - } - virtual BoxedClass* guaranteedClass() { - return NULL; - } - virtual ConcreteCompilerType* getBoxType() { - return this; - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType* other_type) { - if (other_type == this) { - var->incvref(); - return var; - } - fprintf(stderr, "Can't convert unknown to %s...\n", other_type->debugName().c_str()); - abort(); - } - - virtual ConcreteCompilerVariable* len(IREmitter &emitter, ConcreteCompilerVariable *var) { - bool do_patchpoint = ENABLE_ICGENERICS && emitter.getTarget() != IREmitter::INTERPRETER; - llvm::Value* rtn; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createGenericPatchpoint(emitter.currentFunction(), true, 160); - - std::vector llvm_args; - llvm_args.push_back(var->getValue()); - - rtn = emitter.createPatchpoint(pp, (void*)pyston::unboxedLen, llvm_args); - } else { - rtn = emitter.getBuilder()->CreateCall(g.funcs.unboxedLen, var->getValue()); - } - assert(rtn->getType() == g.i64); - return new ConcreteCompilerVariable(INT, rtn, true); - } - - virtual CompilerVariable* getitem(IREmitter &emitter, ConcreteCompilerVariable *var, CompilerVariable *slice) { - ConcreteCompilerVariable *converted_slice = slice->makeConverted(emitter, slice->getBoxType()); - - bool do_patchpoint = ENABLE_ICGETITEMS && emitter.getTarget() != IREmitter::INTERPRETER; - llvm::Value *rtn; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createGetitemPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(var->getValue()); - llvm_args.push_back(converted_slice->getValue()); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, (void*)pyston::getitem, llvm_args); - rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - } else { - rtn = emitter.getBuilder()->CreateCall2(g.funcs.getitem, - var->getValue(), converted_slice->getValue()); - } - - converted_slice->decvref(emitter); - return new ConcreteCompilerVariable(UNKNOWN, rtn, true); - } -}; - -ConcreteCompilerType *UNKNOWN = new UnknownType(); - -CompilerVariable* UnknownType::getattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr) { - llvm::Constant* ptr = getStringConstantPtr(attr + '\0'); - - llvm::Value* rtn_val = NULL; - - bool do_patchpoint = ENABLE_ICGETATTRS && emitter.getTarget() != IREmitter::INTERPRETER; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createGetattrPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(var->getValue()); - llvm_args.push_back(ptr); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, (void*)pyston::getattr, llvm_args); - rtn_val = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - } else { - rtn_val = emitter.getBuilder()->CreateCall2(g.funcs.getattr, var->getValue(), ptr); - } - return new ConcreteCompilerVariable(UNKNOWN, rtn_val, true); -} - -static ConcreteCompilerVariable* _call(IREmitter &emitter, llvm::Value* func, void* func_addr, const std::vector other_args, const std::vector args, ConcreteCompilerType *rtn_type) { - std::vector guaranteed_classes; - std::vector converted_args; - for (int i = 0; i < args.size(); i++) { - converted_args.push_back(args[i]->makeConverted(emitter, args[i]->getBoxType())); - guaranteed_classes.push_back(converted_args.back()->guaranteedClass()); - } - - std::vector llvm_args; - llvm_args.insert(llvm_args.end(), other_args.begin(), other_args.end()); - - if (args.size() >= 1) { - llvm_args.push_back(converted_args[0]->getValue()); - } - if (args.size() >= 2) { - llvm_args.push_back(converted_args[1]->getValue()); - } - if (args.size() >= 3) { - llvm_args.push_back(converted_args[2]->getValue()); - } - - llvm::Value *mallocsave = NULL; - if (args.size() >= 4) { - llvm::Value *arg_array; - - if (emitter.getTarget() == IREmitter::INTERPRETER) { - llvm::Value *n_bytes = getConstantInt((args.size() - 3) * sizeof(Box*), g.i64); - mallocsave = emitter.getBuilder()->CreateCall(g.funcs.malloc, n_bytes); - arg_array = emitter.getBuilder()->CreateBitCast(mallocsave, g.llvm_value_type_ptr->getPointerTo()); - } else { - llvm::Value *n_varargs = getConstantInt(args.size() - 3, g.i64); - - // Don't use the IRBuilder since we want to specifically put this in the entry block so it only gets called once. - // TODO we could take this further and use the same alloca for all function calls? - llvm::Instruction* insertion_point = emitter.currentFunction()->func->getEntryBlock().getTerminator(); - arg_array = new llvm::AllocaInst(g.llvm_value_type_ptr, n_varargs, "arg_scratch", insertion_point); - } - - for (int i = 3; i < args.size(); i++) { - llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, i - 3); - emitter.getBuilder()->CreateStore(converted_args[i]->getValue(), ptr); - } - llvm_args.push_back(arg_array); - } - - //f->dump(); - //for (int i = 0; i < llvm_args.size(); i++) { - //llvm_args[i]->dump(); - //llvm::errs() << '\n'; - //} - - llvm::Value* rtn; - - bool do_patchpoint = ENABLE_ICCALLSITES && emitter.getTarget() != IREmitter::INTERPRETER && (func_addr == runtimeCall || func_addr == pyston::callattr); - if (do_patchpoint) { - assert(func_addr); - - PatchpointSetupInfo *pp = patchpoints::createCallsitePatchpoint(emitter.currentFunction(), args.size()); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, func_addr, llvm_args); - - assert(llvm::cast(llvm::cast(func->getType())->getElementType())->getReturnType() == g.llvm_value_type_ptr); - rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - } else { - //func->dump(); - //for (auto a : llvm_args) { - //a->dump(); - //} - //printf("%ld %ld\n", llvm_args.size(), args.size()); - rtn = emitter.getBuilder()->CreateCall(func, llvm_args); - } - - if (mallocsave) { - llvm::Value *l_free = embedConstantPtr((void*)free, llvm::FunctionType::get(g.void_, g.i8->getPointerTo(), false)->getPointerTo()); - emitter.getBuilder()->CreateCall(l_free, mallocsave); - } - - for (int i = 0; i < args.size(); i++) { - converted_args[i]->decvref(emitter); - } - - assert(rtn->getType() == rtn_type->llvmType()); - return new ConcreteCompilerVariable(rtn_type, rtn, true); -} - -CompilerVariable* UnknownType::call(IREmitter &emitter, ConcreteCompilerVariable *var, const std::vector &args) { - llvm::Value* func; - if (args.size() == 0) - func = g.funcs.runtimeCall0; - else if (args.size() == 1) - func = g.funcs.runtimeCall1; - else if (args.size() == 2) - func = g.funcs.runtimeCall2; - else if (args.size() == 3) - func = g.funcs.runtimeCall3; - else - func = g.funcs.runtimeCall; - - std::vector other_args; - other_args.push_back(var->getValue()); - - llvm::Value *nargs = llvm::ConstantInt::get(g.i64, args.size(), false); - other_args.push_back(nargs); - return _call(emitter, func, (void*)runtimeCall, other_args, args, UNKNOWN); -} - -CompilerVariable* UnknownType::callattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, bool clsonly, const std::vector &args) { - llvm::Value* func; - if (args.size() == 0) - func = g.funcs.callattr0; - else if (args.size() == 1) - func = g.funcs.callattr1; - else if (args.size() == 2) - func = g.funcs.callattr2; - else if (args.size() == 3) - func = g.funcs.callattr3; - else - func = g.funcs.callattr; - - std::vector other_args; - other_args.push_back(var->getValue()); - other_args.push_back(embedConstantPtr(&attr, g.llvm_str_type_ptr)); - other_args.push_back(getConstantInt(clsonly, g.i1)); - - llvm::Value *nargs = llvm::ConstantInt::get(g.i64, args.size(), false); - other_args.push_back(nargs); - return _call(emitter, func, (void*)pyston::callattr, other_args, args, UNKNOWN); -} - -ConcreteCompilerVariable* UnknownType::nonzero(IREmitter &emitter, ConcreteCompilerVariable *var) { - bool do_patchpoint = ENABLE_ICNONZEROS && emitter.getTarget() != IREmitter::INTERPRETER; - llvm::Value* rtn_val; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createNonzeroPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(var->getValue()); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, (void*)pyston::nonzero, llvm_args); - rtn_val = emitter.getBuilder()->CreateTrunc(uncasted, g.i1); - } else { - rtn_val = emitter.getBuilder()->CreateCall(g.funcs.nonzero, var->getValue()); - } - return new ConcreteCompilerVariable(BOOL, rtn_val, true); -} - -CompilerVariable* makeFunction(IREmitter &emitter, CLFunction *f) { - // Unlike the CLFunction*, which can be shared between recompilations, the Box* around it - // should be created anew every time the functiondef is encountered - llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxCLFunction, embedConstantPtr(f, g.llvm_clfunction_type_ptr)); - return new ConcreteCompilerVariable(typeFromClass(function_cls), boxed, true); -} - -class AbstractFunctionType : public CompilerType { - public: - struct Sig { - std::vector arg_types; - CompilerType* rtn_type; - }; - - private: - std::vector sigs; - AbstractFunctionType(const std::vector &sigs) : sigs(sigs) { - } - public: - virtual std::string debugName() { - return ""; - } - - virtual ConcreteCompilerType* getConcreteType() { - return UNKNOWN; - } - - virtual ConcreteCompilerType* getBoxType() { - return UNKNOWN; - } - - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - return other_type == UNKNOWN; - } - - virtual CompilerType* getattrType(const std::string &attr) { - return UNDEF; - } - - virtual CompilerType* callType(std::vector &arg_types) { - for (int i = 0; i < sigs.size(); i++) { - Sig* sig = sigs[i]; - if (sig->arg_types.size() != arg_types.size()) - continue; - - bool works = true; - for (int j = 0; j < sig->arg_types.size(); j++) { - if (!arg_types[j]->canConvertTo(sig->arg_types[j])) { - works = false; - break; - } - } - - if (!works) - continue; - - return sig->rtn_type; - } - return UNDEF; - } - - virtual BoxedClass* guaranteedClass() { - return NULL; - } - - static CompilerType* fromRT(BoxedFunction* rtfunc, bool stripfirst) { - std::vector sigs; - CLFunction *clf = rtfunc->f; - - for (int i = 0; i < clf->versions.size(); i++) { - CompiledFunction *cf = clf->versions[i]; - - FunctionSignature *fsig = cf->sig; - - Sig* type_sig = new Sig(); - type_sig->rtn_type = fsig->rtn_type; - - if (stripfirst) { - assert(fsig->arg_types.size() >= 1); - type_sig->arg_types.insert(type_sig->arg_types.end(), fsig->arg_types.begin()+1, fsig->arg_types.end()); - } else { - type_sig->arg_types.insert(type_sig->arg_types.end(), fsig->arg_types.begin(), fsig->arg_types.end()); - } - sigs.push_back(type_sig); - } - return get(sigs); - } - - static CompilerType* get(const std::vector &sigs) { - return new AbstractFunctionType(sigs); - } -}; - -class IntType : public ConcreteCompilerType { - public: - IntType() {} - - llvm::Type* llvmType() { return g.i64; } - - virtual bool isFitBy(BoxedClass *c) { - return false; - } - - virtual void drop(IREmitter &emitter, ConcreteCompilerVariable *var) { - // pass - } - virtual void grab(IREmitter &emitter, ConcreteCompilerVariable *var) { - // pass - } - - virtual void print(IREmitter &emitter, ConcreteCompilerVariable *var) { - assert(var->getValue()->getType() == g.i64); - - llvm::Constant* int_fmt = getStringConstantPtr("%ld");; - emitter.getBuilder()->CreateCall2(g.funcs.printf, int_fmt, var->getValue()); - } - - virtual CompilerType* getattrType(const std::string &attr) { - static std::vector sigs; - if (sigs.size() == 0) { - AbstractFunctionType::Sig *int_sig = new AbstractFunctionType::Sig(); - int_sig->rtn_type = INT; - int_sig->arg_types.push_back(INT); - sigs.push_back(int_sig); - - AbstractFunctionType::Sig *unknown_sig = new AbstractFunctionType::Sig(); - unknown_sig->rtn_type = UNKNOWN; - unknown_sig->arg_types.push_back(UNKNOWN); - sigs.push_back(unknown_sig); - } - - if (attr == "__add__" || attr == "__sub__" || attr == "__mod__" || attr == "__mul__" || attr == "__lshift__" || attr == "__rshift__" || attr == "__div__" || attr == "__pow__" || attr == "__floordiv__" || attr == "__and__" || attr == "__or__" || attr == "__xor__") { - return AbstractFunctionType::get(sigs); - } - - return BOXED_INT->getattrType(attr); - } - - virtual CompilerVariable* callattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, bool clsonly, const std::vector& args) { - ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); - CompilerVariable* rtn = converted->callattr(emitter, attr, clsonly, args); - converted->decvref(emitter); - return rtn; - } - - virtual CompilerVariable* getattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr) { - ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); - CompilerVariable* rtn = converted->getattr(emitter, attr); - converted->decvref(emitter); - return rtn; - } - - virtual void setattr(IREmitter &emitter, VAR* var, const std::string &attr, CompilerVariable *v) { - llvm::CallInst *call = emitter.getBuilder()->CreateCall2(g.funcs.raiseAttributeErrorStr, getStringConstantPtr("int\0"), getStringConstantPtr(attr + '\0')); - call->setDoesNotReturn(); - } - - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType* other_type) { - if (other_type == this) { - var->incvref(); - return var; - } else if (other_type == UNKNOWN || other_type == BOXED_INT) { - llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxInt, var->getValue()); - return new ConcreteCompilerVariable(other_type, boxed, true); - } else { - printf("Don't know how to convert i64 to %s\n", other_type->debugName().c_str()); - abort(); - } - } - - virtual CompilerVariable *getitem(IREmitter &emitter, VAR *var, CompilerVariable *slice) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, BOXED_INT); - CompilerVariable *rtn = converted->getitem(emitter, slice); - converted->decvref(emitter); - return rtn; - } - - virtual ConcreteCompilerVariable* len(IREmitter &emitter, VAR *var) { - llvm::CallInst* call = emitter.getBuilder()->CreateCall(g.funcs.raiseNotIterableError, getStringConstantPtr("int")); - call->setDoesNotReturn(); - return new ConcreteCompilerVariable(INT, llvm::UndefValue::get(g.i64), true); - } - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, ConcreteCompilerVariable *var) { - llvm::Value *cmp = emitter.getBuilder()->CreateICmpNE(var->getValue(), llvm::ConstantInt::get(g.i64, 0, false)); - return new ConcreteCompilerVariable(BOOL, cmp, true); - } - - virtual ConcreteCompilerType* getBoxType() { - return BOXED_INT; - } -} _INT; -ConcreteCompilerType *INT = &_INT; - -CompilerVariable* makeInt(int64_t n) { - return new ConcreteCompilerVariable(INT, llvm::ConstantInt::get(g.i64, n, true), true); -} - -class FloatType : public ConcreteCompilerType { - public: - FloatType() {} - - llvm::Type* llvmType() { return g.double_; } - - virtual bool isFitBy(BoxedClass *c) { - return false; - } - - virtual void drop(IREmitter &emitter, ConcreteCompilerVariable *var) { - // pass - } - virtual void grab(IREmitter &emitter, ConcreteCompilerVariable *var) { - // pass - } - - virtual void print(IREmitter &emitter, ConcreteCompilerVariable *var) { - assert(var->getValue()->getType() == g.double_); - - emitter.getBuilder()->CreateCall(g.funcs.printFloat, var->getValue()); - } - - virtual CompilerType* getattrType(const std::string &attr) { - static std::vector sigs; - if (sigs.size() == 0) { - AbstractFunctionType::Sig *float_sig = new AbstractFunctionType::Sig(); - float_sig->rtn_type = FLOAT; - float_sig->arg_types.push_back(FLOAT); - sigs.push_back(float_sig); - - AbstractFunctionType::Sig *int_sig = new AbstractFunctionType::Sig(); - int_sig->rtn_type = FLOAT; - int_sig->arg_types.push_back(INT); - sigs.push_back(int_sig); - - AbstractFunctionType::Sig *unknown_sig = new AbstractFunctionType::Sig(); - unknown_sig->rtn_type = UNKNOWN; - unknown_sig->arg_types.push_back(UNKNOWN); - sigs.push_back(unknown_sig); - } - - if (attr == "__add__" || attr == "__sub__" || attr == "__mul__" || attr == "__div__" || attr == "__pow__" || attr == "__floordiv__" || attr == "__mod__" || attr == "__pow__") { - return AbstractFunctionType::get(sigs); - } - - return BOXED_FLOAT->getattrType(attr); - } - - virtual CompilerVariable* getattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr) { - ConcreteCompilerVariable* converted = var->makeConverted(emitter, BOXED_INT); - CompilerVariable* rtn = converted->getattr(emitter, attr); - converted->decvref(emitter); - return rtn; - } - - virtual void setattr(IREmitter &emitter, VAR* var, const std::string &attr, CompilerVariable *v) { - llvm::CallInst* call = emitter.getBuilder()->CreateCall2(g.funcs.raiseAttributeErrorStr, getStringConstantPtr("float\0"), getStringConstantPtr(attr + '\0')); - call->setDoesNotReturn(); - } - - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType* other_type) { - if (other_type == this) { - var->incvref(); - return var; - } else if (other_type == UNKNOWN || other_type == BOXED_FLOAT) { - llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxFloat, var->getValue()); - return new ConcreteCompilerVariable(other_type, boxed, true); - } else { - printf("Don't know how to convert float to %s\n", other_type->debugName().c_str()); - abort(); - } - } - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, ConcreteCompilerVariable *var) { - llvm::Value *cmp = emitter.getBuilder()->CreateFCmpUNE(var->getValue(), llvm::ConstantFP::get(g.double_, 0)); - return new ConcreteCompilerVariable(BOOL, cmp, true); - } - virtual ConcreteCompilerType* getBoxType() { - return BOXED_FLOAT; - } -} _FLOAT; -ConcreteCompilerType *FLOAT = &_FLOAT; - -CompilerVariable* makeFloat(double d) { - return new ConcreteCompilerVariable(FLOAT, llvm::ConstantFP::get(g.double_, d), true); -} - -class KnownClassobjType : public ValuedCompilerType { - private: - BoxedClass *cls; - - static std::unordered_map made; - - KnownClassobjType(BoxedClass *cls) : cls(cls) { - assert(cls); - } - - public: - virtual std::string debugName() { - return "class '" + *getNameOfClass(cls) + "'"; - } - - static KnownClassobjType* fromClass(BoxedClass* cls) { - KnownClassobjType* &rtn = made[cls]; - if (rtn == NULL) { - rtn = new KnownClassobjType(cls); - } - return rtn; - } - - virtual CompilerType* callType(std::vector &arg_types) { - bool is_well_defined = (cls == xrange_cls); - assert(is_well_defined); - return typeFromClass(cls); - } -}; -std::unordered_map KnownClassobjType::made; - -CompilerType* typeOfClassobj(BoxedClass* cls) { - return KnownClassobjType::fromClass(cls); -} - - -class NormalObjectType : public ConcreteCompilerType { - private: - BoxedClass *cls; - - static std::unordered_map made; - - NormalObjectType(BoxedClass *cls) : cls(cls) { - //ASSERT(!isUserDefined(cls) && "instances of user-defined classes can change their __class__, plus even if they couldn't we couldn't statically resolve their attributes", "%s", getNameOfClass(cls)->c_str()); - - assert(cls); - } - - public: - llvm::Type* llvmType() { - return g.llvm_value_type_ptr; - } - std::string debugName() { - assert(cls); - // TODO add getTypeName - - return "NormalType(" + *getNameOfClass(cls) + ")"; - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType* other_type) { - if (other_type == this) { - var->incvref(); - return var; - } - assert(other_type == UNKNOWN); - return new ConcreteCompilerVariable(UNKNOWN, var->getValue(), false); - //return (new ConcreteCompilerVariable(UNKNOWN, var->getValue(), false))->split(emitter); - } - - virtual void drop(IREmitter &emitter, VAR *var) { - emitter.getGC()->dropPointer(emitter, var->getValue()); - } - virtual void grab(IREmitter &emitter, VAR *var) { - emitter.getGC()->grabPointer(emitter, var->getValue()); - } - - virtual bool isFitBy(BoxedClass *c) { - return c == cls; - } - - virtual CompilerType* getattrType(const std::string &attr) { - if (cls->is_constant && !cls->hasattrs) { - Box* rtattr = cls->peekattr(attr); - if (rtattr == NULL) - return UNDEF; - - RELEASE_ASSERT(rtattr, "%s.%s", debugName().c_str(), attr.c_str()); - if (rtattr->cls == function_cls) { - return AbstractFunctionType::fromRT(static_cast(rtattr), true); - //return typeFromClass(instancemethod_cls); - } else { - return typeFromClass(rtattr->cls); - } - } - - return UNKNOWN; - } - virtual CompilerType* callType(std::vector &arg_types) { - return UNKNOWN; - } - - CompilerVariable* getattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr) { - //printf("%s.getattr %s\n", debugName().c_str(), attr.c_str()); - if (cls->is_constant && !cls->hasattrs) { - Box* rtattr = cls->peekattr(attr); - if (rtattr == NULL) { - llvm::CallInst *call = emitter.getBuilder()->CreateCall2(g.funcs.raiseAttributeErrorStr, getStringConstantPtr(*getNameOfClass(cls) + "\0"), getStringConstantPtr(attr + '\0')); - call->setDoesNotReturn(); - return undefVariable(); - } - - ASSERT(rtattr, "%s.%s", debugName().c_str(), attr.c_str()); - if (rtattr->cls == function_cls) { - CompilerVariable* clattr = new ConcreteCompilerVariable(typeFromClass(function_cls), embedConstantPtr(rtattr, g.llvm_value_type_ptr), false); - return InstanceMethodType::makeIM(var, clattr); - } - } - - // TODO could specialize more since we know the class already - return UNKNOWN->getattr(emitter, var, attr); - } - - void setattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, CompilerVariable *v) { - return UNKNOWN->setattr(emitter, var, attr, v); - } - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, ConcreteCompilerVariable *var) { - if (cls == bool_cls) { - llvm::Value *unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxBool, var->getValue()); - assert(unboxed->getType() == g.i1); - return new ConcreteCompilerVariable(BOOL, unboxed, true); - } - - ConcreteCompilerVariable *converted = var->makeConverted(emitter, UNKNOWN); - ConcreteCompilerVariable *rtn = converted->nonzero(emitter); - converted->decvref(emitter); - return rtn; - } - - virtual void print(IREmitter &emitter, ConcreteCompilerVariable *var) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, UNKNOWN); - converted->print(emitter); - converted->decvref(emitter); - } - - virtual CompilerVariable* getitem(IREmitter &emitter, ConcreteCompilerVariable *var, CompilerVariable *slice) { - return UNKNOWN->getitem(emitter, var, slice); - } - - virtual ConcreteCompilerVariable* len(IREmitter &emitter, ConcreteCompilerVariable *var) { - return UNKNOWN->len(emitter, var); - } - - virtual CompilerVariable* call(IREmitter &emitter, ConcreteCompilerVariable *var, const std::vector& args) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, UNKNOWN); - CompilerVariable *rtn = converted->call(emitter, args); - converted->decvref(emitter); - return rtn; - } - - virtual CompilerVariable* callattr(IREmitter &emitter, ConcreteCompilerVariable *var, const std::string &attr, bool clsonly, const std::vector& args) { - if (cls->is_constant && !cls->hasattrs) { - Box* rtattr = cls->peekattr(attr); - if (rtattr == NULL) { - llvm::CallInst *call = emitter.getBuilder()->CreateCall2(g.funcs.raiseAttributeErrorStr, getStringConstantPtr(debugName() + '\0'), getStringConstantPtr(attr + '\0')); - call->setDoesNotReturn(); - return undefVariable(); - } - - if (rtattr->cls == function_cls) { - CLFunction *cl = unboxRTFunction(rtattr); - assert(cl); - - CompiledFunction *cf = NULL; - int nsig_args = 0; - bool found = false; - // TODO have to find the right version.. similar to resolveclfunc? - for (int i = 0; i < cl->versions.size(); i++) { - cf = cl->versions[i]; - nsig_args = cf->sig->arg_types.size(); - if (nsig_args != args.size() + 1) { - continue; - } - - bool fits = true; - for (int j = 1; j < nsig_args; j++) { - //if (cf->sig->arg_types[j] != UNKNOWN) { - //if (cf->sig->arg_types[j]->isFitBy(args[j-1]->guaranteedClass())) { - if (!args[j-1]->canConvertTo(cf->sig->arg_types[j])) { - printf("Can't use version %d since arg %d (%s) doesn't fit into sig arg of %s\n", i, j, args[j-1]->getType()->debugName().c_str(), cf->sig->arg_types[j]->debugName().c_str()); - fits = false; - break; - } - } - if (!fits) - continue; - - found = true; - break; - } - - assert(found); - assert(nsig_args == args.size() + 1); - assert(!cf->is_interpreted); - assert(cf->code); - - std::vector arg_types; - for (int i = 0; i < nsig_args; i++) { - // TODO support passing unboxed values as arguments - assert(cf->sig->arg_types[i]->llvmType() == g.llvm_value_type_ptr); - - arg_types.push_back(g.llvm_value_type_ptr); - if (i == 3) { - arg_types.push_back(g.llvm_value_type_ptr->getPointerTo()); - break; - } - } - llvm::FunctionType *ft = llvm::FunctionType::get(cf->sig->rtn_type->llvmType(), arg_types, false); - - llvm::Value *linked_function = embedConstantPtr(cf->code, ft->getPointerTo()); - - std::vector new_args; - new_args.push_back(var); - new_args.insert(new_args.end(), args.begin(), args.end()); - - std::vector other_args; - - ConcreteCompilerVariable* rtn = _call(emitter, linked_function, cf->code, other_args, new_args, cf->sig->rtn_type); - assert(rtn->getType() == cf->sig->rtn_type); - - assert(cf->sig->rtn_type != BOXED_INT); - ASSERT(cf->sig->rtn_type != BOXED_BOOL, "%p", cf->code); - assert(cf->sig->rtn_type != BOXED_FLOAT); - - return rtn; - } - } - - ConcreteCompilerVariable *converted = var->makeConverted(emitter, UNKNOWN); - CompilerVariable *rtn = converted->callattr(emitter, attr, clsonly, args); - converted->decvref(emitter); - return rtn; - } - - static NormalObjectType* fromClass(BoxedClass* cls) { - NormalObjectType* &rtn = made[cls]; - if (rtn == NULL) { - rtn = new NormalObjectType(cls); - } - return rtn; - } - - virtual BoxedClass* guaranteedClass() { - return cls; - } - - virtual ConcreteCompilerType* getBoxType() { - return this; - } -}; -std::unordered_map NormalObjectType::made; -ConcreteCompilerType *STR, *BOXED_INT, *BOXED_FLOAT, *BOXED_BOOL, *NONE; - -class StrConstantType : public ValuedCompilerType { - public: - std::string debugName() { - return "str_constant"; - } - virtual ConcreteCompilerType* getConcreteType() { - return STR; - } - virtual ConcreteCompilerType* getBoxType() { - return STR; - } - virtual void drop(IREmitter &emitter, VAR *var) { - // pass - } - virtual void grab(IREmitter &emitter, VAR *var) { - // pass - } - virtual void print(IREmitter &emitter, ValuedCompilerVariable *value) { - llvm::Constant* ptr = getStringConstantPtr(*(value->getValue()) + '\0'); - llvm::Constant* fmt = getStringConstantPtr("%s\0"); - emitter.getBuilder()->CreateCall2(g.funcs.printf, fmt, ptr); - } - - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ValuedCompilerVariable *var, ConcreteCompilerType* other_type) { - assert(other_type == STR || other_type == UNKNOWN); - llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxStringPtr, embedConstantPtr(var->getValue(), g.llvm_str_type_ptr)); - return new ConcreteCompilerVariable(other_type, boxed, true); - } - - virtual bool canConvertTo(ConcreteCompilerType *other) { - return (other == STR || other == UNKNOWN); - } - - virtual CompilerVariable *getattr(IREmitter &emitter, VAR *var, const std::string &attr) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, STR); - CompilerVariable *rtn = converted->getattr(emitter, attr); - converted->decvref(emitter); - return rtn; - } - - virtual CompilerVariable* callattr(IREmitter &emitter, VAR *var, const std::string &attr, bool clsonly, const std::vector &args) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, STR); - CompilerVariable *rtn = converted->callattr(emitter, attr, clsonly, args); - converted->decvref(emitter); - return rtn; - } - - virtual CompilerVariable *getitem(IREmitter &emitter, VAR *var, CompilerVariable *slice) { - ConcreteCompilerVariable *converted = var->makeConverted(emitter, STR); - CompilerVariable *rtn = converted->getitem(emitter, slice); - converted->decvref(emitter); - return rtn; - } - -}; -ValuedCompilerType *STR_CONSTANT = new StrConstantType(); - -CompilerVariable* makeStr(std::string *s) { - return new ValuedCompilerVariable(STR_CONSTANT, s, true); -} - -class VoidType : public ConcreteCompilerType { - public: - llvm::Type* llvmType() { return g.void_; } -}; -ConcreteCompilerType *VOID = new VoidType(); - -ConcreteCompilerType* typeFromClass(BoxedClass* c) { - assert(c); - return NormalObjectType::fromClass(c); -} - -class BoolType : public ConcreteCompilerType { - public: - llvm::Type* llvmType() { return g.i1; } - - virtual bool isFitBy(BoxedClass *c) { - return false; - } - - virtual void drop(IREmitter &emitter, VAR *var) { - // pass - } - virtual void grab(IREmitter &emitter, VAR *var) { - // pass - } - virtual void print(IREmitter &emitter, ConcreteCompilerVariable *var) { - assert(var->getValue()->getType() == g.i1); - - llvm::Value* true_str = getStringConstantPtr("True"); - llvm::Value* false_str = getStringConstantPtr("False"); - llvm::Value* selected = emitter.getBuilder()->CreateSelect(var->getValue(), true_str, false_str); - emitter.getBuilder()->CreateCall(g.funcs.printf, selected); - } - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, ConcreteCompilerVariable *var) { - var->incvref(); - return var; - } - - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable *var, ConcreteCompilerType *other_type) { - if (other_type == BOOL) { - var->incvref(); - return var; - } - - ASSERT(other_type == UNKNOWN || other_type == BOXED_BOOL, "%s", other_type->debugName().c_str()); - llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxBool, var->getValue()); - return new ConcreteCompilerVariable(other_type, boxed, true); - } - - virtual ConcreteCompilerType* getBoxType() { - return BOXED_BOOL; - } -}; -ConcreteCompilerType *BOOL = new BoolType(); -CompilerVariable* makeBool(bool b) { - return new ConcreteCompilerVariable(BOOL, llvm::ConstantInt::get(g.i1, b, false), true); -} - -ConcreteCompilerType *BOXED_TUPLE; -class TupleType : public ValuedCompilerType*> { - private: - std::string name; - const std::vector elt_types; - - TupleType(const std::vector &elt_types) : elt_types(elt_types) { - std::ostringstream os(""); - os << "tuple("; - for (int i = 0; i < elt_types.size(); i++) { - if (i) os << ", "; - os << elt_types[i]->debugName(); - } - os << ")"; - name = os.str(); - } - public: - typedef const std::vector VEC; - - std::string debugName() { - return name; - } - - virtual void drop(IREmitter &emitter, VAR *var) { - const std::vector *elts = var->getValue(); - for (int i = 0; i < elts->size(); i++) { - (*elts)[i]->decvref(emitter); - } - } - - virtual void grab(IREmitter &emitter, VAR *var) { - RELEASE_ASSERT(0, ""); - } - - virtual CompilerVariable* dup(VAR *var, DupCache &cache) { - CompilerVariable* &rtn = cache[var]; - - if (rtn == NULL) { - std::vector *elts = new std::vector(); - const std::vector *orig_elts = var->getValue(); - - for (int i = 0; i < orig_elts->size(); i++) { - elts->push_back((*orig_elts)[i]->dup(cache)); - } - rtn = new VAR(this, elts, var->isGrabbed()); - } - return rtn; - } - - virtual void print(IREmitter &emitter, VAR *var) { - llvm::Constant* open_paren = getStringConstantPtr("("); - llvm::Constant* close_paren = getStringConstantPtr(")"); - llvm::Constant* comma = getStringConstantPtr(","); - llvm::Constant* comma_space = getStringConstantPtr(", "); - - VEC* v = var->getValue(); - - emitter.getBuilder()->CreateCall(g.funcs.printf, open_paren); - - for (int i = 0; i < v->size(); i++) { - if (i) emitter.getBuilder()->CreateCall(g.funcs.printf, comma_space); - (*v)[i]->print(emitter); - } - if (v->size() == 1) - emitter.getBuilder()->CreateCall(g.funcs.printf, comma); - - emitter.getBuilder()->CreateCall(g.funcs.printf, close_paren); - } - - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - return (other_type == UNKNOWN || other_type == BOXED_TUPLE); - } - - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, VAR* var, ConcreteCompilerType* other_type) { - assert(other_type == UNKNOWN || other_type == BOXED_TUPLE); - - VEC* v = var->getValue(); - - std::vector converted_args; - - llvm::Value *nelts = llvm::ConstantInt::get(g.i64, v->size(), false); - llvm::Value *alloca = emitter.getBuilder()->CreateAlloca(g.llvm_value_type_ptr, nelts); - for (int i = 0; i < v->size(); i++) { - llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(alloca, i); - ConcreteCompilerVariable* converted = (*v)[i]->makeConverted(emitter, (*v)[i]->getBoxType()); - converted_args.push_back(converted); - emitter.getBuilder()->CreateStore(converted->getValue(), ptr); - } - - llvm::Value* rtn = emitter.getBuilder()->CreateCall2(g.funcs.createTuple, nelts, alloca); - - for (int i = 0; i < converted_args.size(); i++) { - converted_args[i]->decvref(emitter); - } - return new ConcreteCompilerVariable(other_type, rtn, true); - } - - virtual ConcreteCompilerType* getBoxType() { - return BOXED_TUPLE; - } - - virtual ConcreteCompilerType* getConcreteType() { - return BOXED_TUPLE; - } - - static TupleType* make(const std::vector &elt_types) { - return new TupleType(elt_types); - } - - virtual CompilerVariable* getitem(IREmitter &emitter, VAR *var, CompilerVariable *slice) { - if (slice->getType() == INT) { - llvm::Value* v = static_cast(slice)->getValue(); - assert(v->getType() == g.i64); - if (llvm::ConstantInt *ci = llvm::dyn_cast(v)) { - int64_t i = ci->getSExtValue(); - if (i >= 0 && i < var->getValue()->size()) { - CompilerVariable *rtn = (*var->getValue())[i]; - rtn->incvref(); - return rtn; - } else { - llvm::CallInst *call = emitter.getBuilder()->CreateCall2(g.funcs.raiseAttributeErrorStr, getStringConstantPtr(debugName() + '\0'), getStringConstantPtr("__getitem__\0")); - call->setDoesNotReturn(); - return undefVariable(); - } - } - } - RELEASE_ASSERT(0, ""); - //return getConstantInt(var->getValue()->size(), g.i64); - } - - virtual ConcreteCompilerVariable* len(IREmitter &emitter, VAR *var) { - return new ConcreteCompilerVariable(INT, getConstantInt(var->getValue()->size(), g.i64), true); - } - - virtual CompilerType* getattrType(const std::string &attr) { - return BOXED_TUPLE->getattrType(attr); - } -}; - -CompilerType* makeTupleType(const std::vector &elt_types) { - return TupleType::make(elt_types); -} - -CompilerVariable* makeTuple(const std::vector &elts) { - std::vector elt_types; - for (int i = 0; i < elts.size(); i++) { - elts[i]->incvref(); - elt_types.push_back(elts[i]->getType()); - } - TupleType *type = TupleType::make(elt_types); - - const std::vector *alloc_elts = new std::vector(elts); - return new TupleType::VAR(type, alloc_elts, true); -} - -class UndefType : public ConcreteCompilerType { - public: - std::string debugName() { - return "undefType"; - } - - llvm::Type* llvmType() override { - // Something that no one else uses... - // TODO should do something more rare like a unique custom struct - return llvm::Type::getInt16Ty(g.context); - } - - virtual CompilerVariable* call(IREmitter &emitter, VAR *var, const std::vector& args) { - return undefVariable(); - } - virtual void drop(IREmitter &emitter, VAR *var) {} - virtual void grab(IREmitter &emitter, VAR *var) {} - virtual CompilerVariable* dup(VAR *v, DupCache &cache) { - // TODO copied from UnknownType - auto &rtn = cache[v]; - if (rtn == NULL) { - rtn = new VAR(this, v->getValue(), v->isGrabbed()); - while (rtn->getVrefs() < v->getVrefs()) - rtn->incvref(); - } - return rtn; - } - virtual void print(IREmitter &emitter, VAR *var) {} - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, VAR* var, ConcreteCompilerType* other_type) { - llvm::Value *v = llvm::UndefValue::get(other_type->llvmType()); - return new ConcreteCompilerVariable(other_type, v, true); - } - virtual CompilerVariable* getattr(IREmitter &emitter, VAR* var, const std::string &attr) { - return undefVariable(); - } - - virtual CompilerVariable* callattr(IREmitter &emitter, VAR *var, const std::string &attr, bool clsonly, const std::vector& args) { - return undefVariable(); - } - - virtual CompilerType* callType(std::vector &arg_types) { - return UNDEF; - } - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, VAR *var) { - return new ConcreteCompilerVariable(BOOL, llvm::UndefValue::get(g.i1), true); - } - - virtual ConcreteCompilerType* getBoxType() { - return UNKNOWN; - } - - virtual ConcreteCompilerType* getConcreteType() { - return this; - } - - virtual CompilerType* getattrType(const std::string &attr) { - return UNDEF; - } - - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - return true; - } - - virtual BoxedClass* guaranteedClass() { - return NULL; - } -} _UNDEF; -CompilerType *UNDEF = &_UNDEF; - -CompilerVariable* undefVariable() { - return new ConcreteCompilerVariable(&_UNDEF, llvm::UndefValue::get(_UNDEF.llvmType()), true); -} - - -ConcreteCompilerType *LIST, *SLICE, *MODULE, *DICT; - -} // namespace pyston diff --git a/src/codegen/compvars.h b/src/codegen/compvars.h deleted file mode 100644 index 17d24b3ca..000000000 --- a/src/codegen/compvars.h +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_COMPVARS_H -#define PYSTON_CODEGEN_COMPVARS_H - -#include -#include - -#include "llvm/Support/raw_ostream.h" - -#include "core/types.h" - -#include "codegen/codegen.h" - -namespace pyston { - -class CompilerType; - -extern ConcreteCompilerType *INT, *BOXED_INT, *FLOAT, *BOXED_FLOAT, *VOID, *UNKNOWN, *BOOL, *STR, *NONE, *LIST, *SLICE, *MODULE, *DICT, *BOOL, *BOXED_BOOL, *BOXED_TUPLE; -extern CompilerType* UNDEF; - -class CompilerType { - public: - virtual std::string debugName() = 0; - virtual ConcreteCompilerType* getConcreteType() = 0; - virtual ConcreteCompilerType* getBoxType() = 0; - virtual bool canConvertTo(ConcreteCompilerType* other_type) = 0; - virtual CompilerType* getattrType(const std::string &attr) = 0; - virtual CompilerType* callType(std::vector &arg_types) = 0; - virtual BoxedClass* guaranteedClass() = 0; -}; - -typedef std::unordered_map DupCache; - -template -class _ValuedCompilerType : public CompilerType { - public: - typedef ValuedCompilerVariable VAR; - - virtual CompilerVariable* dup(VAR *v, DupCache &cache) { - printf("dup not defined for %s\n", debugName().c_str()); - abort(); - } - virtual ConcreteCompilerType* getConcreteType() { - printf("getConcreteType not defined for %s\n", debugName().c_str()); - abort(); - } - virtual ConcreteCompilerType* getBoxType() { - printf("getBoxType not defined for %s\n", debugName().c_str()); - abort(); - } - virtual void drop(IREmitter &emmitter, VAR* value) { - printf("drop not defined for %s\n", debugName().c_str()); - abort(); - } - virtual void grab(IREmitter &emmitter, VAR* value) { - printf("grab not defined for %s\n", debugName().c_str()); - abort(); - } - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - printf("canConvertTo not defined for %s\n", debugName().c_str()); - abort(); - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, VAR* value, ConcreteCompilerType* other_type) { - printf("makeConverted not defined for %s\n", debugName().c_str()); - abort(); - } - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter, VAR* value) { - printf("nonzero not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerVariable* getattr(IREmitter &emitter, VAR* value, const std::string &attr) { - printf("getattr not defined for %s\n", debugName().c_str()); - abort(); - } - virtual void setattr(IREmitter &emitter, VAR* value, const std::string &attr, CompilerVariable *v) { - printf("setattr not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerVariable* callattr(IREmitter &emitter, VAR* value, const std::string &attr, bool clsonly, const std::vector& args) { - printf("callattr not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerVariable* call(IREmitter &emitter, VAR* value, const std::vector& args) { - printf("call not defined for %s\n", debugName().c_str()); - abort(); - } - virtual void print(IREmitter &emitter, VAR* value) { - printf("print not defined for %s\n", debugName().c_str()); - abort(); - } - virtual ConcreteCompilerVariable* len(IREmitter &emitter, VAR* value) { - printf("len not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerVariable* getitem(IREmitter &emitter, VAR* value, CompilerVariable *v) { - printf("getitem not defined for %s\n", debugName().c_str()); - abort(); - } - virtual llvm::Value* makeClassCheck(IREmitter &emitter, VAR* value, BoxedClass* c) { - printf("makeClassCheck not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerType* getattrType(const std::string &attr) { - printf("getattrType not defined for %s\n", debugName().c_str()); - abort(); - } - virtual CompilerType* callType(std::vector &arg_types) { - printf("callType not defined for %s\n", debugName().c_str()); - abort(); - } - virtual BoxedClass* guaranteedClass() { - ASSERT((CompilerType*)getConcreteType() != this, "%s", debugName().c_str()); - return getConcreteType()->guaranteedClass(); - } -}; - -template -class ValuedCompilerType : public _ValuedCompilerType { - public: -}; - -template <> -class ValuedCompilerType : public _ValuedCompilerType { - public: - virtual llvm::Type* llvmType() = 0; - virtual std::string debugName() { - std::string rtn; - llvm::raw_string_ostream os(rtn); - llvmType()->print(os); - return rtn; - } - virtual bool isFitBy(BoxedClass*) { - printf("isFitBy not defined for %s\n", debugName().c_str()); - abort(); - } - - virtual CompilerVariable* dup(ConcreteCompilerVariable *v, DupCache &cache); - virtual ConcreteCompilerType* getConcreteType() { - return this; - } - virtual bool canConvertTo(ConcreteCompilerType* other_type) { - return other_type == this || other_type == UNKNOWN; - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerVariable* var, ConcreteCompilerType* other_type); -}; - -class CompilerVariable { - private: - int vrefs; - bool grabbed; - protected: - virtual void drop(IREmitter &emitter) = 0; - virtual void grab(IREmitter &emmitter) = 0; - public: - CompilerVariable(bool grabbed) : vrefs(1), grabbed(grabbed) {} - virtual ~CompilerVariable() {} - - bool isGrabbed() { return grabbed; } - void incvref() { - assert(vrefs); - vrefs++; - } - void decvrefNodrop() { - ASSERT(vrefs, "%s", getType()->debugName().c_str()); - vrefs--; - if (vrefs == 0) { - delete this; - } - } - void decvref(IREmitter &emitter) { - ASSERT(vrefs, "%s", getType()->debugName().c_str()); - vrefs--; - if (vrefs == 0) { - if (grabbed) - drop(emitter); - delete this; - } - } - int getVrefs() { - return vrefs; - } - void ensureGrabbed(IREmitter &emitter) { - if (!grabbed) { - grab(emitter); - grabbed = true; - } - } - virtual CompilerVariable* split(IREmitter &emitter) = 0; - virtual CompilerVariable* dup(DupCache &cache) = 0; - - virtual CompilerType* getType() = 0; - virtual ConcreteCompilerType* getConcreteType() = 0; - virtual ConcreteCompilerType* getBoxType() = 0; - virtual bool canConvertTo(ConcreteCompilerType *other_type) = 0; - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerType *other_type) = 0; - virtual llvm::Value* makeClassCheck(IREmitter &emitter, BoxedClass* cls) = 0; - virtual BoxedClass* guaranteedClass() = 0; - - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter) = 0; - virtual CompilerVariable* getattr(IREmitter &emitter, const std::string& attr) = 0; - virtual void setattr(IREmitter &emitter, const std::string& attr, CompilerVariable* v) = 0; - virtual CompilerVariable* callattr(IREmitter &emitter, const std::string &attr, bool clsonly, const std::vector& args) = 0; - virtual CompilerVariable* call(IREmitter &emitter, const std::vector& args) = 0; - virtual void print(IREmitter &emitter) = 0; - virtual ConcreteCompilerVariable* len(IREmitter &emitter) = 0; - virtual CompilerVariable* getitem(IREmitter &emitter, CompilerVariable*) = 0; -}; - -template -class ValuedCompilerVariable : public CompilerVariable { - private: - typedef ValuedCompilerType T; - T *type; - V value; - - protected: - virtual void drop(IREmitter &emitter) { - type->drop(emitter, this); - } - virtual void grab(IREmitter &emmitter) { - type->grab(emmitter, this); - } - - public: - ValuedCompilerVariable(T *type, V value, bool grabbed) : CompilerVariable(grabbed), type(type), value(value) {} - virtual T* getType() { return type; } - virtual V getValue() { return value; } - - virtual ConcreteCompilerType* getConcreteType() { - return type->getConcreteType(); - } - virtual ConcreteCompilerType* getBoxType() { - return type->getBoxType(); - } - - virtual ValuedCompilerVariable* split(IREmitter &emitter) { - ValuedCompilerVariable* rtn; - if (getVrefs() == 1) { - rtn = this; - } else { - rtn = new ValuedCompilerVariable(type, value, false); - this->decvref(emitter); - } - rtn->ensureGrabbed(emitter); - return rtn; - } - virtual CompilerVariable* dup(DupCache &cache) { - return type->dup(this, cache); - //return new ValuedCompilerVariable(type, value, isGrabbed()); - } - - virtual bool canConvertTo(ConcreteCompilerType *other_type) { - return type->canConvertTo(other_type); - } - virtual ConcreteCompilerVariable* makeConverted(IREmitter &emitter, ConcreteCompilerType *other_type) { - ConcreteCompilerVariable* rtn = type->makeConverted(emitter, this, other_type); - ASSERT(rtn->getType() == other_type, "%s", type->debugName().c_str()); - return rtn; - } - virtual ConcreteCompilerVariable* nonzero(IREmitter &emitter) { - return type->nonzero(emitter, this); - } - virtual CompilerVariable* getattr(IREmitter &emitter, const std::string& attr) { - return type->getattr(emitter, this, attr); - } - virtual void setattr(IREmitter &emitter, const std::string& attr, CompilerVariable *v) { - type->setattr(emitter, this, attr, v); - } - virtual CompilerVariable* callattr(IREmitter &emitter, const std::string &attr, bool clsonly, const std::vector& args) { - return type->callattr(emitter, this, attr, clsonly, args); - } - virtual CompilerVariable* call(IREmitter &emitter, const std::vector& args) { - return type->call(emitter, this, args); - } - virtual void print(IREmitter &emitter) { - type->print(emitter, this); - } - virtual ConcreteCompilerVariable* len(IREmitter &emitter) { - return type->len(emitter, this); - } - virtual CompilerVariable* getitem(IREmitter &emitter, CompilerVariable *slice) { - return type->getitem(emitter, this, slice); - } - virtual llvm::Value* makeClassCheck(IREmitter &emitter, BoxedClass* cls) { - return type->makeClassCheck(emitter, this, cls); - } - - virtual BoxedClass* guaranteedClass() { - return type->guaranteedClass(); - } -}; - -template <> -inline ConcreteCompilerVariable::ValuedCompilerVariable(ConcreteCompilerType *type, llvm::Value* value, bool grabbed) : CompilerVariable(grabbed), type(type), value(value) { - assert(value->getType() == type->llvmType()); -} - -CompilerVariable* makeInt(int64_t); -CompilerVariable* makeFloat(double); -CompilerVariable* makeBool(bool); -CompilerVariable* makeStr(std::string*); -CompilerVariable* makeFunction(IREmitter &emitter, CLFunction*); -CompilerVariable* undefVariable(); -CompilerVariable* makeTuple(const std::vector &elts); - -ConcreteCompilerType* typeFromClass(BoxedClass*); -CompilerType* typeOfClassobj(BoxedClass*); -CompilerType* makeTupleType(const std::vector &elt_types); - -} // namespace pyston - -#endif diff --git a/src/codegen/dis.cpp b/src/codegen/dis.cpp deleted file mode 100644 index 8e3a06376..000000000 --- a/src/codegen/dis.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" -#include "llvm/IR/Mangler.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCAtom.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/MC/MCFunction.h" -#include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCModule.h" -#include "llvm/MC/MCObjectDisassembler.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" - -#include "codegen/codegen.h" - -#include "dis.h" - -namespace pyston { - -PystonJITEventListener::PystonJITEventListener() { - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - llvm::InitializeNativeTargetDisassembler(); - - std::string err; - const llvm::Target *target = llvm::TargetRegistry::getClosestTargetForJIT(err); - assert(target); - - const llvm::StringRef triple = g.tm->getTargetTriple(); - llvm::Triple *ltriple = new llvm::Triple(triple); - const llvm::StringRef CPU = ""; - - const llvm::MCRegisterInfo *MRI = target->createMCRegInfo(triple); - assert(MRI); - - const llvm::MCAsmInfo *MAI = target->createMCAsmInfo(*MRI, triple); - assert(MAI); - - const llvm::MCInstrInfo *MII = target->createMCInstrInfo(); - assert(MII); - - std::string FeaturesStr; - const llvm::MCSubtargetInfo *STI = target->createMCSubtargetInfo(triple, CPU, FeaturesStr); - assert(STI); - - llvm::MCObjectFileInfo *MOFI = new llvm::MCObjectFileInfo(); - - llvm::MCContext *Ctx = new llvm::MCContext(MAI, MRI, MOFI); - assert(Ctx); - assert(Ctx->getObjectFileInfo()); - - MOFI->InitMCObjectFileInfo(triple, llvm::Reloc::Default, llvm::CodeModel::Default, *Ctx); - - llvm::MCAsmBackend *TAB = target->createMCAsmBackend(*MRI, triple, CPU); - assert(TAB); - - int AsmPrinterVariant = MAI->getAssemblerDialect(); // 0 is ATT, 1 is Intel - IP = target->createMCInstPrinter(AsmPrinterVariant, - *MAI, *MII, *MRI, *STI); - assert(IP); - - llvm::MCCodeEmitter *CE = target->createMCCodeEmitter(*MII, *MRI, *STI, *Ctx); - assert(CE); - - bool verbose = false; - llvm::MCStreamer *streamer = target->createAsmStreamer(*Ctx, llvm::ferrs(), verbose, true, true, IP, CE, TAB, true); - assert(streamer); - streamer->InitSections(); - streamer->SwitchSection(Ctx->getObjectFileInfo()->getTextSection()); - - asm_printer = target->createAsmPrinter(*g.tm, *streamer); - assert(asm_printer); - - llvm::TargetOptions Options; - llvm::TargetMachine *tmachine = target->createTargetMachine(triple, "", "", Options, llvm::Reloc::Default, llvm::CodeModel::Default, llvm::CodeGenOpt::Default); - - //asm_printer->Mang = new llvm::Mangler(*Ctx, *tmachine->getDataLayout()); - asm_printer->Mang = new llvm::Mangler(tmachine->getDataLayout()); - - - DisAsm = target->createMCDisassembler(*STI); - assert(DisAsm); - MIA = target->createMCInstrAnalysis(MII); - assert(MIA); -} - -void PystonJITEventListener::NotifyFunctionEmitted(const llvm::Function &f, - void *ptr, size_t size, - const llvm::JITEvent_EmittedFunctionDetails &details) { - const llvm::MachineFunction &MF = *details.MF;//*const_cast(details.MF); - printf("emitted! %p %ld %s\n", ptr, size, f.getName().data()); - //MF.dump(); - //MF.print(llvm::errs()); - - asm_printer->MF = &MF; - for (llvm::MachineFunction::const_iterator it = MF.begin(); it != MF.end(); it++) { - //it->dump(); - asm_printer->EmitBasicBlockStart(it); - for (llvm::MachineBasicBlock::const_instr_iterator it2 = it->instr_begin(); it2 != it->instr_end(); it2++) { - //llvm::errs() << "dump:"; - //it2->print(llvm::errs()); - if (it2->getNumOperands() && (it2->getOperand(0).getType() == llvm::MachineOperand::MO_MCSymbol)) { - //it2->print(llvm::errs()); - //it2->getOperand(0).print(llvm::errs()); - llvm::errs() << it2->getOperand(0).getMCSymbol()->getName() << '\n'; - } else { - asm_printer->EmitInstruction(it2); - } - } - } - llvm::errs() << '\n'; - llvm::errs().flush(); -} - -void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - llvm::outs() << "An object has been emitted:\n"; - - llvm::error_code code; - - for (llvm::object::section_iterator I = Obj.begin_sections(), E = Obj.end_sections(); I != E;) { - llvm::StringRef name; - code = I->getName(name); - assert(!code); - - const char* type = "unknown"; - bool b; - code = I->isText(b); assert(!code); if (b) type = "text"; - code = I->isData(b); assert(!code); if (b) type = "data"; - code = I->isBSS(b); assert(!code); if (b) type = "bss"; - code = I->isReadOnlyData(b); assert(!code); if (b) type = "rodata"; - printf("Section: %s %s\n", name.data(), type); - -#if LLVMREV < 200442 - I = I.increment(code); -#else - ++I; -#endif - } - - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;) { - llvm::StringRef name; - uint64_t addr, size, offset; - code = I->getName(name); - assert(!code); - code = I->getAddress(addr); - assert(!code); - code = I->getSize(size); - assert(!code); - code = I->getFileOffset(offset); - assert(!code); - printf("%lx %lx %lx %s\n", addr, addr + size, offset, name.data()); -#if LLVMREV < 200442 - I = I.increment(code); -#else - ++I; -#endif - } - - llvm::MCObjectDisassembler *OD = new llvm::MCObjectDisassembler(*Obj.getObjectFile(), *DisAsm, *MIA); - llvm::MCModule *Mod = OD->buildModule(true); - - // This is taken from llvm-objdump.cpp: - uint64_t text_start = 0; - for (llvm::MCModule::const_atom_iterator AI = Mod->atom_begin(), AE = Mod->atom_end(); AI != AE; ++AI) { - llvm::outs() << "Atom " << (*AI)->getName() << ", starts at " << (void*)(*AI)->getBeginAddr() << ": \n"; - if ((*AI)->getName() == ".text") - text_start = (*AI)->getBeginAddr(); - if (const llvm::MCTextAtom *TA = llvm::dyn_cast(*AI)) { - for (llvm::MCTextAtom::const_iterator II = TA->begin(), IE = TA->end(); II != IE; ++II) { - llvm::outs() << "0x"; - llvm::outs().write_hex(II->Address); - - //llvm::outs() << " (+0x"; - //llvm::outs().write_hex(II->Address - text_start); - llvm::outs() << " (+" << II->Address - text_start; - - llvm::outs() << ") "; - IP->printInst(&II->Inst, llvm::outs(), ""); - llvm::outs() << "\n"; - } - } - } - - llvm::outs().flush(); -} - -} diff --git a/src/codegen/dis.h b/src/codegen/dis.h deleted file mode 100644 index bdf45355e..000000000 --- a/src/codegen/dis.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_DIS_H -#define PYSTON_CODEGEN_DIS_H - -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -namespace llvm { -class MCDisassembler; -class MCInstrAnalysis; -class MCInstPrinter; -} - -namespace pyston { - -class PystonJITEventListener : public llvm::JITEventListener { - private: - llvm::AsmPrinter *asm_printer; - llvm::MCDisassembler *DisAsm; - llvm::MCInstrAnalysis *MIA; - llvm::MCInstPrinter *IP; - - public: - PystonJITEventListener(); - virtual void NotifyFunctionEmitted(const llvm::Function &f, - void *ptr, size_t size, - const llvm::JITEvent_EmittedFunctionDetails &details); - - virtual void NotifyObjectEmitted(const llvm::ObjectImage &Obj); -}; - -} - -#endif diff --git a/src/codegen/entry.cpp b/src/codegen/entry.cpp deleted file mode 100644 index f48e6fd9d..000000000 --- a/src/codegen/entry.cpp +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/Analysis/Passes.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/Cloning.h" - -#include "core/options.h" -#include "core/types.h" - -#include "core/util.h" - -#include "codegen/codegen.h" -#include "codegen/compvars.h" -#include "codegen/dis.h" -#include "codegen/entry.h" -#include "codegen/memmgr.h" -#include "codegen/stackmaps.h" -#include "codegen/profiling/profiling.h" - -#include "runtime/types.h" - -namespace pyston { - -GlobalState g; - -extern "C" { -#ifndef BINARY_SUFFIX -#error Must define BINARY_SUFFIX -#endif -#ifndef BINARY_STRIPPED_SUFFIX -#error Must define BINARY_STRIPPED_SUFFIX -#endif - -#define _CONCAT3(a, b, c) a ## b ## c -#define CONCAT3(a, b, c) _CONCAT3(a, b, c) -#define _CONCAT4(a, b, c, d) a ## b ## c ## d -#define CONCAT4(a, b, c, d) _CONCAT4(a, b, c, d) - -#define STDLIB_BC_START CONCAT3(_binary_stdlib, BINARY_SUFFIX, _bc_start) -#define STDLIB_BC_SIZE CONCAT3(_binary_stdlib, BINARY_SUFFIX, _bc_size) -extern char STDLIB_BC_START[]; -extern int STDLIB_BC_SIZE; - -#define STRIPPED_STDLIB_BC_START CONCAT4(_binary_stdlib, BINARY_SUFFIX, BINARY_STRIPPED_SUFFIX, _bc_start) -#define STRIPPED_STDLIB_BC_SIZE CONCAT4(_binary_stdlib, BINARY_SUFFIX, BINARY_STRIPPED_SUFFIX, _bc_size) -extern char STRIPPED_STDLIB_BC_START[]; -extern int STRIPPED_STDLIB_BC_SIZE; - -} - -static llvm::Module* loadStdlib() { - Timer _t("to load stdlib"); - - llvm::StringRef data; - if (!USE_STRIPPED_STDLIB) { - // Make sure the stdlib got linked in correctly; check the magic number at the beginning: - assert(STDLIB_BC_START[0] == 'B'); - assert(STDLIB_BC_START[1] == 'C'); - intptr_t size = (intptr_t)&STDLIB_BC_SIZE; - assert(size > 0 && size < 1 << 30); // make sure the size is being loaded correctly - data = llvm::StringRef(STDLIB_BC_START, size); - } else { - // Make sure the stdlib got linked in correctly; check the magic number at the beginning: - assert(STRIPPED_STDLIB_BC_START[0] == 'B'); - assert(STRIPPED_STDLIB_BC_START[1] == 'C'); - intptr_t size = (intptr_t)&STRIPPED_STDLIB_BC_SIZE; - assert(size > 0 && size < 1 << 30); // make sure the size is being loaded correctly - data = llvm::StringRef(STRIPPED_STDLIB_BC_START, size); - } - - llvm::MemoryBuffer *buffer = llvm::MemoryBuffer::getMemBuffer(data, "", false); - - //llvm::ErrorOr m_or = llvm::parseBitcodeFile(buffer, g.context); - llvm::ErrorOr m_or = llvm::getLazyBitcodeModule(buffer, g.context); - RELEASE_ASSERT(m_or, ""); - llvm::Module* m = m_or.get(); - assert(m); - - for (llvm::Module::global_iterator I = m->global_begin(), E = m->global_end(); I != E; ++I) { - if (I->getLinkage() == llvm::GlobalVariable::PrivateLinkage) - I->setLinkage(llvm::GlobalVariable::ExternalLinkage); - } - m->setModuleIdentifier(" stdlib "); - return m; -} - -class MyObjectCache : public llvm::ObjectCache { - private: - bool loaded; - public: - MyObjectCache() : loaded(false) {} - - virtual void notifyObjectCompiled(const llvm::Module *M, const llvm::MemoryBuffer *Obj) {} - - virtual llvm::MemoryBuffer* getObject(const llvm::Module* M) { - assert(!loaded); - loaded = true; - g.engine->setObjectCache(NULL); - std::unique_ptr del_at_end(this); - -#if 0 - if (!USE_STRIPPED_STDLIB) { - stajt = STDLIB_CACHE_START; - size = (intptr_t)&STDLIB_CACHE_SIZE; - } else { - start = STRIPPED_STDLIB_CACHE_START; - size = (intptr_t)&STRIPPED_STDLIB_CACHE_SIZE; - } -#else - RELEASE_ASSERT(0, ""); - char* start = NULL; - intptr_t size = 0; -#endif - - // Make sure the stdlib got linked in correctly; check the magic number at the beginning: - assert(start[0] == 0x7f); - assert(start[1] == 'E'); - assert(start[2] == 'L'); - assert(start[3] == 'F'); - - assert(size > 0 && size < 1 << 30); // make sure the size is being loaded correctly - - llvm::StringRef data(start, size); - return llvm::MemoryBuffer::getMemBufferCopy(data, ""); - } - -}; - -static void handle_sigfpe(int signum) { - assert(signum == SIGFPE); - fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n"); - exit(1); -} - -void initCodegen() { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); - - g.stdlib_module = loadStdlib(); - - llvm::EngineBuilder eb(new llvm::Module("empty_initial_module", g.context)); - eb.setEngineKind(llvm::EngineKind::JIT); // specify we only want the JIT, and not the interpreter fallback - eb.setUseMCJIT(true); - eb.setMCJITMemoryManager(createMemoryManager()); - //eb.setOptLevel(llvm::CodeGenOpt::None); // -O0 - //eb.setOptLevel(llvm::CodeGenOpt::Less); // -O1 - //eb.setOptLevel(llvm::CodeGenOpt::Default); // -O2, -Os - //eb.setOptLevel(llvm::CodeGenOpt::Aggressive); // -O3 - - llvm::TargetOptions target_options; - target_options.NoFramePointerElim = true; - //target_options.EnableFastISel = true; - eb.setTargetOptions(target_options); - - g.tm = eb.selectTarget(); - assert(g.tm && "failed to get a target machine"); - g.engine = eb.create(g.tm); - assert(g.engine && "engine creation failed?"); - - //g.engine->setObjectCache(new MyObjectCache()); - - g.i1 = llvm::Type::getInt1Ty(g.context); - g.i8 = llvm::Type::getInt8Ty(g.context); - g.i8_ptr = g.i8->getPointerTo(); - g.i32 = llvm::Type::getInt32Ty(g.context); - g.i64 = llvm::Type::getInt64Ty(g.context); - g.void_ = llvm::Type::getVoidTy(g.context); - g.double_ = llvm::Type::getDoubleTy(g.context); - - std::vector listeners = makeJITEventListeners(); - for (int i = 0; i < listeners.size(); i++) { - g.jit_listeners.push_back(listeners[i]); - g.engine->RegisterJITEventListener(listeners[i]); - } - - llvm::JITEventListener* stackmap_listener = makeStackMapListener(); - g.jit_listeners.push_back(stackmap_listener); - g.engine->RegisterJITEventListener(stackmap_listener); - - llvm::JITEventListener* registry_listener = makeRegistryListener(); - g.jit_listeners.push_back(registry_listener); - g.engine->RegisterJITEventListener(registry_listener); - - llvm::JITEventListener* tracebacks_listener = makeTracebacksListener(); - g.jit_listeners.push_back(tracebacks_listener); - g.engine->RegisterJITEventListener(tracebacks_listener); - - if (SHOW_DISASM) { - llvm::JITEventListener* listener = new PystonJITEventListener(); - g.jit_listeners.push_back(listener); - g.engine->RegisterJITEventListener(listener); - } - - initGlobalFuncs(g); - - setupRuntime(); - - signal(SIGFPE, &handle_sigfpe); - - // There are some parts of llvm that are only configurable through command line args, - // so construct a fake argc/argv pair and pass it to the llvm command line machinery: - const char* llvm_args[] = { - "fake_name", - "--enable-stackmap-liveness", - "--enable-patchpoint-liveness", -#ifndef NDEBUG - //"--debug-only=debug-ir", - //"--debug-only=regalloc", - //"--debug-only=stackmaps", -#endif - //"--print-after-all", - //"--print-machineinstrs", - }; - int num_llvm_args = sizeof(llvm_args) / sizeof(llvm_args[0]); - llvm::cl::ParseCommandLineOptions(num_llvm_args, llvm_args, "\n"); - -} - -void teardownCodegen() { - for (int i = 0; i < g.jit_listeners.size(); i++) { - g.engine->UnregisterJITEventListener(g.jit_listeners[i]); - delete g.jit_listeners[i]; - } - g.jit_listeners.clear(); - delete g.engine; -} - -void printAllIR() { - assert(0 && "unimplemented"); - fprintf(stderr, "==============\n"); -} - -static BoxedModule* main_module = NULL; -BoxedModule* createMainModule(const char* fn) { - //static std::unordered_map made; - //assert(made.count(m) == 0); - assert(main_module == NULL); - std::string s_fn; - if (fn != NULL) - s_fn = fn; - else - s_fn = ""; - std::string name("__main__"); - main_module = createModule(&name, &s_fn); - return main_module; -} - -int joinRuntime() { - assert(main_module != NULL); - - // In the future this will have to wait for non-daemon - // threads to finish - - if (PROFILE) - g.func_addr_registry.dumpPerfMap(); - - teardownRuntime(); - teardownCodegen(); - - return 0; -} - -} diff --git a/src/codegen/entry.h b/src/codegen/entry.h deleted file mode 100644 index 9f616d8fd..000000000 --- a/src/codegen/entry.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_ENTRY_H -#define PYSTON_CODEGEN_ENTRY_H - -namespace pyston { - -class AST_Module; -class BoxedModule; -class CompiledFunction; - -void initCodegen(); -void teardownCodegen(); -void printAllIR(); -CompiledFunction* compileModule(AST_Module *m, BoxedModule* bm); // hacky but this method is actually defined in irgen.cpp -int joinRuntime(); -BoxedModule* createMainModule(const char* fn); - -} - -#endif - diff --git a/src/codegen/gcbuilder.cpp b/src/codegen/gcbuilder.cpp deleted file mode 100644 index a98c562b0..000000000 --- a/src/codegen/gcbuilder.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/options.h" - -#include "codegen/gcbuilder.h" -#include "codegen/irgen.h" - -namespace pyston { - -class ConservativeGCBuilder : public GCBuilder { - private: - virtual llvm::Value* readPointer(IREmitter& emitter, llvm::Value* ptr_ptr) { - assert(ptr_ptr->getType() == g.llvm_value_type_ptr); - return emitter.getBuilder()->CreateLoad(ptr_ptr); - } - virtual void writePointer(IREmitter& emitter, llvm::Value* ptr_ptr, llvm::Value* ptr_value, bool ignore_existing_value) { - assert(ptr_ptr->getType() == g.llvm_value_type_ptr); - emitter.getBuilder()->CreateStore(ptr_value, ptr_ptr); - } - virtual void grabPointer(IREmitter& emitter, llvm::Value* ptr) { - } - virtual void dropPointer(IREmitter& emitter, llvm::Value* ptr) { - } -}; - -ConservativeGCBuilder cgc_builder; - -GCBuilder* getGCBuilder() { - return &cgc_builder; -} - -} diff --git a/src/codegen/gcbuilder.h b/src/codegen/gcbuilder.h deleted file mode 100644 index 43dc877a9..000000000 --- a/src/codegen/gcbuilder.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_GCBUILDER_H -#define PYSTON_CODEGEN_GCBUILDER_H - -#include "llvm/IR/Value.h" - -namespace pyston { - -class IREmitter; -class GCBuilder { - public: - virtual llvm::Value* readPointer(IREmitter&, llvm::Value* ptr_ptr) = 0; - virtual void writePointer(IREmitter&, llvm::Value* ptr_ptr, llvm::Value* ptr_value, bool ignore_existing_value) = 0; - - virtual void grabPointer(IREmitter&, llvm::Value* ptr) = 0; - virtual void dropPointer(IREmitter&, llvm::Value* ptr) = 0; -}; - -GCBuilder* getGCBuilder(); - -} - -#endif diff --git a/src/codegen/irgen.cpp b/src/codegen/irgen.cpp deleted file mode 100644 index ef05bab80..000000000 --- a/src/codegen/irgen.cpp +++ /dev/null @@ -1,2809 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -#include "llvm/DIBuilder.h" -#include "llvm/PassManager.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Scalar.h" - -#include "core/options.h" -#include "core/stats.h" - -#include "core/ast.h" -#include "core/cfg.h" -#include "core/util.h" - -#include "analysis/scoping_analysis.h" -#include "analysis/function_analysis.h" -#include "analysis/type_analysis.h" - -#include "codegen/codegen.h" -#include "codegen/compvars.h" -#include "codegen/irgen.h" -#include "codegen/patchpoints.h" -#include "codegen/osrentry.h" -#include "codegen/stackmaps.h" -#include "codegen/irgen/util.h" -#include "codegen/opt/escape_analysis.h" -#include "codegen/opt/inliner.h" -#include "codegen/opt/passes.h" - -#include "runtime/types.h" -#include "runtime/objmodel.h" - -namespace pyston { - -typedef std::unordered_set BlockSet; - -// This is where you can add a hook for any instruction added through the IRBuilder. -// It's currently not doing any hooking; hopefully there's not too much overhead from this. -void MyInserter::InsertHelper(llvm::Instruction *I, const llvm::Twine &Name, - llvm::BasicBlock *BB, llvm::BasicBlock::iterator InsertPt) const { - llvm::IRBuilderDefaultInserter::InsertHelper(I, Name, BB, InsertPt); -} - -// Class that holds state of the current IR generation, that might not be local -// to the specific phase or pass we're in. -class IRGenState { - private: - CompiledFunction *cf; - SourceInfo* source_info; - GCBuilder *gc; - llvm::MDNode* func_dbg_info; - - llvm::AllocaInst *scratch_space; - int scratch_size; - - public: - IRGenState(CompiledFunction *cf, SourceInfo* source_info, GCBuilder *gc, llvm::MDNode* func_dbg_info) : cf(cf), source_info(source_info), gc(gc), func_dbg_info(func_dbg_info), scratch_space(NULL), scratch_size(0) { - assert(cf->func); - assert(!cf->clfunc); // in this case don't need to pass in sourceinfo - } - - CompiledFunction* getCurFunction() { - return cf; - } - - llvm::Function* getLLVMFunction() { - return cf->func; - } - - EffortLevel::EffortLevel getEffortLevel() { - return cf->effort; - } - - GCBuilder* getGC() { - return gc; - } - - llvm::Value* getScratchSpace(int min_bytes) { - llvm::BasicBlock &entry_block = getLLVMFunction()->getEntryBlock(); - - if (scratch_space) { - assert(scratch_space->getParent() == &entry_block); - assert(scratch_space->isStaticAlloca()); - if (scratch_size >= min_bytes) - return scratch_space; - } - - // Not sure why, but LLVM wants to canonicalize an alloca into an array alloca (assuming - // the alloca is static); just to keep things straightforward, let's do that here: - llvm::Type* array_type = llvm::ArrayType::get(g.i8, min_bytes); - - llvm::AllocaInst* new_scratch_space; - // If the entry block is currently empty, we have to be more careful: - if (entry_block.begin() == entry_block.end()) { - new_scratch_space = new llvm::AllocaInst(array_type, getConstantInt(1, g.i64), "scratch", &entry_block); - } else { - new_scratch_space = new llvm::AllocaInst(array_type, getConstantInt(1, g.i64), "scratch", entry_block.getFirstInsertionPt()); - } - assert(new_scratch_space->isStaticAlloca()); - - if (scratch_space) - scratch_space->replaceAllUsesWith(new_scratch_space); - - scratch_size = min_bytes; - scratch_space = new_scratch_space; - - return scratch_space; - } - - ConcreteCompilerType* getReturnType() { - assert(cf->sig); - return cf->sig->rtn_type; - } - - SourceInfo* getSourceInfo() { - return source_info; - } - - ScopeInfo* getScopeInfo() { - SourceInfo *source = getSourceInfo(); - return source->scoping->getScopeInfoForNode(source->ast); - } - - llvm::MDNode* getFuncDbgInfo() { - return func_dbg_info; - } -}; - -class IREmitterImpl : public IREmitter { - private: - IRGenState *irstate; - IRBuilder *builder; - - public: - explicit IREmitterImpl(IRGenState *irstate) : irstate(irstate), builder(new IRBuilder(g.context)) { - builder->setEmitter(this); - } - - Target getTarget() override { - if (irstate->getEffortLevel() == EffortLevel::INTERPRETED) - return INTERPRETER; - return COMPILATION; - } - - IRBuilder* getBuilder() override { - return builder; - } - - GCBuilder* getGC() override { - return irstate->getGC(); - } - - llvm::Function* getIntrinsic(llvm::Intrinsic::ID intrinsic_id) override { - return llvm::Intrinsic::getDeclaration(g.cur_module, intrinsic_id); - } - - CompiledFunction* currentFunction() override { - return irstate->getCurFunction(); - } - - llvm::Value* createPatchpoint(const PatchpointSetupInfo* pp, void* func_addr, const std::vector &args) override { - std::vector pp_args; - pp_args.push_back(getConstantInt(pp->getPatchpointId(), g.i64)); - pp_args.push_back(getConstantInt(pp->totalSize(), g.i32)); - pp_args.push_back(embedConstantPtr(func_addr, g.i8->getPointerTo())); - pp_args.push_back(getConstantInt(args.size(), g.i32)); - - pp_args.insert(pp_args.end(), args.begin(), args.end()); - - int num_scratch_bytes = pp->numScratchBytes(); - if (num_scratch_bytes) { - llvm::Value* scratch_space = irstate->getScratchSpace(num_scratch_bytes); - pp_args.push_back(scratch_space); - } - - llvm::Intrinsic::ID intrinsic_id = pp->hasReturnValue() ? llvm::Intrinsic::experimental_patchpoint_i64 : llvm::Intrinsic::experimental_patchpoint_void; - llvm::Function *patchpoint = this->getIntrinsic(intrinsic_id); - llvm::CallInst* rtn = this->getBuilder()->CreateCall(patchpoint, pp_args); - - /* - static int n = 0; - n++; - if (n >= 3) - rtn->setCallingConv(llvm::CallingConv::PreserveAll); - */ - rtn->setCallingConv(pp->getCallingConvention()); - - // Not sure why this doesn't work: - //rtn->setCallingConv(llvm::CallingConv::AnyReg); - - return rtn; - } -}; - -static void addIRDebugSymbols(llvm::Function *f) { - llvm::legacy::PassManager mpm; - - llvm::error_code code = llvm::sys::fs::create_directory(".debug_ir", true); - assert(!code); - - mpm.add(llvm::createDebugIRPass(false, false, ".debug_ir", f->getName())); - - mpm.run(*g.cur_module); -} - -static void optimizeIR(llvm::Function *f, EffortLevel::EffortLevel effort) { - // TODO maybe should do some simple passes (ex: gvn?) if effort level isn't maximal? - // In general, this function needs a lot of tuning. - if (effort < EffortLevel::MAXIMAL) - return; - - Timer _t("optimizing"); - - llvm::FunctionPassManager fpm(g.cur_module); - - fpm.add(new llvm::DataLayout(*g.tm->getDataLayout())); - - if (ENABLE_INLINING && effort >= EffortLevel::MAXIMAL) fpm.add(makeFPInliner(275)); - fpm.add(llvm::createCFGSimplificationPass()); - - fpm.add(llvm::createBasicAliasAnalysisPass()); - fpm.add(llvm::createTypeBasedAliasAnalysisPass()); - if (ENABLE_PYSTON_PASSES) { - fpm.add(new EscapeAnalysis()); - fpm.add(createPystonAAPass()); - } - - if (ENABLE_PYSTON_PASSES) fpm.add(createMallocsNonNullPass()); - - // TODO Find the right place for this pass (and ideally not duplicate it) - if (ENABLE_PYSTON_PASSES) { - fpm.add(llvm::createGVNPass()); - fpm.add(createConstClassesPass()); - } - - // TODO: find the right set of passes - if (0) { - // My original set of passes, that seem to get about 90% of the benefit: - fpm.add(llvm::createInstructionCombiningPass()); - fpm.add(llvm::createReassociatePass()); - fpm.add(llvm::createGVNPass()); - fpm.add(llvm::createCFGSimplificationPass()); - } else { - // copied + slightly modified from llvm/lib/Transforms/IPO/PassManagerBuilder.cpp::populateModulePassManager - fpm.add(llvm::createEarlyCSEPass()); // Catch trivial redundancies - fpm.add(llvm::createJumpThreadingPass()); // Thread jumps. - fpm.add(llvm::createCorrelatedValuePropagationPass()); // Propagate conditionals - fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - fpm.add(llvm::createInstructionCombiningPass()); // Combine silly seq's - - fpm.add(llvm::createTailCallEliminationPass()); // Eliminate tail calls - fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - fpm.add(llvm::createReassociatePass()); // Reassociate expressions - fpm.add(llvm::createLoopRotatePass()); // Rotate Loop - fpm.add(llvm::createLICMPass()); // Hoist loop invariants - fpm.add(llvm::createLoopUnswitchPass(true /*optimize_for_size*/)); - fpm.add(llvm::createInstructionCombiningPass()); - fpm.add(llvm::createIndVarSimplifyPass()); // Canonicalize indvars - fpm.add(llvm::createLoopIdiomPass()); // Recognize idioms like memset. - fpm.add(llvm::createLoopDeletionPass()); // Delete dead loops - - fpm.add(llvm::createLoopUnrollPass()); // Unroll small loops - - fpm.add(llvm::createGVNPass()); // Remove redundancies - fpm.add(llvm::createMemCpyOptPass()); // Remove memcpy / form memset - fpm.add(llvm::createSCCPPass()); // Constant prop with SCCP - - // Run instcombine after redundancy elimination to exploit opportunities - // opened up by them. - fpm.add(llvm::createInstructionCombiningPass()); - fpm.add(llvm::createJumpThreadingPass()); // Thread jumps - fpm.add(llvm::createCorrelatedValuePropagationPass()); - fpm.add(llvm::createDeadStoreEliminationPass()); // Delete dead stores - - fpm.add(llvm::createLoopRerollPass()); - //fpm.add(llvm::createSLPVectorizerPass()); // Vectorize parallel scalar chains. - - - fpm.add(llvm::createAggressiveDCEPass()); // Delete dead instructions - fpm.add(llvm::createCFGSimplificationPass()); // Merge & remove BBs - fpm.add(llvm::createInstructionCombiningPass()); // Clean up after everything. - - //fpm.add(llvm::createBarrierNoopPass()); - //fpm.add(llvm::createLoopVectorizePass(DisableUnrollLoops, LoopVectorize)); - fpm.add(llvm::createInstructionCombiningPass()); - fpm.add(llvm::createCFGSimplificationPass()); - } - - // TODO Find the right place for this pass (and ideally not duplicate it) - if (ENABLE_PYSTON_PASSES) { - fpm.add(createConstClassesPass()); - fpm.add(llvm::createInstructionCombiningPass()); - fpm.add(llvm::createCFGSimplificationPass()); - fpm.add(createConstClassesPass()); - fpm.add(createDeadAllocsPass()); - //fpm.add(llvm::createSCCPPass()); // Constant prop with SCCP - //fpm.add(llvm::createEarlyCSEPass()); // Catch trivial redundancies - //fpm.add(llvm::createInstructionCombiningPass()); - //fpm.add(llvm::createCFGSimplificationPass()); - } - - fpm.doInitialization(); - - for (int i = 0; i < MAX_OPT_ITERATIONS; i++) { - bool changed = fpm.run(*f); - - if (!changed) { - if (VERBOSITY("irgen")) printf("done after %d optimization iterations\n", i-1); - break; - } - - if (VERBOSITY("irgen") >= 1) { - fprintf(stderr, "after optimization %d:\n", i); - printf("\033[36m"); - fflush(stdout); - dumpPrettyIR(f); - //f->dump(); - //g.cur_module->dump(); - printf("\033[0m"); - fflush(stdout); - } - } - - long us = _t.end(); - static StatCounter us_optimizing("us_compiling_optimizing"); - us_optimizing.log(us); -} - -class GuardList { - public: - struct ExprTypeGuard { - CFGBlock *cfg_block; - llvm::BranchInst* branch; - AST_expr* ast_node; - CompilerVariable* val; - SymbolTable st; - - ExprTypeGuard(CFGBlock *cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val, const SymbolTable &st) : - cfg_block(cfg_block), branch(branch), ast_node(ast_node) { - DupCache cache; - this->val = val->dup(cache); - for (SymbolTable::const_iterator it = st.begin(), end = st.end(); it != end; ++it) { - this->st[it->first] = it->second->dup(cache); - } - } - }; - - struct BlockEntryGuard { - CFGBlock *cfg_block; - llvm::BranchInst* branch; - SymbolTable symbol_table; - - BlockEntryGuard(CFGBlock *cfg_block, llvm::BranchInst* branch, const SymbolTable &symbol_table) : - cfg_block(cfg_block), branch(branch) { - DupCache cache; - for (SymbolTable::const_iterator it = symbol_table.begin(), end = symbol_table.end(); it != end; ++it) { - this->symbol_table[it->first] = it->second->dup(cache); - } - } - }; - - private: - std::unordered_map expr_type_guards; - std::unordered_map > block_begin_guards; - - public: - typedef std::unordered_map::iterator expr_type_guard_iterator; - typedef std::unordered_map::const_iterator expr_type_guard_const_iterator; - expr_type_guard_iterator after_begin() { - return expr_type_guards.begin(); - } - expr_type_guard_iterator after_end() { - return expr_type_guards.end(); - } - ExprTypeGuard* getNodeTypeGuard(AST_expr* node) const { - expr_type_guard_const_iterator it = expr_type_guards.find(node); - if (it == expr_type_guards.end()) - return NULL; - return it->second; - } - - bool isEmpty() const { - return expr_type_guards.size() == 0; - } - - void addExprTypeGuard(CFGBlock *cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val, const SymbolTable &st) { - ExprTypeGuard* &g = expr_type_guards[ast_node]; - assert(g == NULL); - g = new ExprTypeGuard(cfg_block, branch, ast_node, val, st); - } - - void registerGuardForBlockEntry(CFGBlock *cfg_block, llvm::BranchInst* branch, const SymbolTable &st) { - std::vector &v = block_begin_guards[cfg_block]; - v.push_back(new BlockEntryGuard(cfg_block, branch, st)); - } - - const std::vector& getGuardsForBlock(CFGBlock *block) const { - std::unordered_map >::const_iterator it = block_begin_guards.find(block); - if (it != block_begin_guards.end()) - return it->second; - - static std::vector empty_list; - return empty_list; - } -}; - -class IRGenerator { - private: - IRGenState *irstate; - - IREmitterImpl emitter; - SymbolTable symbol_table; - std::vector &entry_blocks; - llvm::BasicBlock *curblock; - CFGBlock *myblock; - TypeAnalysis *types; - GuardList &out_guards; - const GuardList &in_guards; - - enum State { - PARTIAL, // running through a partial block, waiting to hit the first in_guard - RUNNING, // normal - DEAD, // passed a Return statement; still syntatically valid but the code should not be compiled - FINISHED, // passed a pseudo-node such as Branch or Jump; internal error if there are any more statements - } state; - - public: - IRGenerator(IRGenState *irstate, std::vector &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial) : irstate(irstate), emitter(irstate), entry_blocks(entry_blocks), myblock(myblock), types(types), out_guards(out_guards), in_guards(in_guards), state(is_partial ? PARTIAL : RUNNING) { - llvm::BasicBlock* entry_block = entry_blocks[myblock->idx]; - emitter.getBuilder()->SetInsertPoint(entry_block); - curblock = entry_block; - } - - ~IRGenerator() { - delete emitter.getBuilder(); - } - - private: - void createExprTypeGuard(llvm::Value *check_val, AST_expr* node, CompilerVariable* node_value) { - assert(check_val->getType() == g.i1); - - llvm::Value* md_vals[] = {llvm::MDString::get(g.context, "branch_weights"), getConstantInt(1000), getConstantInt(1)}; - llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef(md_vals)); - - // For some reason there doesn't seem to be the ability to place the new BB - // right after the current bb (can only place it *before* something else), - // but we can put it somewhere arbitrary and then move it. - llvm::BasicBlock* success_bb = llvm::BasicBlock::Create(g.context, "check_succeeded", irstate->getLLVMFunction()); - success_bb->moveAfter(curblock); - - llvm::BranchInst* guard = emitter.getBuilder()->CreateCondBr(check_val, success_bb, success_bb, branch_weights); - - curblock = success_bb; - emitter.getBuilder()->SetInsertPoint(curblock); - - out_guards.addExprTypeGuard(myblock, guard, node, node_value, symbol_table); - } - - CompilerVariable* evalAttribute(AST_Attribute *node) { - assert(node->ctx_type == AST_TYPE::Load); - CompilerVariable *value = evalExpr(node->value); - if (state == PARTIAL) - return NULL; - - CompilerVariable *rtn = value->getattr(emitter, node->attr); - value->decvref(emitter); - return rtn; - } - - CompilerVariable* evalClsAttribute(AST_ClsAttribute *node) { - CompilerVariable *value = evalExpr(node->value); - if (state == PARTIAL) - return NULL; - - //ASSERT((node->attr == "__iter__" || node->attr == "__hasnext__" || node->attr == "next" || node->attr == "__enter__" || node->attr == "__exit__") && (value->getType() == UNDEF || value->getType() == value->getBoxType()) && "inefficient for anything else, should change", "%s", node->attr.c_str()); - - ConcreteCompilerVariable *converted = value->makeConverted(emitter, value->getBoxType()); - value->decvref(emitter); - - bool do_patchpoint = ENABLE_ICGETATTRS && emitter.getTarget() != IREmitter::INTERPRETER; - llvm::Value *rtn; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createGetattrPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(converted->getValue()); - llvm_args.push_back(getStringConstantPtr(node->attr + '\0')); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, (void*)pyston::getclsattr, llvm_args); - rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - } else { - rtn = emitter.getBuilder()->CreateCall2(g.funcs.getclsattr, - converted->getValue(), getStringConstantPtr(node->attr + '\0')); - } - converted->decvref(emitter); - return new ConcreteCompilerVariable(UNKNOWN, rtn, true); - } - - enum BinExpType { - BinOp, - Compare, - }; - CompilerVariable* _evalBinExp(CompilerVariable *left, CompilerVariable *right, AST_TYPE::AST_TYPE type, BinExpType exp_type) { - assert(left); - assert(right); - - if (left->getType() == INT && right->getType() == INT) { - ConcreteCompilerVariable *converted_left = left->makeConverted(emitter, INT); - ConcreteCompilerVariable *converted_right = right->makeConverted(emitter, INT); - llvm::Value *v; - if (type == AST_TYPE::Mod) { - v = emitter.getBuilder()->CreateCall2(g.funcs.mod_i64_i64, converted_left->getValue(), converted_right->getValue()); - } else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) { - v = emitter.getBuilder()->CreateCall2(g.funcs.div_i64_i64, converted_left->getValue(), converted_right->getValue()); - } else if (type == AST_TYPE::Pow) { - v = emitter.getBuilder()->CreateCall2(g.funcs.pow_i64_i64, converted_left->getValue(), converted_right->getValue()); - } else if (exp_type == BinOp) { - llvm::Instruction::BinaryOps binopcode; - switch (type) { - case AST_TYPE::Add: - binopcode = llvm::Instruction::Add; - break; - case AST_TYPE::BitAnd: - binopcode = llvm::Instruction::And; - break; - case AST_TYPE::BitOr: - binopcode = llvm::Instruction::Or; - break; - case AST_TYPE::BitXor: - binopcode = llvm::Instruction::Xor; - break; - case AST_TYPE::LShift: - binopcode = llvm::Instruction::Shl; - break; - case AST_TYPE::RShift: - binopcode = llvm::Instruction::AShr; - break; - case AST_TYPE::Mult: - binopcode = llvm::Instruction::Mul; - break; - case AST_TYPE::Sub: - binopcode = llvm::Instruction::Sub; - break; - default: - ASSERT(0, "%s", getOpName(type).c_str()); - abort(); - break; - } - v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(), converted_right->getValue()); - } else { - assert(exp_type == Compare); - llvm::CmpInst::Predicate cmp_pred; - switch(type) { - case AST_TYPE::Eq: - case AST_TYPE::Is: - cmp_pred = llvm::CmpInst::ICMP_EQ; - break; - case AST_TYPE::Lt: - cmp_pred = llvm::CmpInst::ICMP_SLT; - break; - case AST_TYPE::LtE: - cmp_pred = llvm::CmpInst::ICMP_SLE; - break; - case AST_TYPE::Gt: - cmp_pred = llvm::CmpInst::ICMP_SGT; - break; - case AST_TYPE::GtE: - cmp_pred = llvm::CmpInst::ICMP_SGE; - break; - case AST_TYPE::NotEq: - case AST_TYPE::IsNot: - cmp_pred = llvm::CmpInst::ICMP_NE; - break; - default: - ASSERT(0, "%s", getOpName(type).c_str()); - abort(); - break; - } - v = emitter.getBuilder()->CreateICmp(cmp_pred, converted_left->getValue(), converted_right->getValue()); - } - converted_left->decvref(emitter); - converted_right->decvref(emitter); - assert(v->getType() == g.i64 || v->getType() == g.i1); - return new ConcreteCompilerVariable(v->getType() == g.i64 ? INT : BOOL, v, true); - } - - if (left->getType() == FLOAT && (right->getType() == FLOAT || right->getType() == INT)) { - ConcreteCompilerVariable *converted_left = left->makeConverted(emitter, FLOAT); - - ConcreteCompilerVariable *converted_right; - if (right->getType() == FLOAT) { - converted_right = right->makeConverted(emitter, FLOAT); - } else { - converted_right = right->makeConverted(emitter, INT); - llvm::Value* conv = emitter.getBuilder()->CreateSIToFP(converted_right->getValue(), g.double_); - converted_right->decvref(emitter); - converted_right = new ConcreteCompilerVariable(FLOAT, conv, true); - } - llvm::Value *v; - bool succeeded = true; - if (type == AST_TYPE::Mod) { - v = emitter.getBuilder()->CreateCall2(g.funcs.mod_float_float, converted_left->getValue(), converted_right->getValue()); - } else if (type == AST_TYPE::Div || type == AST_TYPE::FloorDiv) { - v = emitter.getBuilder()->CreateCall2(g.funcs.div_float_float, converted_left->getValue(), converted_right->getValue()); - } else if (type == AST_TYPE::Pow) { - v = emitter.getBuilder()->CreateCall2(g.funcs.pow_float_float, converted_left->getValue(), converted_right->getValue()); - } else if (exp_type == BinOp) { - llvm::Instruction::BinaryOps binopcode; - switch (type) { - case AST_TYPE::Add: - binopcode = llvm::Instruction::FAdd; - break; - case AST_TYPE::Mult: - binopcode = llvm::Instruction::FMul; - break; - case AST_TYPE::Sub: - binopcode = llvm::Instruction::FSub; - break; - case AST_TYPE::BitAnd: - case AST_TYPE::BitOr: - case AST_TYPE::BitXor: - case AST_TYPE::LShift: - case AST_TYPE::RShift: - succeeded = false; - break; - default: - ASSERT(0, "%s", getOpName(type).c_str()); - abort(); - break; - } - - if (succeeded) { - v = emitter.getBuilder()->CreateBinOp(binopcode, converted_left->getValue(), converted_right->getValue()); - } - } else { - assert(exp_type == Compare); - llvm::CmpInst::Predicate cmp_pred; - switch(type) { - case AST_TYPE::Eq: - case AST_TYPE::Is: - cmp_pred = llvm::CmpInst::FCMP_OEQ; - break; - case AST_TYPE::Lt: - cmp_pred = llvm::CmpInst::FCMP_OLT; - break; - case AST_TYPE::LtE: - cmp_pred = llvm::CmpInst::FCMP_OLE; - break; - case AST_TYPE::Gt: - cmp_pred = llvm::CmpInst::FCMP_OGT; - break; - case AST_TYPE::GtE: - cmp_pred = llvm::CmpInst::FCMP_OGE; - break; - case AST_TYPE::NotEq: - case AST_TYPE::IsNot: - cmp_pred = llvm::CmpInst::FCMP_UNE; - break; - default: - ASSERT(0, "%s", getOpName(type).c_str()); - abort(); - break; - } - v = emitter.getBuilder()->CreateFCmp(cmp_pred, converted_left->getValue(), converted_right->getValue()); - } - converted_left->decvref(emitter); - converted_right->decvref(emitter); - - if (succeeded) { - assert(v->getType() == g.double_ || v->getType() == g.i1); - return new ConcreteCompilerVariable(v->getType() == g.double_ ? FLOAT : BOOL, v, true); - } - } - //ASSERT(left->getType() == left->getBoxType() || right->getType() == right->getBoxType(), "%s %s", - //left->getType()->debugName().c_str(), right->getType()->debugName().c_str()); - - ConcreteCompilerVariable *boxed_left = left->makeConverted(emitter, left->getBoxType()); - ConcreteCompilerVariable *boxed_right = right->makeConverted(emitter, right->getBoxType()); - - llvm::Value* rtn; - bool do_patchpoint = ENABLE_ICBINEXPS && emitter.getTarget() != IREmitter::INTERPRETER; - - llvm::Value *rt_func; - void* rt_func_addr; - if (exp_type == BinOp) { - rt_func = g.funcs.binop; - rt_func_addr = (void*)binop; - } else { - rt_func = g.funcs.compare; - rt_func_addr = (void*)compare; - } - - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createBinexpPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(boxed_left->getValue()); - llvm_args.push_back(boxed_right->getValue()); - llvm_args.push_back(getConstantInt(type, g.i32)); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, rt_func_addr, llvm_args); - rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - } else { - - rtn = emitter.getBuilder()->CreateCall3(rt_func, boxed_left->getValue(), boxed_right->getValue(), getConstantInt(type, g.i32)); - } - - boxed_left->decvref(emitter); - boxed_right->decvref(emitter); - - return new ConcreteCompilerVariable(UNKNOWN, rtn, true); - } - - CompilerVariable* evalBinOp(AST_BinOp *node) { - CompilerVariable *left = evalExpr(node->left); - _setFake(_nodeFakeName(0, node), left); // 'fakes' are for handling deopt entries - CompilerVariable *right = evalExpr(node->right); - _setFake(_nodeFakeName(1, node), right); - - if (state == PARTIAL) { - _clearFake(_nodeFakeName(0, node)); - _clearFake(_nodeFakeName(1, node)); - return NULL; - } - left = _getFake(_nodeFakeName(0, node)); - right = _getFake(_nodeFakeName(1, node)); - - assert(node->op_type != AST_TYPE::Is && node->op_type != AST_TYPE::IsNot && "not tested yet"); - - CompilerVariable *rtn = this->_evalBinExp(left, right, node->op_type, BinOp); - left->decvref(emitter); - right->decvref(emitter); - return rtn; - } - - CompilerVariable* evalBoolOp(AST_BoolOp *node) { - assert(state != PARTIAL); - - assert(node->op_type == AST_TYPE::And || node->op_type == AST_TYPE::Or); - bool is_and = node->op_type == AST_TYPE::And; - int nvals = node->values.size(); - assert(nvals >= 2); - - std::vector starting_blocks; - for (int i = 0; i < nvals - 1; i++) { - starting_blocks.push_back(llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction())); - } - llvm::BasicBlock *exit_block = llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction()); - std::vector ending_blocks; - - std::vector converted_vals; - ConcreteCompilerVariable *prev = NULL; - - for (int i = 0; i < nvals; i++) { - if (i > 0) { - assert(prev); - prev->decvref(emitter); - } - - CompilerVariable *v = evalExpr(node->values[i]); - ConcreteCompilerVariable *converted = prev = v->makeConverted(emitter, v->getBoxType()); - v->decvref(emitter); - converted_vals.push_back(converted->getValue()); - - ending_blocks.push_back(curblock); - - if (i == nvals - 1) { - emitter.getBuilder()->CreateBr(exit_block); - emitter.getBuilder()->SetInsertPoint(exit_block); - curblock = exit_block; - } else { - ConcreteCompilerVariable *nz = converted->nonzero(emitter); - //ConcreteCompilerVariable *nz = v->nonzero(emitter); - assert(nz->getType() == BOOL); - llvm::Value* nz_v = nz->getValue(); - - if (is_and) - emitter.getBuilder()->CreateCondBr(nz_v, starting_blocks[i], exit_block); - else - emitter.getBuilder()->CreateCondBr(nz_v, exit_block, starting_blocks[i]); - - // Shouldn't generate any code, so should be safe to put after branch instruction; - // if that assumption fails, will fail loudly. - nz->decvref(emitter); - emitter.getBuilder()->SetInsertPoint(starting_blocks[i]); - curblock = starting_blocks[i]; - } - } - - // TODO prev (from the last block) doesn't get freed! - - llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(g.llvm_value_type_ptr, nvals); - for (int i = 0; i < nvals; i++) { - phi->addIncoming(converted_vals[i], ending_blocks[i]); - } - - //cf->func->dump(); - return new ConcreteCompilerVariable(UNKNOWN, phi, true); - } - - CompilerVariable* evalCompare(AST_Compare *node) { - RELEASE_ASSERT(node->ops.size() == 1, ""); - - CompilerVariable *left = evalExpr(node->left); - _setFake(_nodeFakeName(0, node), left); // 'fakes' are for handling deopt entries - CompilerVariable *right = evalExpr(node->comparators[0]); - _setFake(_nodeFakeName(1, node), right); - - if (state == PARTIAL) { - _clearFake(_nodeFakeName(0, node)); - _clearFake(_nodeFakeName(1, node)); - return NULL; - } - left = _getFake(_nodeFakeName(0, node)); - right = _getFake(_nodeFakeName(1, node)); - - assert(left); - assert(right); - - CompilerVariable *rtn = _evalBinExp(left, right, node->ops[0], Compare); - left->decvref(emitter); - right->decvref(emitter); - return rtn; - } - - CompilerVariable* evalCall(AST_Call *node) { - bool is_callattr; - bool callattr_clsonly = false; - std::string *attr = NULL; - CompilerVariable *func; - if (node->func->type == AST_TYPE::Attribute) { - is_callattr = true; - callattr_clsonly = false; - AST_Attribute* attr_ast = static_cast(node->func); - func = evalExpr(attr_ast->value); - attr = &attr_ast->attr; - } else if (node->func->type == AST_TYPE::ClsAttribute) { - is_callattr = true; - callattr_clsonly = true; - AST_ClsAttribute* attr_ast = static_cast(node->func); - func = evalExpr(attr_ast->value); - attr = &attr_ast->attr; - } else { - is_callattr = false; - func = evalExpr(node->func); - } - - _setFake(_nodeFakeName(-1, node), func); - - std::vector args; - for (int i = 0; i < node->args.size(); i++) { - CompilerVariable *a = evalExpr(node->args[i]); - _setFake(_nodeFakeName(i, node), a); - } - if (state == PARTIAL) { - _clearFake(_nodeFakeName(-1, node)); - for (int i = 0; i < node->args.size(); i++) { - _clearFake(_nodeFakeName(i, node)); - } - return NULL; - } - - func = _getFake(_nodeFakeName(-1, node)); - for (int i = 0; i < node->args.size(); i++) { - args.push_back(_getFake(_nodeFakeName(i, node))); - } - - //if (VERBOSITY("irgen") >= 1) - //_addAnnotation("before_call"); - - CompilerVariable *rtn; - if (is_callattr) { - rtn = func->callattr(emitter, *attr, callattr_clsonly, args); - } else { - rtn = func->call(emitter, args); - } - - func->decvref(emitter); - for (int i = 0; i < args.size(); i++) { - args[i]->decvref(emitter); - } - - //if (VERBOSITY("irgen") >= 1) - //_addAnnotation("end_of_call"); - - return rtn; - } - - CompilerVariable* evalDict(AST_Dict *node) { - assert(state != PARTIAL); - - llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createDict); - ConcreteCompilerVariable *rtn = new ConcreteCompilerVariable(DICT, v, true); - if (node->keys.size()) { - CompilerVariable *setitem = rtn->getattr(emitter, "__setitem__"); - for (int i = 0; i < node->keys.size(); i++) { - CompilerVariable *key = evalExpr(node->keys[i]); - CompilerVariable *value = evalExpr(node->values[i]); - - std::vector args; - args.push_back(key); - args.push_back(value); - // TODO could use the internal _listAppend function to avoid incref/decref'ing None - CompilerVariable *rtn = setitem->call(emitter, args); - rtn->decvref(emitter); - - key->decvref(emitter); - value->decvref(emitter); - } - setitem->decvref(emitter); - } - return rtn; - } - - void _addAnnotation(const char* message) { - llvm::Instruction *inst = emitter.getBuilder()->CreateCall(llvm::Intrinsic::getDeclaration(g.cur_module, llvm::Intrinsic::donothing)); - llvm::Value* md_vals[] = {getConstantInt(0)}; - llvm::MDNode* mdnode = llvm::MDNode::get(g.context, md_vals); - inst->setMetadata(message, mdnode); - } - - CompilerVariable* evalIndex(AST_Index *node) { - return evalExpr(node->value); - } - - CompilerVariable* evalList(AST_List *node) { - for (int i = 0; i < node->elts.size(); i++) { - CompilerVariable *value = evalExpr(node->elts[i]); - _setFake(_nodeFakeName(i, node), value); - } - - if (state == PARTIAL) { - for (int i = 0; i < node->elts.size(); i++) { - _clearFake(_nodeFakeName(i, node)); - } - return NULL; - } - - std::vector elts; - for (int i = 0; i < node->elts.size(); i++) { - elts.push_back(_getFake(_nodeFakeName(i, node))); - } - - llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createList); - ConcreteCompilerVariable *rtn = new ConcreteCompilerVariable(LIST, v, true); - - llvm::Value *f = g.funcs.listAppendInternal; - llvm::Value *bitcast = emitter.getBuilder()->CreateBitCast(v, *llvm::cast(llvm::cast(f->getType())->getElementType())->param_begin()); - - for (int i = 0; i < node->elts.size(); i++) { - CompilerVariable *elt = elts[i]; - ConcreteCompilerVariable *converted = elt->makeConverted(emitter, elt->getBoxType()); - elt->decvref(emitter); - - emitter.getBuilder()->CreateCall2(f, bitcast, converted->getValue()); - converted->decvref(emitter); - } - return rtn; - } - - CompilerVariable* getNone() { - ConcreteCompilerVariable *v = new ConcreteCompilerVariable(typeFromClass(none_cls), embedConstantPtr(None, g.llvm_value_type_ptr), false); - return v; - } - - CompilerVariable* evalName(AST_Name *node) { - if (state == PARTIAL) - return NULL; - - if (irstate->getScopeInfo()->refersToGlobal(node->id)) { - if (1) { - // Method 1: calls into the runtime getGlobal(), which handles things like falling back to builtins - // or raising the correct error message. - bool do_patchpoint = ENABLE_ICGETGLOBALS && emitter.getTarget() != IREmitter::INTERPRETER; - bool from_global = irstate->getSourceInfo()->ast->type == AST_TYPE::Module; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createGetGlobalPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr)); - llvm_args.push_back(embedConstantPtr(&node->id, g.llvm_str_type_ptr)); - llvm_args.push_back(getConstantInt(from_global, g.i1)); - - llvm::Value* uncasted = emitter.createPatchpoint(pp, (void*)pyston::getGlobal, llvm_args); - llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); - return new ConcreteCompilerVariable(UNKNOWN, r, true); - } else { - llvm::Value *r = emitter.getBuilder()->CreateCall3(g.funcs.getGlobal, embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr), embedConstantPtr(&node->id, g.llvm_str_type_ptr), getConstantInt(from_global, g.i1)); - return new ConcreteCompilerVariable(UNKNOWN, r, true); - } - } else { - // Method 2 [testing-only]: (ab)uses existing getattr patchpoints and just calls module.getattr() - // This option exists for performance testing because method 1 does not currently use patchpoints. - ConcreteCompilerVariable *mod = new ConcreteCompilerVariable(MODULE, embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_value_type_ptr), false); - CompilerVariable *attr = mod->getattr(emitter, node->id); - mod->decvref(emitter); - return attr; - } - } else { - if (symbol_table.find(node->id) == symbol_table.end()) { - // TODO should mark as DEAD here, though we won't end up setting all the names appropriately - //state = DEAD; - llvm::CallInst *call = emitter.getBuilder()->CreateCall2(g.funcs.assertNameDefined, getConstantInt(0, g.i1), getStringConstantPtr(node->id + '\0')); - call->setDoesNotReturn(); - return undefVariable(); - } - - std::string defined_name = _getFakeName("is_defined", node->id.c_str()); - ConcreteCompilerVariable *is_defined = static_cast(_getFake(defined_name, true)); - if (is_defined) { - emitter.getBuilder()->CreateCall2(g.funcs.assertNameDefined, is_defined->getValue(), getStringConstantPtr(node->id + '\0')); - } - - CompilerVariable *rtn = symbol_table[node->id]; - rtn->incvref(); - return rtn; - } - } - - CompilerVariable* evalNum(AST_Num *node) { - if (state == PARTIAL) - return NULL; - if (node->num_type == AST_Num::INT) - return makeInt(node->n_int); - else if (node->num_type == AST_Num::FLOAT) - return makeFloat(node->n_float); - else - RELEASE_ASSERT(0, ""); - } - - CompilerVariable* evalSlice(AST_Slice *node) { - if (state == PARTIAL) - return NULL; - - CompilerVariable *start, *stop, *step; - start = node->lower ? evalExpr(node->lower) : getNone(); - stop = node->upper ? evalExpr(node->upper) : getNone(); - step = node->step ? evalExpr(node->step) : getNone(); - - ConcreteCompilerVariable *cstart, *cstop, *cstep; - cstart = start->makeConverted(emitter, start->getBoxType()); - cstop = stop->makeConverted(emitter, stop->getBoxType()); - cstep = step->makeConverted(emitter, step->getBoxType()); - start->decvref(emitter); - stop->decvref(emitter); - step->decvref(emitter); - - std::vector args; - args.push_back(cstart->getValue()); - args.push_back(cstop->getValue()); - args.push_back(cstep->getValue()); - llvm::Value* rtn = emitter.getBuilder()->CreateCall(g.funcs.createSlice, args); - - cstart->decvref(emitter); - cstop->decvref(emitter); - cstep->decvref(emitter); - return new ConcreteCompilerVariable(SLICE, rtn, true); - } - - CompilerVariable* evalStr(AST_Str *node) { - if (state == PARTIAL) - return NULL; - return makeStr(&node->s); - } - - CompilerVariable* evalSubscript(AST_Subscript *node) { - CompilerVariable *value = evalExpr(node->value); - _setFake(_nodeFakeName(0, node), value); // 'fakes' are for handling deopt entries - CompilerVariable *slice = evalExpr(node->slice); - _setFake(_nodeFakeName(1, node), slice); - - if (state == PARTIAL) { - _clearFake(_nodeFakeName(0, node)); - _clearFake(_nodeFakeName(1, node)); - return NULL; - } - value = _getFake(_nodeFakeName(0, node)); - slice = _getFake(_nodeFakeName(1, node)); - - CompilerVariable *rtn = value->getitem(emitter, slice); - value->decvref(emitter); - slice->decvref(emitter); - return rtn; - } - - CompilerVariable* evalTuple(AST_Tuple *node) { - for (int i = 0; i < node->elts.size(); i++) { - CompilerVariable *value = evalExpr(node->elts[i]); - _setFake(_nodeFakeName(i, node), value); - } - - if (state == PARTIAL) { - for (int i = 0; i < node->elts.size(); i++) { - _clearFake(_nodeFakeName(i, node)); - } - return NULL; - } - - std::vector elts; - for (int i = 0; i < node->elts.size(); i++) { - elts.push_back(_getFake(_nodeFakeName(i, node))); - } - - // TODO makeTuple should probably just transfer the vref, but I want to keep things consistent - CompilerVariable *rtn = makeTuple(elts); - for (int i = 0; i < node->elts.size(); i++) { - elts[i]->decvref(emitter); - } - return rtn; - } - - CompilerVariable* evalUnaryOp(AST_UnaryOp *node) { - assert(state != PARTIAL); - - CompilerVariable* operand = evalExpr(node->operand); - - if (node->op_type == AST_TYPE::Not) { - ConcreteCompilerVariable *rtn = operand->nonzero(emitter); - operand->decvref(emitter); - - llvm::Value* v = rtn->getValue(); - assert(v->getType() == g.i1); - llvm::Value* negated = emitter.getBuilder()->CreateNot(v); - rtn->decvref(emitter); - return new ConcreteCompilerVariable(BOOL, negated, true); - } else { - // TODO These are pretty inefficient, but luckily I don't think they're used that often: - ConcreteCompilerVariable *converted = operand->makeConverted(emitter, operand->getBoxType()); - operand->decvref(emitter); - - llvm::Value* rtn = emitter.getBuilder()->CreateCall2(g.funcs.unaryop, converted->getValue(), getConstantInt(node->op_type, g.i32)); - converted->decvref(emitter); - - return new ConcreteCompilerVariable(UNKNOWN, rtn, true); - } - } - - ConcreteCompilerVariable* unboxVar(ConcreteCompilerType *t, llvm::Value *v, bool grabbed) { - if (t == BOXED_INT) { - llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxInt, v); - ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(INT, unboxed, true); - return rtn; - } - if (t == BOXED_FLOAT) { - llvm::Value* unboxed = emitter.getBuilder()->CreateCall(g.funcs.unboxFloat, v); - ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(FLOAT, unboxed, true); - return rtn; - } - return new ConcreteCompilerVariable(t, v, grabbed); - } - - CompilerVariable* evalExpr(AST_expr *node) { - emitter.getBuilder()->SetCurrentDebugLocation(llvm::DebugLoc::get(node->lineno, 0, irstate->getFuncDbgInfo())); - - CompilerVariable *rtn; - switch (node->type) { - case AST_TYPE::Attribute: - rtn = evalAttribute(static_cast(node)); - break; - case AST_TYPE::BinOp: - rtn = evalBinOp(static_cast(node)); - break; - case AST_TYPE::BoolOp: - rtn = evalBoolOp(static_cast(node)); - break; - case AST_TYPE::Call: - rtn = evalCall(static_cast(node)); - break; - case AST_TYPE::Compare: - rtn = evalCompare(static_cast(node)); - break; - case AST_TYPE::Dict: - rtn = evalDict(static_cast(node)); - break; - case AST_TYPE::Index: - rtn = evalIndex(static_cast(node)); - break; - case AST_TYPE::List: - rtn = evalList(static_cast(node)); - break; - case AST_TYPE::Name: - rtn = evalName(static_cast(node)); - break; - case AST_TYPE::Num: - rtn = evalNum(static_cast(node)); - break; - case AST_TYPE::Slice: - rtn = evalSlice(static_cast(node)); - break; - case AST_TYPE::Str: - rtn = evalStr(static_cast(node)); - break; - case AST_TYPE::Subscript: - rtn = evalSubscript(static_cast(node)); - break; - case AST_TYPE::Tuple: - rtn = evalTuple(static_cast(node)); - break; - case AST_TYPE::UnaryOp: - rtn = evalUnaryOp(static_cast(node)); - break; - case AST_TYPE::ClsAttribute: - rtn = evalClsAttribute(static_cast(node)); - break; - default: - printf("Unhandled expr type: %d (irgen.cpp:" STRINGIFY(__LINE__) ")\n", node->type); - exit(1); - } - - if (rtn == NULL) { - assert(state == PARTIAL); - } - - // Out-guarding: - BoxedClass *speculated_class = types->speculatedExprClass(node); - if (speculated_class != NULL && state != PARTIAL) { - assert(rtn); - - ConcreteCompilerType *speculated_type = typeFromClass(speculated_class); - if (VERBOSITY("irgen") >= 1) { - printf("Speculating that %s is actually %s, at ", rtn->getConcreteType()->debugName().c_str(), speculated_type->debugName().c_str()); - PrintVisitor printer; - node->accept(&printer); - printf("\n"); - } - - // That's not really a speculation.... could potentially handle this here, but - // I think it's better to just not generate bad speculations: - assert(!rtn->canConvertTo(speculated_type)); - - ConcreteCompilerVariable *old_rtn = rtn->makeConverted(emitter, UNKNOWN); - rtn->decvref(emitter); - - llvm::Value* guard_check = old_rtn->makeClassCheck(emitter, speculated_class); - assert(guard_check->getType() == g.i1); - createExprTypeGuard(guard_check, node, old_rtn); - - rtn = unboxVar(speculated_type, old_rtn->getValue(), true); - } - - // In-guarding: - GuardList::ExprTypeGuard* guard = in_guards.getNodeTypeGuard(node); - if (guard != NULL) { - if (VERBOSITY("irgen") >= 1) { - printf("merging guard after "); - PrintVisitor printer; - node->accept(&printer); - printf("; is_partial=%d\n", state == PARTIAL); - } - if (state == PARTIAL) { - guard->branch->setSuccessor(1, curblock); - symbol_table = SymbolTable(guard->st); - assert(guard->val); - state = RUNNING; - - return guard->val; - } else { - assert(state == RUNNING); - compareKeyset(&symbol_table, &guard->st); - - assert(symbol_table.size() == guard->st.size()); - llvm::BasicBlock *ramp_block = llvm::BasicBlock::Create(g.context, "deopt_ramp", irstate->getLLVMFunction()); - llvm::BasicBlock *join_block = llvm::BasicBlock::Create(g.context, "deopt_join", irstate->getLLVMFunction()); - SymbolTable joined_st; - for (SymbolTable::iterator it = guard->st.begin(), end = guard->st.end(); it != end; ++it) { - //if (VERBOSITY("irgen") >= 1) printf("merging %s\n", it->first.c_str()); - CompilerVariable *curval = symbol_table[it->first]; - // I'm not sure this is necessary or even correct: - //ASSERT(curval->getVrefs() == it->second->getVrefs(), "%s %d %d", it->first.c_str(), curval->getVrefs(), it->second->getVrefs()); - - ConcreteCompilerType *merged_type = curval->getConcreteType(); - - emitter.getBuilder()->SetInsertPoint(ramp_block); - ConcreteCompilerVariable* converted1 = it->second->makeConverted(emitter, merged_type); - it->second->decvref(emitter); // for makeconverted - //guard->st[it->first] = converted; - //it->second->decvref(emitter); // for the replaced version - - emitter.getBuilder()->SetInsertPoint(curblock); - ConcreteCompilerVariable* converted2 = curval->makeConverted(emitter, merged_type); - curval->decvref(emitter); // for makeconverted - //symbol_table[it->first] = converted; - //curval->decvref(emitter); // for the replaced version - - if (converted1->getValue() == converted2->getValue()) { - joined_st[it->first] = new ConcreteCompilerVariable(merged_type, converted1->getValue(), true); - } else { - emitter.getBuilder()->SetInsertPoint(join_block); - llvm::PHINode* phi = emitter.getBuilder()->CreatePHI(merged_type->llvmType(), 2, it->first); - phi->addIncoming(converted1->getValue(), ramp_block); - phi->addIncoming(converted2->getValue(), curblock); - joined_st[it->first] = new ConcreteCompilerVariable(merged_type, phi, true); - } - - // TODO free dead Variable objects! - } - symbol_table = joined_st; - - emitter.getBuilder()->SetInsertPoint(curblock); - emitter.getBuilder()->CreateBr(join_block); - - emitter.getBuilder()->SetInsertPoint(ramp_block); - emitter.getBuilder()->CreateBr(join_block); - - guard->branch->setSuccessor(1, ramp_block); - - { - ConcreteCompilerType *this_merged_type = rtn->getConcreteType(); - - emitter.getBuilder()->SetInsertPoint(ramp_block); - ConcreteCompilerVariable *converted_guard_rtn = guard->val->makeConverted(emitter, this_merged_type); - guard->val->decvref(emitter); - - emitter.getBuilder()->SetInsertPoint(curblock); - ConcreteCompilerVariable *converted_rtn = rtn->makeConverted(emitter, this_merged_type); - rtn->decvref(emitter); - - emitter.getBuilder()->SetInsertPoint(join_block); - llvm::PHINode* this_phi = emitter.getBuilder()->CreatePHI(this_merged_type->llvmType(), 2); - this_phi->addIncoming(converted_rtn->getValue(), curblock); - this_phi->addIncoming(converted_guard_rtn->getValue(), ramp_block); - rtn = new ConcreteCompilerVariable(this_merged_type, this_phi, true); - - // TODO free dead Variable objects! - } - - curblock = join_block; - emitter.getBuilder()->SetInsertPoint(curblock); - } - } - - return rtn; - } - - static std::string _getFakeName(const char* prefix, const char* token) { - char buf[40]; - snprintf(buf, 40, "!%s_%s", prefix, token); - return std::string(buf); - } - static std::string _nodeFakeName(int idx, AST* node) { - char buf[40]; - snprintf(buf, 40, "%p(%d)_%d", (void*)node, node->type, idx); - return _getFakeName("node", buf); - } - void _setFake(std::string name, CompilerVariable* val) { - assert(name[0] == '!'); - CompilerVariable* &cur = symbol_table[name]; - assert(cur == NULL); - cur = val; - } - CompilerVariable* _clearFake(std::string name) { - assert(name[0] == '!'); - CompilerVariable* rtn = symbol_table[name]; - assert(rtn == NULL); - symbol_table.erase(name); - return rtn; - } - CompilerVariable* _getFake(std::string name, bool allow_missing=false) { - assert(name[0] == '!'); - CompilerVariable* rtn = symbol_table[name]; - if (!allow_missing) - assert(rtn != NULL); - symbol_table.erase(name); - return rtn; - } - - void _doSet(const std::string &name, CompilerVariable* val) { - assert(name != "None"); - if (irstate->getScopeInfo()->refersToGlobal(name)) { - // TODO do something special here so that it knows to only emit a monomorphic inline cache? - ConcreteCompilerVariable* module = new ConcreteCompilerVariable(MODULE, embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_value_type_ptr), false); - module->setattr(emitter, name, val); - module->decvref(emitter); - } else { - CompilerVariable* &prev = symbol_table[name]; - if (prev != NULL) { - prev->decvref(emitter); - } - prev = val; - val->incvref(); - } - } - - void _doSetattr(AST_Attribute* target, CompilerVariable* val) { - assert(state != PARTIAL); - CompilerVariable *t = evalExpr(target->value); - t->setattr(emitter, target->attr, val); - t->decvref(emitter); - } - - void _doSetitem(AST_Subscript* target, CompilerVariable* val) { - assert(state != PARTIAL); - CompilerVariable *tget = evalExpr(target->value); - CompilerVariable *slice = evalExpr(target->slice); - - ConcreteCompilerVariable *converted_target = tget->makeConverted(emitter, tget->getBoxType()); - ConcreteCompilerVariable *converted_slice = slice->makeConverted(emitter, slice->getBoxType()); - tget->decvref(emitter); - slice->decvref(emitter); - - ConcreteCompilerVariable *converted_val = val->makeConverted(emitter, val->getBoxType()); - - bool do_patchpoint = ENABLE_ICSETITEMS && emitter.getTarget() != IREmitter::INTERPRETER; - if (do_patchpoint) { - PatchpointSetupInfo *pp = patchpoints::createSetitemPatchpoint(emitter.currentFunction()); - - std::vector llvm_args; - llvm_args.push_back(converted_target->getValue()); - llvm_args.push_back(converted_slice->getValue()); - llvm_args.push_back(converted_val->getValue()); - - emitter.createPatchpoint(pp, (void*)pyston::setitem, llvm_args); - } else { - emitter.getBuilder()->CreateCall3(g.funcs.setitem, - converted_target->getValue(), converted_slice->getValue(), converted_val->getValue()); - } - - converted_target->decvref(emitter); - converted_slice->decvref(emitter); - converted_val->decvref(emitter); - } - - void _doUnpackTuple(AST_Tuple* target, CompilerVariable* val) { - int ntargets = target->elts.size(); - ConcreteCompilerVariable *len = val->len(emitter); - emitter.getBuilder()->CreateCall2(g.funcs.checkUnpackingLength, - getConstantInt(ntargets, g.i64), len->getValue()); - - for (int i = 0; i < ntargets; i++) { - CompilerVariable *unpacked = val->getitem(emitter, makeInt(i)); - _doSet(target->elts[i], unpacked); - unpacked->decvref(emitter); - } - } - - void _doSet(AST* target, CompilerVariable* val) { - switch (target->type) { - case AST_TYPE::Attribute: - _doSetattr(static_cast(target), val); - break; - case AST_TYPE::Name: - _doSet(static_cast(target)->id, val); - break; - case AST_TYPE::Subscript: - _doSetitem(static_cast(target), val); - break; - case AST_TYPE::Tuple: - _doUnpackTuple(static_cast(target), val); - break; - default: - ASSERT(0, "Unknown type for IRGenerator: %d", target->type); - abort(); - } - } - - void doAssign(AST_Assign *node) { - CompilerVariable *val = evalExpr(node->value); - if (state == PARTIAL) - return; - for (int i = 0; i < node->targets.size(); i++) { - _doSet(node->targets[i], val); - } - val->decvref(emitter); - } - - void doClassDef(AST_ClassDef *node) { - if (state == PARTIAL) - return; - - ScopeInfo *scope_info = irstate->getSourceInfo()->scoping->getScopeInfoForNode(node); - - llvm::Value *classobj = emitter.getBuilder()->CreateCall2(g.funcs.createClass, embedConstantPtr(&node->name, g.llvm_str_type_ptr), embedConstantPtr(irstate->getSourceInfo()->parent_module, g.llvm_module_type_ptr)); - ConcreteCompilerVariable* cls = new ConcreteCompilerVariable(typeFromClass(type_cls), classobj, true); - - RELEASE_ASSERT(node->bases.size() == 1, ""); - RELEASE_ASSERT(node->bases[0]->type == AST_TYPE::Name, ""); - RELEASE_ASSERT(static_cast(node->bases[0])->id == "object", ""); - - //CompilerVariable* name = makeStr(&node->name); - //cls->setattr(emitter, "__name__", name); - //name->decvref(emitter); - - for (int i = 0, n = node->body.size(); i < n; i++) { - AST_TYPE::AST_TYPE type = node->body[i]->type; - if (type == AST_TYPE::Pass) { - continue; - } else if (type == AST_TYPE::FunctionDef) { - AST_FunctionDef *fdef = static_cast(node->body[i]); - CLFunction *cl = this->_wrapFunction(fdef); - CompilerVariable *func = makeFunction(emitter, cl); - cls->setattr(emitter, fdef->name, func); - func->decvref(emitter); - } else { - RELEASE_ASSERT(node->body[i]->type == AST_TYPE::Pass, "%d", type); - } - } - - _doSet(node->name, cls); - cls->decvref(emitter); - } - - CLFunction* _wrapFunction(AST_FunctionDef *node) { - // Different compilations of the parent scope of a functiondef should lead - // to the same CLFunction* being used: - static std::unordered_map made; - - CLFunction* &cl = made[node]; - if (cl == NULL) { - SourceInfo *si = new SourceInfo(irstate->getSourceInfo()->parent_module, irstate->getSourceInfo()->scoping); - si->ast = node; - cl = new CLFunction(si); - } - return cl; - } - - void doFunction(AST_FunctionDef *node) { - if (state == PARTIAL) - return; - - CLFunction *cl = this->_wrapFunction(node); - CompilerVariable *func = makeFunction(emitter, cl); - - //llvm::Type* boxCLFuncArgType = g.funcs.boxCLFunction->arg_begin()->getType(); - //llvm::Value *boxed = emitter.getBuilder()->CreateCall(g.funcs.boxCLFunction, embedConstantPtr(cl, boxCLFuncArgType)); - //CompilerVariable *func = new ConcreteCompilerVariable(typeFromClass(function_cls), boxed, true); - - _doSet(node->name, func); - func->decvref(emitter); - } - - void doIf(AST_If *node) { - assert(0); - } - - void doImport(AST_Import *node) { - for (int i = 0; i < node->names.size(); i++) { - AST_alias *alias = node->names[i]; - - std::string &modname = alias->name; - std::string &asname = alias->asname.size() ? alias->asname : alias->name; - - llvm::Value* imported = emitter.getBuilder()->CreateCall(g.funcs.import, embedConstantPtr(&modname, g.llvm_str_type_ptr)); - ConcreteCompilerVariable *v = new ConcreteCompilerVariable(UNKNOWN, imported, true); - _doSet(asname, v); - v->decvref(emitter); - } - } - - void doPrint(AST_Print *node) { - assert(node->dest == NULL); - for (int i = 0; i < node->values.size(); i++) { - if (i > 0) { - emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" ")); - } - CompilerVariable* var = evalExpr(node->values[i]); - if (state != PARTIAL) { - var->print(emitter); - var->decvref(emitter); - } - } - if (state != PARTIAL) { - if (node->nl) - emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr("\n")); - else - emitter.getBuilder()->CreateCall(g.funcs.printf, getStringConstantPtr(" ")); - } - } - - void doReturn(AST_Return *node) { - CompilerVariable *val; - if (node->value == NULL) { - if (irstate->getReturnType() == VOID) { - endBlock(DEAD); - emitter.getBuilder()->CreateRetVoid(); - return; - } - - val = new ConcreteCompilerVariable(NONE, embedConstantPtr(None, g.llvm_value_type_ptr), false); - } else { - val = evalExpr(node->value); - assert(state != PARTIAL); - } - assert(val); - - // If we ask the return variable to become UNKNOWN (the typical return type), - // it will be forced to split a copy of itself and incref. - // But often the return variable will already be in the right shape, so in - // that case asking it to convert to itself ends up just being an incvref - // and doesn't end up emitting an incref+decref pair. - // This could also be handled by casting from the CompilerVariable to - // ConcreteCOmpilerVariable, but this way feels a little more robust to me. - ConcreteCompilerType *opt_rtn_type = irstate->getReturnType(); - if (irstate->getReturnType()->llvmType() == val->getConcreteType()->llvmType()) - opt_rtn_type = val->getConcreteType(); - - ConcreteCompilerVariable* rtn = val->makeConverted(emitter, opt_rtn_type); - rtn->ensureGrabbed(emitter); - val->decvref(emitter); - - endBlock(DEAD); - - assert(rtn->getVrefs() == 1); - emitter.getBuilder()->CreateRet(rtn->getValue()); - } - - void doBranch(AST_Branch *node) { - assert(node->iftrue->idx > myblock->idx); - assert(node->iffalse->idx > myblock->idx); - - CompilerVariable *val = evalExpr(node->test); - assert(state != PARTIAL); - - ConcreteCompilerVariable* nonzero = val->nonzero(emitter); - assert(nonzero->getType() == BOOL); - val->decvref(emitter); - - llvm::Value *llvm_nonzero = nonzero->getValue(); - llvm::BasicBlock *iftrue = entry_blocks[node->iftrue->idx]; - llvm::BasicBlock *iffalse = entry_blocks[node->iffalse->idx]; - - nonzero->decvref(emitter); - - endBlock(FINISHED); - - emitter.getBuilder()->CreateCondBr(llvm_nonzero, iftrue, iffalse); - } - - void doExpr(AST_Expr *node) { - CompilerVariable *var = evalExpr(node->value); - if (state != PARTIAL) - var->decvref(emitter); - } - - void doOSRExit(llvm::BasicBlock *normal_target, AST_Jump* osr_key) { - llvm::BasicBlock *starting_block = curblock; - llvm::BasicBlock *onramp = llvm::BasicBlock::Create(g.context, "onramp", irstate->getLLVMFunction()); - - // Code to check if we want to do the OSR: - llvm::GlobalVariable* edgecount_ptr = new llvm::GlobalVariable(*g.cur_module, g.i64, false, llvm::GlobalValue::InternalLinkage, getConstantInt(0, g.i64), "edgecount"); - llvm::Value* curcount = emitter.getBuilder()->CreateLoad(edgecount_ptr); - llvm::Value* newcount = emitter.getBuilder()->CreateAdd(curcount, getConstantInt(1, g.i64)); - emitter.getBuilder()->CreateStore(newcount, edgecount_ptr); - - int OSR_THRESHOLD = 10000; - if (irstate->getEffortLevel() == EffortLevel::INTERPRETED) - OSR_THRESHOLD = 100; - llvm::Value* osr_test = emitter.getBuilder()->CreateICmpSGT(newcount, getConstantInt(OSR_THRESHOLD)); - - llvm::Value* md_vals[] = {llvm::MDString::get(g.context, "branch_weights"), getConstantInt(1), getConstantInt(1000)}; - llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef(md_vals)); - emitter.getBuilder()->CreateCondBr(osr_test, onramp, normal_target, branch_weights); - - // Emitting the actual OSR: - emitter.getBuilder()->SetInsertPoint(onramp); - OSRExit* exit = new OSRExit(irstate->getCurFunction(), OSREntryDescriptor::create(irstate->getCurFunction(), osr_key)); - llvm::Value* partial_func = emitter.getBuilder()->CreateCall(g.funcs.compilePartialFunc, embedConstantPtr(exit, g.i8->getPointerTo())); - - std::vector llvm_args; - std::vector llvm_arg_types; - std::vector converted_args; - - SortedSymbolTable sorted_symbol_table(symbol_table.begin(), symbol_table.end()); - /* - for (SortedSymbolTable::iterator it = sorted_symbol_table.begin(), end = sorted_symbol_table.end(); it != end; ) { - if (!source->liveness->isLiveAtEnd(it->first, myblock)) { - // I think this line can never get hit: nothing can die on a backedge, since control flow can eventually - // reach this block again, where the symbol was live (as shown by it being in the symbol table) - printf("Not sending %s to osr since it will die\n", it->first.c_str()); - it = sorted_symbol_table.erase(it); - } else { - ++it; - } - }*/ - - // For OSR calls, we use the same calling convention as in some other places; namely, - // arg1, arg2, arg3, argarray [nargs is ommitted] - // It would be nice to directly pass all variables as arguments, instead of packing them into - // an array, for a couple reasons (eliminate copies, and allow for a tail call). - // But this doesn't work if the IR is being interpreted, because the interpreter can't - // do arbitrary-arity function calls (yet?). One possibility is to pass them as an - // array for the interpreter and as all arguments for compilation, but I'd rather avoid - // having two different calling conventions for the same thing. Plus, this would - // prevent us from having two OSR exits point to the same OSR entry; not something that - // we're doing right now but something that would be nice in the future. - - llvm::Value *arg_array = NULL, *malloc_save = NULL; - if (sorted_symbol_table.size() > 3) { - // Leave in the ability to use malloc but I guess don't use it. - // Maybe if there are a ton of live variables it'd be nice to have them be - // heap-allocated, or if we don't immediately return the result of the OSR? - bool use_malloc = false; - if (false) { - llvm::Value *n_bytes = getConstantInt((sorted_symbol_table.size() - 3) * sizeof(Box*), g.i64); - llvm::Value *l_malloc = embedConstantPtr((void*)malloc, llvm::FunctionType::get(g.i8->getPointerTo(), g.i64, false)->getPointerTo()); - malloc_save = emitter.getBuilder()->CreateCall(l_malloc, n_bytes); - arg_array = emitter.getBuilder()->CreateBitCast(malloc_save, g.llvm_value_type_ptr->getPointerTo()); - } else { - llvm::Value *n_varargs = llvm::ConstantInt::get(g.i64, sorted_symbol_table.size() - 3, false); - arg_array = emitter.getBuilder()->CreateAlloca(g.llvm_value_type_ptr, n_varargs); - } - } - - int i = 0; - for (SortedSymbolTable::iterator it = sorted_symbol_table.begin(), end = sorted_symbol_table.end(); it != end; ++it, ++i) { - // I don't think this can fail, but if it can we should filter out dead symbols before - // passing them on: - assert(irstate->getSourceInfo()->liveness->isLiveAtEnd(it->first, myblock)); - - // This line can never get hit right now since we unnecessarily force every variable to be concrete - // for a loop, since we generate all potential phis: - ASSERT(it->second->getType() == it->second->getConcreteType(), "trying to pass through %s\n", it->second->getType()->debugName().c_str()); - - ConcreteCompilerVariable* var = it->second->makeConverted(emitter, it->second->getConcreteType()); - converted_args.push_back(var); - - assert(var->getType() != BOXED_INT && "should probably unbox it, but why is it boxed in the first place?"); - assert(var->getType() != BOXED_FLOAT && "should probably unbox it, but why is it boxed in the first place?"); - - // This line can never get hit right now for the same reason that the variables must already be concrete, - // because we're over-generating phis. - ASSERT(var->isGrabbed(), "%s", it->first.c_str()); - //var->ensureGrabbed(emitter); - - llvm::Value* val = var->getValue(); - - if (i < 3) { - llvm_args.push_back(val); - llvm_arg_types.push_back(val->getType()); - } else { - llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, i-3); - - if (var->getType() == INT) { - val = emitter.getBuilder()->CreateIntToPtr(val, g.llvm_value_type_ptr); - } else if (var->getType() == FLOAT) { - //val = emitter.getBuilder()->CreateBitCast(val, g.llvm_value_type_ptr); - ptr = emitter.getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo()); - } else { - assert(val->getType() == g.llvm_value_type_ptr); - } - - emitter.getBuilder()->CreateStore(val, ptr); - } - - ConcreteCompilerType* &t = exit->entry->args[it->first]; - if (t == NULL) - t = var->getType(); - else - ASSERT(t == var->getType(), "%s %s\n", t->debugName().c_str(), var->getType()->debugName().c_str()); - } - - if (sorted_symbol_table.size() > 3) { - llvm_args.push_back(arg_array); - llvm_arg_types.push_back(arg_array->getType()); - } - - llvm::FunctionType* ft = llvm::FunctionType::get(irstate->getReturnType()->llvmType(), llvm_arg_types, false /*vararg*/); - partial_func = emitter.getBuilder()->CreateBitCast(partial_func, ft->getPointerTo()); - - llvm::CallInst *rtn = emitter.getBuilder()->CreateCall(partial_func, llvm_args); - - // If we alloca'd the arg array, we can't make this into a tail call: - if (arg_array == NULL && malloc_save != NULL) { - rtn->setTailCall(true); - } - - if (malloc_save != NULL) { - llvm::Value *l_free = embedConstantPtr((void*)free, llvm::FunctionType::get(g.void_, g.i8->getPointerTo(), false)->getPointerTo()); - emitter.getBuilder()->CreateCall(l_free, malloc_save); - } - - for (int i = 0; i < converted_args.size(); i++) { - converted_args[i]->decvref(emitter); - } - - if (irstate->getReturnType() == VOID) - emitter.getBuilder()->CreateRetVoid(); - else - emitter.getBuilder()->CreateRet(rtn); - - emitter.getBuilder()->SetInsertPoint(starting_block); - } - - void doJump(AST_Jump *node) { - endBlock(FINISHED); - - llvm::BasicBlock *target = entry_blocks[node->target->idx]; - - if (ENABLE_OSR && node->target->idx < myblock->idx && irstate->getEffortLevel() < EffortLevel::MAXIMAL) { - assert(node->target->predecessors.size() > 1); - doOSRExit(target, node); - } else { - emitter.getBuilder()->CreateBr(target); - } - } - - void doStmt(AST *node) { - switch (node->type) { - case AST_TYPE::Assign: - doAssign(static_cast(node)); - break; - case AST_TYPE::ClassDef: - doClassDef(static_cast(node)); - break; - case AST_TYPE::Expr: - doExpr(static_cast(node)); - break; - case AST_TYPE::FunctionDef: - doFunction(static_cast(node)); - break; - case AST_TYPE::If: - doIf(static_cast(node)); - break; - case AST_TYPE::Import: - doImport(static_cast(node)); - break; - case AST_TYPE::Global: - // Should have been handled already - break; - case AST_TYPE::Pass: - break; - case AST_TYPE::Print: - doPrint(static_cast(node)); - break; - case AST_TYPE::Return: - doReturn(static_cast(node)); - break; - case AST_TYPE::Branch: - doBranch(static_cast(node)); - break; - case AST_TYPE::Jump: - doJump(static_cast(node)); - break; - default: - printf("Unhandled stmt type at " __FILE__ ":" STRINGIFY(__LINE__) ": %d\n", node->type); - exit(1); - } - } - - template - void loadArgument(const T &name, ConcreteCompilerType* t, llvm::Value* v) { - ConcreteCompilerVariable *var = unboxVar(t, v, false); - _doSet(name, var); - var->decvref(emitter); - } - - void endBlock(State new_state) { - assert(state == RUNNING); - - //cf->func->dump(); - - SourceInfo* source = irstate->getSourceInfo(); - ScopeInfo *scope_info = irstate->getScopeInfo(); - - for (SymbolTable::iterator it = symbol_table.begin(); it != symbol_table.end();) { - ASSERT(it->first[0] != '!' || startswith(it->first, "!is_defined"), "left a fake variable in the real symbol table? '%s'", it->first.c_str()); - - if (!source->liveness->isLiveAtEnd(it->first, myblock)) { - //printf("%s dead at end of %d; grabbed = %d, %d vrefs\n", it->first.c_str(), myblock->idx, it->second->isGrabbed(), it->second->getVrefs()); - it->second->decvref(emitter); - it = symbol_table.erase(it); - } else if (source->phis->isRequiredAfter(it->first, myblock)) { - assert(!scope_info->refersToGlobal(it->first)); - ConcreteCompilerType *phi_type = types->getTypeAtBlockEnd(it->first, myblock); - //printf("Converting %s from %s to %s\n", it->first.c_str(), it->second->getType()->debugName().c_str(), phi_type->debugName().c_str()); - //printf("have to convert %s from %s to %s\n", it->first.c_str(), it->second->getType()->debugName().c_str(), phi_type->debugName().c_str()); - ConcreteCompilerVariable *v = it->second->makeConverted(emitter, phi_type); - it->second->decvref(emitter); - symbol_table[it->first] = v->split(emitter); - it++; - } else { -#ifndef NDEBUG - // TODO getTypeAtBlockEnd will automatically convert up to the concrete type, which we don't want here, - // but this is just for debugging so I guess let it happen for now: - ConcreteCompilerType *ending_type = types->getTypeAtBlockEnd(it->first, myblock); - ASSERT(it->second->canConvertTo(ending_type), "%s is supposed to be %s, but somehow is %s", it->first.c_str(), ending_type->debugName().c_str(), it->second->getType()->debugName().c_str()); -#endif - - it++; - } - } - - const PhiAnalysis::RequiredSet &all_phis = source->phis->getAllRequiredAfter(myblock); - for (PhiAnalysis::RequiredSet::const_iterator it = all_phis.begin(), end = all_phis.end(); it != end; ++it) { - //printf("phi will be required for %s\n", it->c_str()); - assert(!scope_info->refersToGlobal(*it)); - CompilerVariable* &cur = symbol_table[*it]; - - if (cur != NULL) { - if (source->phis->isPotentiallyUndefinedAfter(*it, myblock)) { - //printf("is potentially undefined\n"); - _setFake(_getFakeName("is_defined", it->c_str()), new ConcreteCompilerVariable(BOOL, getConstantInt(1, g.i1), true)); - } else { - //printf("is definitely defined\n"); - } - } else { - //printf("no st entry, setting undefined\n"); - ConcreteCompilerType *phi_type = types->getTypeAtBlockEnd(*it, myblock); - cur = new ConcreteCompilerVariable(phi_type, llvm::UndefValue::get(phi_type->llvmType()), true); - _setFake(_getFakeName("is_defined", it->c_str()), new ConcreteCompilerVariable(BOOL, getConstantInt(0, g.i1), true)); - } - } - - state = new_state; - } - - public: - struct EndingState { - SymbolTable* symbol_table; - ConcreteSymbolTable* phi_symbol_table; - llvm::BasicBlock* ending_block; - EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table, llvm::BasicBlock* ending_block) : - symbol_table(symbol_table), phi_symbol_table(phi_symbol_table), ending_block(ending_block) {} - }; - - EndingState getEndingSymbolTable() { - assert(state == FINISHED || state == DEAD); - - //for (SymbolTable::iterator it = symbol_table.begin(); it != symbol_table.end(); ++it) { - //printf("%s %p %d\n", it->first.c_str(), it->second, it->second->getVrefs()); - //} - - SourceInfo* source = irstate->getSourceInfo(); - - SymbolTable *st = new SymbolTable(symbol_table); - ConcreteSymbolTable *phi_st = new ConcreteSymbolTable(); - for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) { - if (it->first[0] == '!') { - ASSERT(startswith(it->first, _getFakeName("is_defined", "")), "left a fake variable in the real symbol table? '%s'", it->first.c_str()); - } else { - ASSERT(source->liveness->isLiveAtEnd(it->first, myblock), "%s", it->first.c_str()); - } - } - - if (myblock->successors.size() == 0) { - assert(st->size() == 0); // shouldn't have anything live if there are no successors! - return EndingState(st, phi_st, curblock); - } else if (myblock->successors.size() > 1) { - // Since there are no critical edges, all successors come directly from this node, - // so there won't be any required phis. - return EndingState(st, phi_st, curblock); - } - - assert(myblock->successors.size() == 1); // other cases should have been handled - for (SymbolTable::iterator it = st->begin(); it != st->end();) { - if (startswith(it->first, "!is_defined") || source->phis->isRequiredAfter(it->first, myblock)) { - assert(it->second->isGrabbed()); - assert(it->second->getVrefs() == 1); - // this conversion should have already happened... should refactor this. - ConcreteCompilerType *ending_type; - if (startswith(it->first, "!is_defined")) { - assert(it->second->getType() == BOOL); - ending_type = BOOL; - } else { - ending_type = types->getTypeAtBlockEnd(it->first, myblock); - } - //(*phi_st)[it->first] = it->second->makeConverted(emitter, it->second->getConcreteType()); - //printf("%s %p %d\n", it->first.c_str(), it->second, it->second->getVrefs()); - (*phi_st)[it->first] = it->second->split(emitter)->makeConverted(emitter, ending_type); - it = st->erase(it); - } else { - ++it; - } - } - return EndingState(st, phi_st, curblock); - } - - void giveLocalSymbol(const std::string &name, CompilerVariable *var) { - assert(name != "None"); - ASSERT(!irstate->getScopeInfo()->refersToGlobal(name), "%s", name.c_str()); - assert(var->getType() != BOXED_INT); - assert(var->getType() != BOXED_FLOAT); - CompilerVariable* &cur = symbol_table[name]; - assert(cur == NULL); - cur = var; - } - - void copySymbolsFrom(SymbolTable* st) { - assert(st); - DupCache cache; - for (SymbolTable::iterator it = st->begin(); it != st->end(); it++) { - //printf("Copying in %s: %p, %d\n", it->first.c_str(), it->second, it->second->getVrefs()); - symbol_table[it->first] = it->second->dup(cache); - //printf("got: %p, %d\n", symbol_table[it->first], symbol_table[it->first]->getVrefs()); - } - } - - void unpackArguments(const std::vector &arg_names, const std::vector &arg_types) { - int i = 0; - llvm::Value* argarray = NULL; - for (llvm::Function::arg_iterator AI = irstate->getLLVMFunction()->arg_begin(); AI != irstate->getLLVMFunction()->arg_end(); AI++, i++) { - if (i == 3) { - argarray = AI; - break; - } - loadArgument(arg_names[i], arg_types[i], AI); - } - - for (int i = 3; i < arg_types.size(); i++) { - llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(argarray, i-3); - llvm::Value* loaded = emitter.getBuilder()->CreateLoad(ptr); - - if (arg_types[i]->llvmType() == g.i64) - loaded = emitter.getBuilder()->CreatePtrToInt(loaded, arg_types[i]->llvmType()); - else - assert(arg_types[i]->llvmType() == g.llvm_value_type_ptr); - - loadArgument(arg_names[i], arg_types[i], loaded); - } - } - - void run(const CFGBlock* block) { - for (int i = 0; i < block->body.size(); i++) { - if (state == DEAD) - break; - assert(state != FINISHED); - doStmt(block->body[i]); - } - } - -}; - -static bool compareBlockPairs (const std::pair& p1, const std::pair& p2) { - return p1.first->idx < p2.first->idx; -} - -static std::vector > computeBlockTraversalOrder(const BlockSet &full_blocks, const BlockSet &partial_blocks, CFGBlock *start) { - - std::vector > rtn; - std::unordered_set in_queue; - - if (start) { - assert(full_blocks.count(start)); - in_queue.insert(start); - rtn.push_back(std::make_pair(start, (CFGBlock*)NULL)); - } - - for (BlockSet::const_iterator it = partial_blocks.begin(), end = partial_blocks.end(); it != end; ++it) { - in_queue.insert(*it); - rtn.push_back(std::make_pair(*it, (CFGBlock*)NULL)); - } - - // It's important for debugging purposes that the order is deterministic, but the iteration - // over the BlockSet is not: - std::sort(rtn.begin(), rtn.end(), compareBlockPairs); - - int idx = 0; - while (rtn.size() < full_blocks.size() + partial_blocks.size()) { - // TODO: come up with an alternative algorithm that outputs - // the blocks in "as close to in-order as possible". - // Do this by iterating over all blocks and picking the smallest one - // that has a predecessor in the list already. - while (idx < rtn.size()) { - CFGBlock *cur = rtn[idx].first; - - for (int i = 0; i < cur->successors.size(); i++) { - CFGBlock *b = cur->successors[i]; - assert(full_blocks.count(b) || partial_blocks.count(b)); - if (in_queue.count(b)) - continue; - - rtn.push_back(std::make_pair(b, cur)); - in_queue.insert(b); - } - - idx++; - } - - if (rtn.size() == full_blocks.size() + partial_blocks.size()) - break; - - CFGBlock *best = NULL; - for (BlockSet::const_iterator it = full_blocks.begin(), end = full_blocks.end(); it != end; ++it) { - CFGBlock *b = *it; - if (in_queue.count(b)) - continue; - - // Avoid picking any blocks where we can't add an epilogue to the predecessors - if (b->predecessors.size() == 1 && b->predecessors[0]->successors.size() > 1) - continue; - - if (best == NULL || b->idx < best->idx) - best = b; - } - assert(best != NULL); - - if (VERBOSITY("irgen") >= 1) printf("Giving up and adding block %d to the order\n", best->idx); - in_queue.insert(best); - rtn.push_back(std::make_pair(best, (CFGBlock*)NULL)); - } - - ASSERT(rtn.size() == full_blocks.size() + partial_blocks.size(), "%ld\n", rtn.size()); - return rtn; -} - -static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_guards, const GuardList &in_guards, TypeAnalysis *types, const std::vector &arg_names, const OSREntryDescriptor *entry_descriptor, const BlockSet &full_blocks, const BlockSet &partial_blocks) { - SourceInfo *source = irstate->getSourceInfo(); - EffortLevel::EffortLevel effort = irstate->getEffortLevel(); - CompiledFunction *cf = irstate->getCurFunction(); - ConcreteCompilerType *rtn_type = irstate->getReturnType(); - llvm::MDNode* func_info = irstate->getFuncDbgInfo(); - - if (entry_descriptor != NULL) - assert(full_blocks.count(source->cfg->blocks[0]) == 0); - - // We need the entry blocks pre-allocated so that we can jump forward to them. - std::vector llvm_entry_blocks; - for (int i = 0; i < source->cfg->blocks.size(); i++) { - CFGBlock *block = source->cfg->blocks[i]; - if (partial_blocks.count(block) == 0 && full_blocks.count(block) == 0) { - llvm_entry_blocks.push_back(NULL); - continue; - } - - char buf[40]; - snprintf(buf, 40, "%s_block%d", bb_type, i); - llvm_entry_blocks.push_back(llvm::BasicBlock::Create(g.context, buf, irstate->getLLVMFunction())); - } - - llvm::BasicBlock *osr_entry_block = NULL; // the function entry block, where we add the type guards - llvm::BasicBlock *osr_unbox_block = NULL; // the block after type guards where we up/down-convert things - ConcreteSymbolTable *osr_syms = NULL; // syms after conversion - if (entry_descriptor != NULL) { - osr_unbox_block = llvm::BasicBlock::Create(g.context, "osr_unbox", irstate->getLLVMFunction(), &irstate->getLLVMFunction()->getEntryBlock()); - osr_entry_block = llvm::BasicBlock::Create(g.context, "osr_entry", irstate->getLLVMFunction(), &irstate->getLLVMFunction()->getEntryBlock()); - assert(&irstate->getLLVMFunction()->getEntryBlock() == osr_entry_block); - - osr_syms = new ConcreteSymbolTable(); - SymbolTable *initial_syms = new SymbolTable(); - //llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block); - - IREmitterImpl entry_emitter(irstate); - entry_emitter.getBuilder()->SetInsertPoint(osr_entry_block); - IREmitterImpl unbox_emitter(irstate); - unbox_emitter.getBuilder()->SetInsertPoint(osr_unbox_block); - - CFGBlock *target_block = entry_descriptor->backedge->target; - - // Currently we AND all the type guards together and then do just a single jump; - // guard_val is the current AND'd value, or NULL if there weren't any guards - llvm::Value *guard_val = NULL; - - std::vector func_args; - for (llvm::Function::arg_iterator AI = irstate->getLLVMFunction()->arg_begin(); AI != irstate->getLLVMFunction()->arg_end(); AI++) { - func_args.push_back(AI); - } - - // Handle loading symbols from the passed osr arguments: - int i = 0; - for (OSREntryDescriptor::ArgMap::const_iterator it = entry_descriptor->args.begin(), end = entry_descriptor->args.end(); it != end; ++it, ++i) { - llvm::Value* from_arg; - if (i < 3) { - from_arg = func_args[i]; - } else { - ASSERT(func_args.size() == 4, "%ld", func_args.size()); - llvm::Value* ptr = entry_emitter.getBuilder()->CreateConstGEP1_32(func_args[3], i-3); - if (it->second == INT) { - ptr = entry_emitter.getBuilder()->CreateBitCast(ptr, g.i64->getPointerTo()); - } else if (it->second == FLOAT) { - ptr = entry_emitter.getBuilder()->CreateBitCast(ptr, g.double_->getPointerTo()); - } - from_arg = entry_emitter.getBuilder()->CreateLoad(ptr); - assert(from_arg->getType() == it->second->llvmType()); - } - - ConcreteCompilerType *phi_type = types->getTypeAtBlockStart(it->first, target_block); - //ConcreteCompilerType *analyzed_type = types->getTypeAtBlockStart(it->first, block); - //ConcreteCompilerType *phi_type = (*phis)[it->first].first; - - ConcreteCompilerVariable *var = new ConcreteCompilerVariable(it->second, from_arg, true); - (*initial_syms)[it->first] = var; - - // It's possible to OSR into a version of the function with a higher speculation level; - // this means that the types of the OSR variables are potentially higher (more unspecialized) - // than what the optimized code expects. - // So, we have to re-check the speculations and potentially deopt. - llvm::Value *v = NULL; - if (it->second == phi_type) { - // good to go - v = from_arg; - } else if (it->second->canConvertTo(phi_type)) { - // not sure if/when this happens, but if there's a type mismatch but one we know - // can be handled (such as casting from a subclass to a superclass), handle it: - ConcreteCompilerVariable *converted = var->makeConverted(unbox_emitter, phi_type); - v = converted->getValue(); - delete converted; - } else { - ASSERT(it->second == UNKNOWN, "%s", it->second->debugName().c_str()); - BoxedClass *speculated_class = NULL; - if (phi_type == INT) { - speculated_class = int_cls; - } else if (phi_type == FLOAT) { - speculated_class = float_cls; - } else { - speculated_class = phi_type->guaranteedClass(); - } - ASSERT(speculated_class, "%s", phi_type->debugName().c_str()); - - llvm::Value* type_check = ConcreteCompilerVariable(it->second, from_arg, true).makeClassCheck(entry_emitter, speculated_class); - if (guard_val) { - guard_val = entry_emitter.getBuilder()->CreateAnd(guard_val, type_check); - } else { - guard_val = type_check; - } - //entry_emitter.getBuilder()->CreateCall(g.funcs.my_assert, type_check); - - if (speculated_class == int_cls) { - v = unbox_emitter.getBuilder()->CreateCall(g.funcs.unboxInt, from_arg); - (new ConcreteCompilerVariable(BOXED_INT, from_arg, true))->decvref(unbox_emitter); - } else if (speculated_class == float_cls) { - v = unbox_emitter.getBuilder()->CreateCall(g.funcs.unboxFloat, from_arg); - (new ConcreteCompilerVariable(BOXED_FLOAT, from_arg, true))->decvref(unbox_emitter); - } else { - assert(phi_type == typeFromClass(speculated_class)); - v = from_arg; - } - } - - if (VERBOSITY("irgen")) v->setName("prev_" + it->first); - - (*osr_syms)[it->first] = new ConcreteCompilerVariable(phi_type, v, true); - } - - if (guard_val) { - llvm::BranchInst *br = entry_emitter.getBuilder()->CreateCondBr(guard_val, osr_unbox_block, osr_unbox_block); - out_guards.registerGuardForBlockEntry(target_block, br, *initial_syms); - } else { - entry_emitter.getBuilder()->CreateBr(osr_unbox_block); - } - unbox_emitter.getBuilder()->CreateBr(llvm_entry_blocks[entry_descriptor->backedge->target->idx]); - - for (SymbolTable::iterator it = initial_syms->begin(), end = initial_syms->end(); it != end; ++it) { - delete it->second; - } - delete initial_syms; - } - - // In a similar vein, we need to keep track of the exit blocks for each cfg block, - // so that we can construct phi nodes later. - // Originally I preallocated these blocks as well, but we can construct the phi's - // after the fact, so we can just record the exit blocks as we go along. - std::unordered_map llvm_exit_blocks; - - //// - // Main ir generation: go through each basic block in the CFG and emit the code - - std::unordered_map ending_symbol_tables; - std::unordered_map phi_ending_symbol_tables; - typedef std::unordered_map > PHITable; - std::unordered_map created_phis; - - CFGBlock* initial_block = NULL; - if (entry_descriptor) { - initial_block = entry_descriptor->backedge->target; - } else if (full_blocks.count(source->cfg->blocks[0])) { - initial_block = source->cfg->blocks[0]; - } - - // The rest of this code assumes that for each non-entry block that gets evaluated, - // at least one of its predecessors has been evaluated already (from which it will - // get type information). - // The cfg generation code will generate a cfg such that each block has a predecessor - // with a lower index value, so if the entry block is 0 then we can iterate in index - // order. - // The entry block doesn't have to be zero, so we have to calculate an allowable order here: - std::vector > traversal_order = computeBlockTraversalOrder(full_blocks, partial_blocks, initial_block); - - std::unordered_set into_hax; - for (int _i = 0; _i < traversal_order.size(); _i++) { - CFGBlock *block = traversal_order[_i].first; - CFGBlock *pred = traversal_order[_i].second; - //for (int _i = 0; _i < source->cfg->blocks.size(); _i++) { - //CFGBlock *block = source->cfg->blocks[_i]; - //CFGBlock *pred = NULL; - //if (block->predecessors.size()) - //CFGBlock *pred = block->predecessors[0]; - - if (VERBOSITY("irgen") >= 1) printf("processing %s block %d\n", bb_type, block->idx); - - bool is_partial = false; - if (partial_blocks.count(block)) { - if (VERBOSITY("irgen") >= 1) printf("is partial block\n"); - is_partial = true; - } else if (!full_blocks.count(block)) { - if (VERBOSITY("irgen") >= 1) printf("Skipping this block\n"); - //created_phis[block->idx] = NULL; - //ending_symbol_tables[block->idx] = NULL; - //phi_ending_symbol_tables[block->idx] = NULL; - //llvm_exit_blocks[block->idx] = NULL; - continue; - } - - IRGenerator generator(irstate, llvm_entry_blocks, block, types, out_guards, in_guards, is_partial); - IREmitterImpl emitter(irstate); - emitter.getBuilder()->SetInsertPoint(llvm_entry_blocks[block->idx]); - - PHITable* phis = NULL; - if (!is_partial) { - phis = new PHITable(); - created_phis[block->idx] = phis; - } - - // Set initial symbol table: - if (is_partial) { - // pass - } else if (block->idx == 0) { - assert(entry_descriptor == NULL); - // number of times a function needs to be called to be reoptimized: - static const int REOPT_THRESHOLDS[] = { - 10, // INTERPRETED->MINIMAL - 250, // MINIMAL->MODERATE - 10000, // MODERATE->MAXIMAL - }; - - assert(strcmp("opt", bb_type) == 0); - - if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast != NULL && source->ast->type != AST_TYPE::Module) { - llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create(g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[0]); - llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction()); - emitter.getBuilder()->SetInsertPoint(preentry_bb); - - llvm::Value *call_count_ptr = embedConstantPtr(&cf->times_called, g.i64->getPointerTo()); - llvm::Value *cur_call_count = emitter.getBuilder()->CreateLoad(call_count_ptr); - llvm::Value *new_call_count = emitter.getBuilder()->CreateAdd(cur_call_count, getConstantInt(1, g.i64)); - emitter.getBuilder()->CreateStore(new_call_count, call_count_ptr); - llvm::Value *reopt_test = emitter.getBuilder()->CreateICmpSGT(new_call_count, getConstantInt(REOPT_THRESHOLDS[effort], g.i64)); - - llvm::Value* md_vals[] = {llvm::MDString::get(g.context, "branch_weights"), getConstantInt(1), getConstantInt(1000)}; - llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef(md_vals)); - - llvm::BranchInst* guard = emitter.getBuilder()->CreateCondBr(reopt_test, reopt_bb, llvm_entry_blocks[0], branch_weights); - - emitter.getBuilder()->SetInsertPoint(reopt_bb); - //emitter.getBuilder()->CreateCall(g.funcs.my_assert, getConstantInt(0, g.i1)); - llvm::Value* r = emitter.getBuilder()->CreateCall(g.funcs.reoptCompiledFunc, embedConstantPtr(cf, g.i8->getPointerTo())); - assert(r); - assert(r->getType() == g.i8->getPointerTo()); - - llvm::Value *bitcast_r = emitter.getBuilder()->CreateBitCast(r, irstate->getLLVMFunction()->getType()); - - std::vector args; - //bitcast_r->dump(); - for (llvm::Function::arg_iterator AI = irstate->getLLVMFunction()->arg_begin(); AI != irstate->getLLVMFunction()->arg_end(); AI++) { - //AI->dump(); - args.push_back(&(*AI)); - } - //printf("%ld\n", args.size()); - llvm::CallInst *postcall = emitter.getBuilder()->CreateCall(bitcast_r, args); - postcall->setTailCall(true); - if (rtn_type == VOID) { - emitter.getBuilder()->CreateRetVoid(); - } else { - emitter.getBuilder()->CreateRet(postcall); - } - - emitter.getBuilder()->SetInsertPoint(llvm_entry_blocks[0]); - } - generator.unpackArguments(arg_names, cf->sig->arg_types); - } else if (entry_descriptor && block == entry_descriptor->backedge->target) { - assert(block->predecessors.size() > 1); - assert(osr_entry_block); - assert(phis); - - for (OSREntryDescriptor::ArgMap::const_iterator it = entry_descriptor->args.begin(), end = entry_descriptor->args.end(); it != end; ++it) { - ConcreteCompilerType *analyzed_type = types->getTypeAtBlockStart(it->first, block); - //printf("For %s, given %s, analyzed for %s\n", it->first.c_str(), it->second->debugName().c_str(), analyzed_type->debugName().c_str()); - - llvm::PHINode *phi = emitter.getBuilder()->CreatePHI(analyzed_type->llvmType(), block->predecessors.size()+1, it->first); - ConcreteCompilerVariable *var = new ConcreteCompilerVariable(analyzed_type, phi, true); - generator.giveLocalSymbol(it->first, var); - (*phis)[it->first] = std::make_pair(analyzed_type, phi); - } - } else if (pred == NULL) { - assert(traversal_order.size() < source->cfg->blocks.size()); - assert(phis); - assert(block->predecessors.size()); - for (int i = 0; i < block->predecessors.size(); i++) { - CFGBlock *b2 = block->predecessors[i]; - assert(ending_symbol_tables.count(b2->idx) == 0); - into_hax.insert(b2); - } - - const PhiAnalysis::RequiredSet &names = source->phis->getAllDefinedAt(block); - for (PhiAnalysis::RequiredSet::const_iterator it = names.begin(), end = names.end(); it != end; ++it) { - // TODO the list from getAllDefinedAt should come filtered: - if (!source->liveness->isLiveAtEnd(*it, block->predecessors[0])) - continue; - - //printf("adding guessed phi for %s\n", it->c_str()); - ConcreteCompilerType *type = types->getTypeAtBlockStart(*it, block); - llvm::PHINode *phi = emitter.getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), *it); - ConcreteCompilerVariable *var = new ConcreteCompilerVariable(type, phi, true); - generator.giveLocalSymbol(*it, var); - - (*phis)[*it] = std::make_pair(type, phi); - } - } else { - assert(pred); - assert(full_blocks.count(pred) || partial_blocks.count(pred)); - - if (block->predecessors.size() == 1) { - // If this block has only one predecessor, it by definition doesn't need any phi nodes. - // Assert that the phi_st is empty, and just create the symbol table from the non-phi st: - assert(phi_ending_symbol_tables[pred->idx]->size() == 0); - assert(ending_symbol_tables.count(pred->idx)); - generator.copySymbolsFrom(ending_symbol_tables[pred->idx]); - } else { - // With multiple predecessors, the symbol tables at the end of each predecessor should be *exactly* the same. - // (this should be satisfied by the post-run() code in this function) - - // With multiple predecessors, we have to combine the non-phi and phi symbol tables. - // Start off with the non-phi ones: - generator.copySymbolsFrom(ending_symbol_tables[pred->idx]); - - // And go through and add phi nodes: - ConcreteSymbolTable *pred_st = phi_ending_symbol_tables[pred->idx]; - for (ConcreteSymbolTable::iterator it = pred_st->begin(); it != pred_st->end(); it++) { - //printf("adding phi for %s\n", it->first.c_str()); - llvm::PHINode *phi = emitter.getBuilder()->CreatePHI(it->second->getType()->llvmType(), block->predecessors.size(), it->first); - //emitter.getBuilder()->CreateCall(g.funcs.dump, phi); - ConcreteCompilerVariable *var = new ConcreteCompilerVariable(it->second->getType(), phi, true); - generator.giveLocalSymbol(it->first, var); - - (*phis)[it->first] = std::make_pair(it->second->getType(), phi); - } - } - } - - generator.run(block); - - const IRGenerator::EndingState &ending_st = generator.getEndingSymbolTable(); - ending_symbol_tables[block->idx] = ending_st.symbol_table; - phi_ending_symbol_tables[block->idx] = ending_st.phi_symbol_table; - llvm_exit_blocks[block->idx] = ending_st.ending_block; - - if (into_hax.count(block)) - ASSERT(ending_st.symbol_table->size() == 0, "%d", block->idx); - } - - //// - // Phi generation. - // We don't know the exact ssa values to back-propagate to the phi nodes until we've generated - // the relevant IR, so after we have done all of it, go back through and populate the phi nodes. - // Also, do some checking to make sure that the phi analysis stuff worked out, and that all blocks - // agreed on what symbols + types they should be propagiting for the phis. - for (int i = 0; i < source->cfg->blocks.size(); i++) { - PHITable *phis = created_phis[i]; - if (phis == NULL) - continue; - - bool this_is_osr_entry = (entry_descriptor && i == entry_descriptor->backedge->target->idx); - - CFGBlock *b = source->cfg->blocks[i]; - - const std::vector &block_guards = in_guards.getGuardsForBlock(b); - - for (int j = 0; j < b->predecessors.size(); j++) { - CFGBlock *b2 = b->predecessors[j]; - if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0) - continue; - - //printf("%d %d %ld %ld\n", i, b2->idx, phi_ending_symbol_tables[b2->idx]->size(), phis->size()); - compareKeyset(phi_ending_symbol_tables[b2->idx], phis); - assert(phi_ending_symbol_tables[b2->idx]->size() == phis->size()); - } - - if (this_is_osr_entry) { - compareKeyset(osr_syms, phis); - } - - std::vector emitters; - std::vector offramps; - for (int i = 0; i < block_guards.size(); i++) { - compareKeyset(&block_guards[i]->symbol_table, phis); - - llvm::BasicBlock* off_ramp = llvm::BasicBlock::Create(g.context, "deopt_ramp", irstate->getLLVMFunction()); - offramps.push_back(off_ramp); - IREmitterImpl *emitter = new IREmitterImpl(irstate); - emitter->getBuilder()->SetInsertPoint(off_ramp); - emitters.push_back(emitter); - - block_guards[i]->branch->setSuccessor(1, off_ramp); - } - - for (PHITable::iterator it = phis->begin(); it != phis->end(); it++) { - llvm::PHINode* llvm_phi = it->second.second; - for (int j = 0; j < b->predecessors.size(); j++) { - CFGBlock *b2 = b->predecessors[j]; - if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0) - continue; - - ConcreteCompilerVariable *v = (*phi_ending_symbol_tables[b2->idx])[it->first]; - assert(v); - assert(v->isGrabbed()); - - // Make sure they all prepared for the same type: - ASSERT(it->second.first == v->getType(), "%d %d: %s %s %s", b->idx, b2->idx, it->first.c_str(), it->second.first->debugName().c_str(), v->getType()->debugName().c_str()); - - llvm_phi->addIncoming(v->getValue(), llvm_exit_blocks[b->predecessors[j]->idx]); - } - - if (this_is_osr_entry) { - ConcreteCompilerVariable *v = (*osr_syms)[it->first]; - assert(v); - assert(v->isGrabbed()); - - ASSERT(it->second.first == v->getType(), ""); - llvm_phi->addIncoming(v->getValue(), osr_unbox_block); - } - - for (int i = 0; i < block_guards.size(); i++) { - GuardList::BlockEntryGuard *g = block_guards[i]; - IREmitterImpl *emitter = emitters[i]; - - CompilerVariable *unconverted = g->symbol_table[it->first]; - ConcreteCompilerVariable *v = unconverted->makeConverted(*emitter, it->second.first); - assert(v); - assert(v->isGrabbed()); - - - ASSERT(it->second.first == v->getType(), ""); - llvm_phi->addIncoming(v->getValue(), offramps[i]); - - // TODO not sure if this is right: - unconverted->decvref(*emitter); - delete v; - } - } - - for (int i = 0; i < block_guards.size(); i++) { - emitters[i]->getBuilder()->CreateBr(llvm_entry_blocks[b->idx]); - delete emitters[i]; - } - } - - for (int i = 0; i < source->cfg->blocks.size(); i++) { - if (ending_symbol_tables[i] == NULL) - continue; - - for (SymbolTable::iterator it = ending_symbol_tables[i]->begin(); it != ending_symbol_tables[i]->end(); it++) { - it->second->decvrefNodrop(); - } - for (ConcreteSymbolTable::iterator it = phi_ending_symbol_tables[i]->begin(); it != phi_ending_symbol_tables[i]->end(); it++) { - it->second->decvrefNodrop(); - } - delete phi_ending_symbol_tables[i]; - delete ending_symbol_tables[i]; - delete created_phis[i]; - } - - if (entry_descriptor) { - for (ConcreteSymbolTable::iterator it = osr_syms->begin(), end = osr_syms->end(); it != end; ++it) { - delete it->second; - } - delete osr_syms; - } -} - -static void computeBlockSetClosure(BlockSet &full_blocks, BlockSet &partial_blocks) { - if (VERBOSITY("irgen") >= 1) { - printf("Initial full:"); - for (BlockSet::iterator it = full_blocks.begin(), end = full_blocks.end(); it != end; ++it) { - printf(" %d", (*it)->idx); - } - printf("\n"); - printf("Initial partial:"); - for (BlockSet::iterator it = partial_blocks.begin(), end = partial_blocks.end(); it != end; ++it) { - printf(" %d", (*it)->idx); - } - printf("\n"); - } - std::vector q; - BlockSet expanded; - q.insert(q.end(), full_blocks.begin(), full_blocks.end()); - q.insert(q.end(), partial_blocks.begin(), partial_blocks.end()); - - while (q.size()) { - CFGBlock *b = q.back(); - q.pop_back(); - - if (expanded.count(b)) - continue; - expanded.insert(b); - - for (int i = 0; i < b->successors.size(); i++) { - CFGBlock *b2 = b->successors[i]; - partial_blocks.erase(b2); - full_blocks.insert(b2); - q.push_back(b2); - } - } - - if (VERBOSITY("irgen") >= 1) { - printf("Ending full:"); - for (BlockSet::iterator it = full_blocks.begin(), end = full_blocks.end(); it != end; ++it) { - printf(" %d", (*it)->idx); - } - printf("\n"); - printf("Ending partial:"); - for (BlockSet::iterator it = partial_blocks.begin(), end = partial_blocks.end(); it != end; ++it) { - printf(" %d", (*it)->idx); - } - printf("\n"); - } -} -// returns a pointer to the function-info mdnode -static llvm::MDNode* setupDebugInfo(SourceInfo *source, llvm::Function *f, std::string origname) { - int lineno = 0; - if (source->ast) - lineno = source->ast->lineno; - - llvm::DIBuilder builder(*g.cur_module); - - std::string fn = source->parent_module->fn; - std::string dir = "TODO fill this in"; - std::string producer = "pyston; git rev " STRINGIFY(GITREV); - - llvm::DIFile file = builder.createFile(fn, dir); - llvm::DIArray param_types = builder.getOrCreateArray(llvm::None); - llvm::DICompositeType func_type = builder.createSubroutineType(file, param_types); - llvm::DISubprogram func_info = builder.createFunction(file, f->getName(), f->getName(), file, lineno, func_type, false, true, lineno + 1, 0, true, f); - llvm::DICompileUnit compile_unit = builder.createCompileUnit(llvm::dwarf::DW_LANG_Python, fn, dir, producer, true, "", 0); - - llvm::DIArray subprograms = builder.getOrCreateArray(&*func_info); - compile_unit.getSubprograms()->replaceAllUsesWith(subprograms); - - compile_unit.getEnumTypes()->replaceAllUsesWith(builder.getOrCreateArray(llvm::ArrayRef())); - compile_unit.getRetainedTypes()->replaceAllUsesWith(builder.getOrCreateArray(llvm::ArrayRef())); - compile_unit.getGlobalVariables()->replaceAllUsesWith(builder.getOrCreateArray(llvm::ArrayRef())); - compile_unit.getImportedEntities()->replaceAllUsesWith(builder.getOrCreateArray(llvm::ArrayRef())); - return func_info; -} - -static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel::EffortLevel effort, const OSREntryDescriptor *entry) { - static int num_functions = 0; - - std::ostringstream os; - os << nameprefix; - os << "_e" << effort; - if (entry) { - os << "_osr" << entry->backedge->target->idx << "_from_" << entry->cf->func->getName().data(); - } - os << '_' << num_functions; - num_functions++; - return os.str(); -} - -CompiledFunction* compileFunction(SourceInfo *source, const OSREntryDescriptor *entry_descriptor, EffortLevel::EffortLevel effort, FunctionSignature *sig, const std::vector &arg_names, std::string nameprefix) { - Timer _t("in compileFunction"); - - if (VERBOSITY("irgen") >= 1) source->cfg->print(); - - assert(g.cur_module == NULL); - std::string name = getUniqueFunctionName(nameprefix, effort, entry_descriptor); - g.cur_module = new llvm::Module(name, g.context); - g.cur_module->setDataLayout(g.tm->getDataLayout()->getStringRepresentation()); - //g.engine->addModule(g.cur_module); - - //// - // Initializing the llvm-level structures: - - int nargs = arg_names.size(); - ASSERT(nargs == sig->arg_types.size(), "%d %ld", nargs, sig->arg_types.size()); - - std::vector llvm_arg_types; - if (entry_descriptor == NULL) { - for (int i = 0; i < nargs; i++) { - if (i == 3) { - llvm_arg_types.push_back(g.llvm_value_type_ptr->getPointerTo()); - break; - } - llvm_arg_types.push_back(sig->arg_types[i]->llvmType()); - } - } else { - int i = 0; - for (OSREntryDescriptor::ArgMap::const_iterator it = entry_descriptor->args.begin(), end = entry_descriptor->args.end(); it != end; ++it, ++i) { - //printf("Loading %s: %s\n", it->first.c_str(), it->second->debugName().c_str()); - if (i < 3) - llvm_arg_types.push_back(it->second->llvmType()); - else { - llvm_arg_types.push_back(g.llvm_value_type_ptr->getPointerTo()); - break; - } - } - } - - llvm::FunctionType *ft = llvm::FunctionType::get(sig->rtn_type->llvmType(), llvm_arg_types, false /*vararg*/); - - llvm::Function *f = llvm::Function::Create(ft, llvm::Function::ExternalLinkage, name, g.cur_module); - //g.func_registry.registerFunction(f, g.cur_module); - - CompiledFunction *cf = new CompiledFunction(f, sig, (effort == EffortLevel::INTERPRETED), NULL, NULL, effort, entry_descriptor); - - llvm::MDNode* dbg_funcinfo = setupDebugInfo(source, f, nameprefix); - - TypeAnalysis::SpeculationLevel speculation_level = TypeAnalysis::NONE; - if (ENABLE_SPECULATION && effort >= EffortLevel::MODERATE) - speculation_level = TypeAnalysis::SOME; - TypeAnalysis *types = doTypeAnalysis(source->cfg, arg_names, sig->arg_types, speculation_level, source->scoping->getScopeInfoForNode(source->ast)); - - GuardList guards; - - BlockSet full_blocks, partial_blocks; - if (entry_descriptor == NULL) { - for (int i = 0; i < source->cfg->blocks.size(); i++) { - full_blocks.insert(source->cfg->blocks[i]); - } - } else { - full_blocks.insert(entry_descriptor->backedge->target); - computeBlockSetClosure(full_blocks, partial_blocks); - } - - IRGenState irstate(cf, source, getGCBuilder(), dbg_funcinfo); - - emitBBs(&irstate, "opt", guards, GuardList(), types, arg_names, entry_descriptor, full_blocks, partial_blocks); - - // De-opt handling: - - if (!guards.isEmpty()) { - BlockSet deopt_full_blocks, deopt_partial_blocks; - GuardList deopt_guards; - //typedef std::unordered_map > Worklist; - //Worklist guard_worklist; - for (GuardList::expr_type_guard_iterator it = guards.after_begin(), end = guards.after_end(); it != end; ++it) { - deopt_partial_blocks.insert(it->second->cfg_block); - } - - computeBlockSetClosure(deopt_full_blocks, deopt_partial_blocks); - - TypeAnalysis *deopt_types = doTypeAnalysis(source->cfg, arg_names, sig->arg_types, TypeAnalysis::NONE, source->scoping->getScopeInfoForNode(source->ast)); - emitBBs(&irstate, "deopt", deopt_guards, guards, deopt_types, arg_names, NULL, deopt_full_blocks, deopt_partial_blocks); - assert(deopt_guards.isEmpty()); - - delete deopt_types; - } - - for (GuardList::expr_type_guard_iterator it = guards.after_begin(), end = guards.after_end(); it != end; ++it) { - delete it->second; - } - - delete types; - - if (VERBOSITY("irgen") >= 1) { - printf("generated IR:\n"); - printf("\033[33m"); - fflush(stdout); - dumpPrettyIR(f); - //f->dump(); - //g.cur_module->dump(); - //g.cur_module->print(llvm::outs(), NULL); - printf("\033[0m"); - fflush(stdout); - } else { - // Somehow, running this code makes it faster...????? - //printf("\033[0m"); - //fflush(stdout); - } - -#ifndef NDEBUG - if (!BENCH) { - // Calling verifyFunction() confuses the profiler, which will end up attributing - // a large amount of runtime to it since the call stack looks very similar to - // the (expensive) case of compiling the function. - llvm::verifyFunction(*f); - } -#endif - - long us = _t.end(); - static StatCounter us_irgen("us_compiling_irgen"); - us_irgen.log(us); - - if (ENABLE_LLVMOPTS) - optimizeIR(f, effort); - - bool ENABLE_IR_DEBUG = false; - if (ENABLE_IR_DEBUG) { - addIRDebugSymbols(f); - //dumpPrettyIR(f); - } - - g.cur_module = NULL; - - return cf; -} - - - -} // namespace pyston diff --git a/src/codegen/irgen.h b/src/codegen/irgen.h deleted file mode 100644 index 303a4a5b6..000000000 --- a/src/codegen/irgen.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_IRGEN_H -#define PYSTON_CODEGEN_IRGEN_H - -#include "llvm/IR/Function.h" -#include "llvm/IR/IntrinsicInst.h" - -#include "core/types.h" - -#include "codegen/compvars.h" -//#include "codegen/function_analysis.h" - -namespace pyston { - -class AST_expr; - -typedef std::unordered_map SymbolTable; -typedef std::map SortedSymbolTable; -typedef std::unordered_map ConcreteSymbolTable; - -class IREmitter; -class MyInserter : public llvm::IRBuilderDefaultInserter { - private: - IREmitter *emitter; - - protected: - void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name, - llvm::BasicBlock *BB, llvm::BasicBlock::iterator InsertPt) const; - - public: - void setEmitter(IREmitter *emitter) { - this->emitter = emitter; - } -}; - -class PatchpointSetupInfo; - -class IREmitter { - public: - enum Target { - INTERPRETER, - COMPILATION, - }; - typedef llvm::IRBuilder IRBuilder; - - virtual ~IREmitter() {} - - virtual Target getTarget() = 0; - virtual IRBuilder* getBuilder() = 0; - virtual GCBuilder* getGC() = 0; - virtual CompiledFunction* currentFunction() = 0; - - virtual llvm::Function* getIntrinsic(llvm::Intrinsic::ID) = 0; - virtual llvm::Value* createPatchpoint(const PatchpointSetupInfo *pp, void* func_addr, const std::vector &args) = 0; -}; - -CompiledFunction* compileFunction(SourceInfo *source, const OSREntryDescriptor *entry_descriptor, EffortLevel::EffortLevel effort, FunctionSignature *sig, const std::vector &arg_names, std::string nameprefix); - -} - -#endif diff --git a/src/codegen/irgen/hooks.cpp b/src/codegen/irgen/hooks.cpp deleted file mode 100644 index 60760e689..000000000 --- a/src/codegen/irgen/hooks.cpp +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "llvm/Support/raw_ostream.h" - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "core/ast.h" -#include "core/cfg.h" -#include "core/util.h" - -#include "analysis/function_analysis.h" -#include "analysis/scoping_analysis.h" - -#include "asm_writing/icinfo.h" - -#include "codegen/codegen.h" -#include "codegen/compvars.h" -#include "codegen/irgen.h" -#include "codegen/llvm_interpreter.h" -#include "codegen/osrentry.h" -#include "codegen/stackmaps.h" -#include "codegen/patchpoints.h" -#include "codegen/irgen/hooks.h" -#include "codegen/irgen/util.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -namespace pyston { - -// TODO terrible place for these! -const std::string SourceInfo::getName() { - assert(ast); - switch (ast->type) { - case AST_TYPE::FunctionDef: - return static_cast(ast)->name; - case AST_TYPE::Module: - return "module"; - default: - RELEASE_ASSERT(0, "%d", ast->type); - } -} - -AST_arguments* SourceInfo::getArgsAST() { - assert(ast); - switch (ast->type) { - case AST_TYPE::FunctionDef: - return static_cast(ast)->args; - case AST_TYPE::Module: - return NULL; - default: - RELEASE_ASSERT(0, "%d", ast->type); - } -} - -const std::vector& SourceInfo::getArgNames() { - static std::vector empty; - - AST_arguments* args = getArgsAST(); - if (args == NULL) - return empty; - return args->args; -} - -const std::vector& SourceInfo::getBody() { - assert(ast); - switch (ast->type) { - case AST_TYPE::FunctionDef: - return static_cast(ast)->body; - case AST_TYPE::Module: - return static_cast(ast)->body; - default: - RELEASE_ASSERT(0, "%d", ast->type); - } -} - -static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) { - assert(cf); - assert(cf->func); - - //g.engine->finalizeOBject(); - if (VERBOSITY("irgen") >= 1) { - printf("Compiling...\n"); - //g.cur_module->dump(); - } - - void* compiled = NULL; - if (effort > EffortLevel::INTERPRETED) { - Timer _t("to jit the IR"); - g.engine->addModule(cf->func->getParent()); - compiled = (void*)g.engine->getFunctionAddress(cf->func->getName()); - assert(compiled); - cf->llvm_code = embedConstantPtr(compiled, cf->func->getType()); - - long us = _t.end(); - static StatCounter us_jitting("us_compiling_jitting"); - us_jitting.log(us); - static StatCounter num_jits("num_jits"); - num_jits.log(); - } else { - // HAX just get it for now; this is just to make sure everything works - //(void*)g.func_registry.getFunctionAddress(cf->func->getName()); - } - - cf->code = compiled; - if (VERBOSITY("irgen") >= 1) { - printf("Compiled function to %p\n", compiled); - } - - StackMap *stackmap = parseStackMap(); - patchpoints::processStackmap(stackmap); -} - -// Compiles a new version of the function with the given signature and adds it to the list; -// should only be called after checking to see if the other versions would work. -static CompiledFunction* _doCompile(CLFunction *f, FunctionSignature *sig, EffortLevel::EffortLevel effort, const OSREntryDescriptor *entry) { - Timer _t("for _doCompile()"); - assert(sig); - - ASSERT(f->versions.size() < 20, "%ld", f->versions.size()); - SourceInfo *source = f->source; - assert(source); - - std::string name = source->getName(); - const std::vector &arg_names = source->getArgNames(); - AST_arguments *args = source->getArgsAST(); - - if (VERBOSITY("irgen") >= 1) { - std::string s; - llvm::raw_string_ostream ss(s); - - ss << "\033[34;1mJIT'ing " << name << " with signature ("; - for (int i = 0; i < sig->arg_types.size(); i++) { - if (i > 0) ss << ", "; - ss << sig->arg_types[i]->debugName(); - //sig->arg_types[i]->llvmType()->print(ss); - } - ss << ") -> "; - ss << sig->rtn_type->debugName(); - //sig->rtn_type->llvmType()->print(ss); - ss << " at effort level " << effort; - if (entry != NULL) { - ss << "\nDoing OSR-entry partial compile, starting with backedge to block " << entry->backedge->target->idx << '\n'; - } - ss << "\033[0m"; - printf("%s\n", ss.str().c_str()); - } - - // Do the analysis now if we had deferred it earlier: - if (source->cfg == NULL) { - assert(source->ast); - source->cfg = computeCFG(source->ast->type, source->getBody()); - source->liveness = computeLivenessInfo(source->cfg); - source->phis = computeRequiredPhis(args, source->cfg, source->liveness, - source->scoping->getScopeInfoForNode(source->ast)); - } - - CompiledFunction *cf = compileFunction(source, entry, effort, sig, arg_names, name); - - compileIR(cf, effort); - f->addVersion(cf); - assert(f->versions.size()); - - long us = _t.end(); - static StatCounter us_compiling("us_compiling"); - us_compiling.log(us); - static StatCounter num_compiles("num_compiles"); - num_compiles.log(); - - switch(effort) { - case EffortLevel::INTERPRETED: { - static StatCounter us_compiling("us_compiling_0_interpreted"); - us_compiling.log(us); - static StatCounter num_compiles("num_compiles_0_interpreted"); - num_compiles.log(); - break; - } - case EffortLevel::MINIMAL: { - static StatCounter us_compiling("us_compiling_1_minimal"); - us_compiling.log(us); - static StatCounter num_compiles("num_compiles_1_minimal"); - num_compiles.log(); - break; - } - case EffortLevel::MODERATE: { - static StatCounter us_compiling("us_compiling_2_moderate"); - us_compiling.log(us); - static StatCounter num_compiles("num_compiles_2_moderate"); - num_compiles.log(); - break; - } - case EffortLevel::MAXIMAL: { - static StatCounter us_compiling("us_compiling_3_maximal"); - us_compiling.log(us); - static StatCounter num_compiles("num_compiles_3_maximal"); - num_compiles.log(); - break; - } - } - - return cf; -} - -static EffortLevel::EffortLevel initialEffort() { - if (FORCE_OPTIMIZE) - return EffortLevel::MAXIMAL; - if (ENABLE_INTERPRETER) - return EffortLevel::INTERPRETED; - return EffortLevel::MINIMAL; -} - -CompiledFunction* compileModule(AST_Module *m, BoxedModule *bm) { - Timer _t("for compileModule()"); - - ScopingAnalysis *scoping = runScopingAnalysis(m); - - SourceInfo *si = new SourceInfo(bm, scoping); - si->cfg = computeCFG(AST_TYPE::Module, m->body); - si->ast = m; - si->liveness = computeLivenessInfo(si->cfg); - si->phis = computeRequiredPhis(NULL, si->cfg, si->liveness, si->scoping->getScopeInfoForNode(si->ast)); - - CLFunction *cl_f = new CLFunction(si); - - EffortLevel::EffortLevel effort = initialEffort(); - - CompiledFunction *cf = _doCompile(cl_f, new FunctionSignature(VOID, false), effort, NULL); - assert(cf->clfunc->versions.size()); - - return cf; -} - -/// Reoptimizes the given function version at the new effort level. -/// The cf must be an active version in its parents CLFunction; the given -/// version will be replaced by the new version, which will be returned. -static CompiledFunction* _doReopt(CompiledFunction *cf, EffortLevel::EffortLevel new_effort) { - assert(cf->clfunc->versions.size()); - - assert(cf); - assert(cf->entry_descriptor == NULL && "We can't reopt an osr-entry compile!"); - assert(cf->sig); - - CLFunction *clfunc = cf->clfunc; - assert(clfunc); - - assert(new_effort > cf->effort); - - FunctionList &versions = clfunc->versions; - for (int i = 0; i < versions.size(); i++) { - if (versions[i] == cf) { - versions.erase(versions.begin() + i); - - CompiledFunction *new_cf = _doCompile(clfunc, cf->sig, new_effort, NULL); // this pushes the new CompiledVersion to the back of the version list - - cf->dependent_callsites.invalidateAll(); - - return new_cf; - } - } - assert(0 && "Couldn't find a version to reopt! Probably reopt'd already?"); - abort(); -} - -static StatCounter stat_osrexits("OSR exits"); -void* compilePartialFunc(OSRExit* exit) { - assert(exit); - assert(exit->parent_cf); - assert(exit->parent_cf->effort < EffortLevel::MAXIMAL); - stat_osrexits.log(); - - //if (VERBOSITY("irgen") >= 1) printf("In compilePartialFunc, handling %p\n", exit); - - assert(exit->parent_cf->clfunc); - CompiledFunction* &new_cf = exit->parent_cf->clfunc->osr_versions[exit->entry]; - if (new_cf == NULL) { - EffortLevel::EffortLevel new_effort = EffortLevel::MAXIMAL; - if (exit->parent_cf->effort == EffortLevel::INTERPRETED) - new_effort = EffortLevel::MINIMAL; - //EffortLevel::EffortLevel new_effort = (EffortLevel::EffortLevel)(exit->parent_cf->effort + 1); - //new_effort = EffortLevel::MAXIMAL; - CompiledFunction *compiled = _doCompile(exit->parent_cf->clfunc, exit->parent_cf->sig, new_effort, exit->entry); - assert(compiled = new_cf); - } - - return new_cf->code; -} - -static StatCounter stat_reopt("reopts"); -extern "C" char* reoptCompiledFunc(CompiledFunction *cf) { - if (VERBOSITY("irgen") >= 1) printf("In reoptCompiledFunc, %p, %ld\n", cf, cf->times_called); - stat_reopt.log(); - - assert(cf->effort < EffortLevel::MAXIMAL); - assert(cf->clfunc->versions.size()); - CompiledFunction *new_cf = _doReopt(cf, (EffortLevel::EffortLevel(cf->effort + 1))); - assert(!new_cf->is_interpreted); - return (char*)new_cf->code; -} - -CompiledFunction* resolveCLFunc(CLFunction *f, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) { - static StatCounter slowpath_resolveclfunc("slowpath_resolveclfunc"); - slowpath_resolveclfunc.log(); - - FunctionList &versions = f->versions; - - for (int i = 0; i < versions.size(); i++) { - CompiledFunction *cf = versions[i]; - FunctionSignature* sig = cf->sig; - if (sig->rtn_type->llvmType() != g.llvm_value_type_ptr) - continue; - if ((!sig->is_vararg && sig->arg_types.size() != nargs) || (sig->is_vararg && nargs < sig->arg_types.size())) - continue; - - int nsig_args = sig->arg_types.size(); - - if (nsig_args >= 1) { - if (sig->arg_types[0]->isFitBy(arg1->cls)) { - // pass - } else { - continue; - } - } - if (nsig_args >= 2) { - if (sig->arg_types[1]->isFitBy(arg2->cls)) { - // pass - } else { - continue; - } - } - if (nsig_args >= 3) { - if (sig->arg_types[2]->isFitBy(arg3->cls)) { - // pass - } else { - continue; - } - } - bool bad = false; - for (int j = 3; j < nsig_args; j++) { - if (sig->arg_types[j]->isFitBy(args[j-3]->cls)) { - // pass - } else { - bad = true; - break; - } - } - if (bad) continue; - - assert(cf); - assert(!cf->entry_descriptor); - assert(cf->is_interpreted == (cf->code == NULL)); - - return cf; - } - - if (f->source == NULL) { - printf("Error: couldn't find suitable function version and no source to recompile!\n"); - printf("%ld args:", nargs); - for (int i = 0; i < nargs; i++) { - Box* firstargs[] = {arg1, arg2, arg3}; - printf(" %s", getTypeName(firstargs[i])->c_str()); - if (i == 3) { - printf(" [and more]"); - break; - } - } - printf("\n"); - for (int j = 0; j < f->versions.size(); j++) { - std::string func_name = g.func_addr_registry.getFuncNameAtAddress(f->versions[j]->code, true); - printf("Version %d, %s:", j, func_name.c_str()); - FunctionSignature *sig = f->versions[j]->sig; - for (int i = 0; i < sig->arg_types.size(); i++) { - printf(" %s", sig->arg_types[i]->debugName().c_str()); - } - if (sig->is_vararg) - printf(" *vararg"); - printf("\n"); - //printf(" @%p %s\n", f->versions[j]->code, func_name.c_str()); - } - abort(); - } - - assert(f->source->getArgsAST()->vararg.size() == 0); - bool is_vararg = false; - - std::vector arg_types; - if (nargs >= 1) { - arg_types.push_back(typeFromClass(arg1->cls)); - } - if (nargs >= 2) { - arg_types.push_back(typeFromClass(arg2->cls)); - } - if (nargs >= 3) { - arg_types.push_back(typeFromClass(arg3->cls)); - } - for (int j = 3; j < nargs; j++) { - arg_types.push_back(typeFromClass(args[j-3]->cls)); - } - FunctionSignature *sig = new FunctionSignature(UNKNOWN, arg_types, is_vararg); - - EffortLevel::EffortLevel new_effort = initialEffort(); - - CompiledFunction *cf = _doCompile(f, sig, new_effort, NULL); // this pushes the new CompiledVersion to the back of the version list - assert(cf->is_interpreted == (cf->code == NULL)); - - return cf; -} - -Box* callCompiledFunc(CompiledFunction *cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box**args) { - assert(cf); - - // TODO these shouldn't have to be initialized, but I don't want to issue a #pragma - // that disables the warning for the whole file: - Box *rarg1 = arg1, *rarg2 = arg2, *rarg3 = arg3; - Box **rargs = NULL; - if (nargs > 3) { - if (cf->sig->is_vararg) { - // the +2 is for the varargs and kwargs - rargs = (Box**)alloca((nargs - 3 + 2) * sizeof(Box*)); - memcpy(rargs, args, (nargs - 3) * sizeof(Box*)); - } else { - rargs = args; - } - } - - int nsig_args = cf->sig->arg_types.size(); - - BoxedList* made_vararg = NULL; - if (cf->sig->is_vararg) { - made_vararg = (BoxedList*)createList(); - if (nsig_args == 0) - rarg1 = made_vararg; - else if (nsig_args == 1) - rarg2 = made_vararg; - else if (nsig_args == 2) - rarg3 = made_vararg; - else - rargs[nsig_args-3] = made_vararg; - - for (int i = nsig_args; i < nargs; i++) { - if (i == 0) listAppendInternal(made_vararg, arg1); - else if (i == 1) listAppendInternal(made_vararg, arg2); - else if (i == 2) listAppendInternal(made_vararg, arg3); - else listAppendInternal(made_vararg, args[i - 3]); - } - } - - if (!cf->is_interpreted) { - if (cf->sig->is_vararg) { - Box* rtn = cf->call(rarg1, rarg2, rarg3, rargs); - return rtn; - } else { - return cf->call(rarg1, rarg2, rarg3, rargs); - } - } else { - return interpretFunction(cf->func, nargs, rarg1, rarg2, rarg3, rargs); - } -} - -CLFunction* createRTFunction() { - return new CLFunction(NULL); -} - -extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg) { - CLFunction *cl_f = createRTFunction(); - - addRTFunction(cl_f, f, rtn_type, nargs, is_vararg); - return cl_f; -} - -void addRTFunction(CLFunction *cl_f, void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg) { - std::vector arg_types(nargs, NULL); - return addRTFunction(cl_f, f, rtn_type, arg_types, is_vararg); -} - -static ConcreteCompilerType* processType(ConcreteCompilerType *type) { - if (type == NULL) - return UNKNOWN; - return type; -} - -void addRTFunction(CLFunction *cl_f, void* f, ConcreteCompilerType* rtn_type, const std::vector &arg_types, bool is_vararg) { - FunctionSignature *sig = new FunctionSignature(processType(rtn_type), is_vararg); - std::vector llvm_arg_types; - for (int i = 0; i < arg_types.size(); i++) { - sig->arg_types.push_back(processType(arg_types[i])); - llvm_arg_types.push_back(g.llvm_value_type_ptr); - } - - llvm::FunctionType *ft = llvm::FunctionType::get(g.llvm_value_type_ptr, llvm_arg_types, false); - - cl_f->addVersion(new CompiledFunction(NULL, sig, false, f, embedConstantPtr(f, ft->getPointerTo()), EffortLevel::MAXIMAL, NULL)); -} - -} diff --git a/src/codegen/irgen/hooks.h b/src/codegen/irgen/hooks.h deleted file mode 100644 index d31759115..000000000 --- a/src/codegen/irgen/hooks.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_IRGEN_HOOKS_H -#define PYSTON_CODEGEN_IRGEN_HOOKS_H - -namespace pyston { - -class OSRExit; -void* compilePartialFunc(OSRExit*); -extern "C" char* reoptCompiledFunc(CompiledFunction*); - -} - -#endif diff --git a/src/codegen/irgen/util.cpp b/src/codegen/irgen/util.cpp deleted file mode 100644 index ec70099af..000000000 --- a/src/codegen/irgen/util.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/Support/InstIterator.h" -#include "llvm/Transforms/Utils/Cloning.h" - -#include "core/common.h" - -#include "runtime/types.h" - -#include "codegen/codegen.h" -#include "codegen/irgen/util.h" - -namespace pyston { - -/* -static std::string getStringName(std::string strvalue) { - std::ostringstream name_os; - name_os << "str"; - name_os << g.global_string_table.size(); - name_os << '_'; - for (int i = 0; i < strvalue.size(); i++) { - if (isalnum(strvalue[i])) - name_os << strvalue[i]; - } - return name_os.str(); -} - -// Gets a reference (creating if necessary) to a global string constant with the given value. -// The return type will be a char array. -static llvm::Constant* getStringConstant(const std::string &str) { - if (g.global_string_table.find(str) != g.global_string_table.end()) { - llvm::GlobalVariable *gv = g.global_string_table[str]; - llvm::Constant *rtn = g.cur_module->getOrInsertGlobal(gv->getName(), gv->getType()->getElementType()); - return rtn; - } - - int len = str.size(); - std::vector chars; - for (int i = 0; i < len; i++) { - chars.push_back(llvm::ConstantInt::get(g.i8, str[i])); - } - llvm::ArrayType *at = llvm::ArrayType::get(g.i8, len); - llvm::Constant *val = llvm::ConstantArray::get(at, llvm::ArrayRef(chars)); - llvm::GlobalVariable *gv = new llvm::GlobalVariable(*g.cur_module, at, true, llvm::GlobalValue::ExternalLinkage, val, getStringName(str)); - g.global_string_table[str] = gv; - return gv; -} -*/ - -std::unordered_map strings; - -// Returns a llvm::Constant char* to a global string constant -llvm::Constant* getStringConstantPtr(const std::string &str) { - const char* c; - if (strings.count(str)) { - c = strings[str]; - } else { - char *buf = (char*)malloc(str.size() + 1); - memcpy(buf, str.c_str(), str.size()); - buf[str.size()] = '\0'; - - strings[str] = buf; - c = buf; - } - return embedConstantPtr(c, g.i8->getPointerTo()); -} - -// Returns a llvm::Constant char* to a global string constant -llvm::Constant* getStringConstantPtr(const char* str) { - return getStringConstantPtr(std::string(str, strlen(str) + 1)); -} - -// Sometimes we want to embed pointers into the emitted code, usually to link the emitted code -// to some associated compiler-level data structure. -// It's slightly easier to emit them as integers (there are primitive integer constants but not pointer constants), -// but doing it this way makes it clearer what's going on. -llvm::Constant* embedConstantPtr(const void* addr, llvm::Type* type) { - assert(type); - llvm::Constant *int_val = llvm::ConstantInt::get(g.i64, reinterpret_cast(addr), false); - llvm::Constant *ptr_val = llvm::ConstantExpr::getIntToPtr(int_val, type); - return ptr_val; -} - -llvm::Constant* getConstantInt(int n, llvm::Type* t) { - return llvm::ConstantInt::get(t, n); -} - -llvm::Constant* getConstantInt(int n) { - return getConstantInt(n, g.i64); -} - -class PrettifyingMaterializer : public llvm::ValueMaterializer { - private: - llvm::Module* module; - public: - PrettifyingMaterializer(llvm::Module* module) : module(module) { - } - - virtual llvm::Value* materializeValueFor(llvm::Value* v) { - if (llvm::ConstantExpr *ce = llvm::dyn_cast(v)) { - llvm::PointerType* pt = llvm::dyn_cast(ce->getType()); - if (ce->isCast() && ce->getOpcode() == llvm::Instruction::IntToPtr && pt) { - llvm::ConstantInt* addr_const = llvm::cast(ce->getOperand(0)); - void* addr = (void*)addr_const->getSExtValue(); - - bool lookup_success = true; - std::string name; - if (addr == (void*)None) { - name = "None"; - } else { - name = g.func_addr_registry.getFuncNameAtAddress(addr, true, &lookup_success); - } - - if (!lookup_success) - return v; - - return module->getOrInsertGlobal(name, pt->getElementType()); - } - } - return v; - } -}; - -void dumpPrettyIR(llvm::Function *f) { - std::unique_ptr tmp_module(llvm::CloneModule(f->getParent())); - //std::unique_ptr tmp_module(new llvm::Module("tmp", g.context)); - - llvm::Function *new_f = tmp_module->begin(); - - llvm::ValueToValueMapTy VMap; - PrettifyingMaterializer materializer(tmp_module.get()); - for (llvm::Function::iterator I = new_f->begin(), E = new_f->end(); I != E; ++I) { - VMap[I] = I; - } - for (llvm::inst_iterator it = inst_begin(new_f), end = inst_end(new_f); it != end; ++it) { - llvm::RemapInstruction(&*it, VMap, llvm::RF_None, NULL, &materializer); - } - tmp_module->begin()->dump(); - //tmp_module->dump(); -} - - -} diff --git a/src/codegen/irgen/util.h b/src/codegen/irgen/util.h deleted file mode 100644 index 2faed685c..000000000 --- a/src/codegen/irgen/util.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_IRGEN_UTIL_H -#define PYSTON_CODEGEN_IRGEN_UTIL_H - -#include - -namespace llvm { -class Constant; -class Type; -} - -namespace pyston { - -llvm::Constant* getStringConstantPtr(const std::string &str); -llvm::Constant* getStringConstantPtr(const char* str); -llvm::Constant* embedConstantPtr(const void* addr, llvm::Type*); -llvm::Constant* getConstantInt(int val); -llvm::Constant* getConstantInt(int val, llvm::Type*); - -void dumpPrettyIR(llvm::Function *f); - -} - -#endif diff --git a/src/codegen/llvm_interpreter.cpp b/src/codegen/llvm_interpreter.cpp deleted file mode 100644 index 741b13fd7..000000000 --- a/src/codegen/llvm_interpreter.cpp +++ /dev/null @@ -1,628 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" - -#include "core/common.h" -#include "core/stats.h" - -#include "core/util.h" - -#include "codegen/codegen.h" -#include "codegen/llvm_interpreter.h" -#include "codegen/irgen/hooks.h" -#include "codegen/irgen/util.h" - -namespace pyston { - -union Val { - bool b; - int64_t n; - double d; - Box* o; - - Val(bool b) : b(b) {} - Val(int64_t n) : n(n) {} - Val(double d) : d(d) {} - Val(Box* o) : o(o) {} -}; - -typedef std::unordered_map SymMap; - -int width(llvm::Type *t, const llvm::DataLayout &dl) { - return dl.getTypeSizeInBits(t) / 8; - //if (t == g.i1) return 1; - //if (t == g.i64) return 8; - //if (t->isPointerTy()) return 8; -// - //t->dump(); - //RELEASE_ASSERT(0, ""); -} - -int width(llvm::Value *v, const llvm::DataLayout &dl) { - return width(v->getType(), dl); -} - -//#undef VERBOSITY -//#define VERBOSITY(x) 2 -#define TIME_INTERPRETS - -Val fetch(llvm::Value* v, const llvm::DataLayout &dl, const SymMap &symbols) { - assert(v); - - int opcode = v->getValueID(); - - //std::ostringstream os(""); - //os << "fetch_" << opcode; - //int statid = Stats::getStatId(os.str()); - //Stats::log(statid); - - if (opcode >= llvm::Value::InstructionVal) { - assert(symbols.count(v)); - return symbols.find(v)->second; - } - - switch(opcode) { - case llvm::Value::ArgumentVal: { - assert(symbols.count(v)); - return symbols.find(v)->second; - } - case llvm::Value::ConstantIntVal: { - if (v->getType() == g.i1) - return (int64_t)llvm::cast(v)->getZExtValue(); - if (v->getType() == g.i64 || v->getType() == g.i32) - return llvm::cast(v)->getSExtValue(); - v->dump(); - RELEASE_ASSERT(0, ""); - } - case llvm::Value::ConstantFPVal: { - return llvm::cast(v)->getValueAPF().convertToDouble(); - } - case llvm::Value::ConstantExprVal: { - llvm::ConstantExpr *ce = llvm::cast(v); - if (ce->isCast()) { - assert(width(ce->getOperand(0), dl) == 8 && width(ce, dl) == 8); - - Val o = fetch(ce->getOperand(0), dl, symbols); - return o; - } else if (ce->getOpcode() == llvm::Instruction::GetElementPtr) { - int64_t base = (int64_t)fetch(ce->getOperand(0), dl, symbols).o; - llvm::Type *t = ce->getOperand(0)->getType(); - - llvm::User::value_op_iterator begin = ce->value_op_begin(); - ++begin; - std::vector indices(begin, ce->value_op_end()); - - int64_t offset = dl.getIndexedOffset(t, indices); - - /*if (VERBOSITY()) { - ce->dump(); - ce->getOperand(0)->dump(); - for (int i = 0; i < indices.size() ;i++) { - indices[i]->dump(); - } - printf("resulting offset: %ld\n", offset); - }*/ - - return base + offset; - } else { - v->dump(); - RELEASE_ASSERT(0, ""); - } - } - /*case llvm::Value::FunctionVal: { - llvm::Function* f = llvm::cast(v); - if (f->getName() == "printf") { - return (int64_t)printf; - } else if (f->getName() == "reoptCompiledFunc") { - return (int64_t)reoptCompiledFunc; - } else if (f->getName() == "compilePartialFunc") { - return (int64_t)compilePartialFunc; - } else if (startswith(f->getName(), "runtimeCall")) { - return (int64_t)g.func_registry.getFunctionAddress("runtimeCall"); - } else { - return (int64_t)g.func_registry.getFunctionAddress(f->getName()); - } - }*/ - case llvm::Value::GlobalVariableVal: { - llvm::GlobalVariable* gv = llvm::cast(v); - if (!gv->isDeclaration() && gv->getLinkage() == llvm::GlobalVariable::InternalLinkage) { - static std::unordered_map made; - - void* &r = made[gv]; - if (r == NULL) { - llvm::Type *t = gv->getType()->getElementType(); - r = (void*)malloc(width(t, dl)); - if (gv->hasInitializer()) { - llvm::Constant* init = gv->getInitializer(); - assert(init->getType() == t); - if (t == g.i64) { - llvm::ConstantInt *ci = llvm::cast(init); - *(int64_t*)r = ci->getSExtValue(); - } else { - gv->dump(); - RELEASE_ASSERT(0, ""); - } - } - } - - //gv->getType()->dump(); - //gv->dump(); - //printf("%p\n", r); - //RELEASE_ASSERT(0, ""); - return (int64_t)r; - } - - gv->dump(); - RELEASE_ASSERT(0, ""); - } - case llvm::Value::UndefValueVal: - return (int64_t)-1337; - default: - v->dump(); - RELEASE_ASSERT(0, "%d", v->getValueID()); - } -} - -static void set(SymMap &symbols, const llvm::BasicBlock::iterator &it, Val v) { - if (VERBOSITY() >= 2) { - printf("Setting to %lx / %f: ", v.n, v.d); - fflush(stdout); - it->dump(); - } - - SymMap::iterator f = symbols.find(it); - if (f != symbols.end()) - f->second = v; - else - symbols.insert(std::make_pair(static_cast(&(*it)), v)); -//#define SET(v) symbols.insert(std::make_pair(static_cast(&(*it)), Val(v))) -} - -static std::unordered_map interpreter_roots; -void gatherInterpreterRootsForFrame(GCVisitor *visitor, void* frame_ptr) { - auto it = interpreter_roots.find(frame_ptr); - if (it == interpreter_roots.end()) { - printf("%p is not an interpreter frame; they are", frame_ptr); - for (auto it2 : interpreter_roots) { - printf(" %p", it2.first); - } - printf("\n"); - abort(); - } - - //printf("Gathering roots for frame %p\n", frame_ptr); - const SymMap* symbols = it->second; - - for (auto it2 : *symbols) { - visitor->visitPotential(it2.second.o); - } -} - -class UnregisterHelper { - private: - void* frame_ptr; - - public: - constexpr UnregisterHelper(void* frame_ptr) : frame_ptr(frame_ptr) {} - - ~UnregisterHelper() { - assert(interpreter_roots.count(frame_ptr)); - interpreter_roots.erase(frame_ptr); - } -}; - -Box* interpretFunction(llvm::Function *f, int nargs, Box* arg1, Box* arg2, Box* arg3, Box* *args) { - assert(f); - -#ifdef TIME_INTERPRETS - Timer _t("to interpret", 1000000); - long this_us = 0; -#endif - - static StatCounter interpreted_runs("interpreted_runs"); - interpreted_runs.log(); - - llvm::DataLayout dl(f->getParent()); - - //f->dump(); - //assert(nargs == f->getArgumentList().size()); - - SymMap symbols; - - void* frame_ptr = __builtin_frame_address(0); - interpreter_roots[frame_ptr] = &symbols; - UnregisterHelper helper(frame_ptr); - - int i = 0; - for (llvm::Function::arg_iterator AI = f->arg_begin(), end = f->arg_end(); AI != end; AI++, i++) { - if (i == 0) symbols.insert(std::make_pair(static_cast(&(*AI)), Val(arg1))); - else if (i == 1) symbols.insert(std::make_pair(static_cast(&(*AI)), Val(arg2))); - else if (i == 2) symbols.insert(std::make_pair(static_cast(&(*AI)), Val(arg3))); - else { - assert(i == 3); - assert(f->getArgumentList().size() == 4); - assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo()); - symbols.insert(std::make_pair(static_cast(&(*AI)), Val((int64_t)args))); - //printf("loading %%4 with %p\n", (void*)args); - break; - } - } - - llvm::BasicBlock *prevblock = NULL; - llvm::BasicBlock *curblock = &f->getEntryBlock(); - - - while (true) { - for (llvm::BasicBlock::iterator it = curblock->begin(), end = curblock->end(); it != end; ++it) { - if (VERBOSITY("interpreter") >= 2) { - printf("executing in %s: ", f->getName().data()); - fflush(stdout); - it->dump(); - //f->dump(); - } - -#define SET(v) set(symbols, it, (v)) - if (llvm::LoadInst *li = llvm::dyn_cast(it)) { - llvm::Value *ptr = li->getOperand(0); - Val v = fetch(ptr, dl, symbols); - //printf("loading from %p\n", v.o); - - if (width(li, dl) == 1) { - Val r = Val(*(bool*)v.o); - SET(r); - continue; - } else if (width(li, dl) == 8) { - Val r = Val(*(int64_t*)v.o); - SET(r); - continue; - } else { - li->dump(); - RELEASE_ASSERT(0, ""); - } - } else if (llvm::StoreInst *si = llvm::dyn_cast(it)) { - llvm::Value *val = si->getOperand(0); - llvm::Value *ptr = si->getOperand(1); - Val v = fetch(val, dl, symbols); - Val p = fetch(ptr, dl, symbols); - - //printf("storing %lx at %lx\n", v.n, p.n); - - if (width(val, dl) == 1) { - *(bool*)p.o = v.b; - continue; - } else if (width(val, dl) == 8) { - *(int64_t*)p.o = v.n; - continue; - } else { - si->dump(); - RELEASE_ASSERT(0, ""); - } - } else if (llvm::CmpInst *ci = llvm::dyn_cast(it)) { - assert(ci->getType() == g.i1); - - Val a0 = fetch(ci->getOperand(0), dl, symbols); - Val a1 = fetch(ci->getOperand(1), dl, symbols); - llvm::CmpInst::Predicate pred = ci->getPredicate(); - switch (pred) { - case llvm::CmpInst::ICMP_EQ: - SET(a0.n == a1.n); - continue; - case llvm::CmpInst::ICMP_NE: - SET(a0.n != a1.n); - continue; - case llvm::CmpInst::ICMP_SLT: - SET(a0.n < a1.n); - continue; - case llvm::CmpInst::ICMP_SLE: - SET(a0.n <= a1.n); - continue; - case llvm::CmpInst::ICMP_SGT: - SET(a0.n > a1.n); - continue; - case llvm::CmpInst::ICMP_SGE: - SET(a0.n >= a1.n); - continue; - case llvm::CmpInst::FCMP_OEQ: - SET(a0.d == a1.d); - continue; - case llvm::CmpInst::FCMP_UNE: - SET(a0.d != a1.d); - continue; - case llvm::CmpInst::FCMP_OLT: - SET(a0.d < a1.d); - continue; - case llvm::CmpInst::FCMP_OLE: - SET(a0.d <= a1.d); - continue; - case llvm::CmpInst::FCMP_OGT: - SET(a0.d > a1.d); - continue; - case llvm::CmpInst::FCMP_OGE: - SET(a0.d >= a1.d); - continue; - default: - ci->dump(); - RELEASE_ASSERT(0, ""); - } - continue; - } else if (llvm::BinaryOperator *bo = llvm::dyn_cast(it)) { - if (bo->getOperand(0)->getType() == g.i64 || bo->getOperand(0)->getType() == g.i1) { - //assert(bo->getOperand(0)->getType() == g.i64); - //assert(bo->getOperand(1)->getType() == g.i64); - - Val a0 = fetch(bo->getOperand(0), dl, symbols); - Val a1 = fetch(bo->getOperand(1), dl, symbols); - llvm::Instruction::BinaryOps opcode = bo->getOpcode(); - switch (opcode) { - case llvm::Instruction::Add: - SET(a0.n + a1.n); - continue; - case llvm::Instruction::And: - SET(a0.n & a1.n); - continue; - case llvm::Instruction::AShr: - SET(a0.n >> a1.n); - continue; - case llvm::Instruction::Mul: - SET(a0.n * a1.n); - continue; - case llvm::Instruction::Or: - SET(a0.n | a1.n); - continue; - case llvm::Instruction::Shl: - SET(a0.n << a1.n); - continue; - case llvm::Instruction::Sub: - SET(a0.n - a1.n); - continue; - case llvm::Instruction::Xor: - SET(a0.n ^ a1.n); - continue; - default: - bo->dump(); - RELEASE_ASSERT(0, ""); - } - continue; - } else if (bo->getOperand(0)->getType() == g.double_) { - //assert(bo->getOperand(0)->getType() == g.i64); - //assert(bo->getOperand(1)->getType() == g.i64); - - double lhs = fetch(bo->getOperand(0), dl, symbols).d; - double rhs = fetch(bo->getOperand(1), dl, symbols).d; - llvm::Instruction::BinaryOps opcode = bo->getOpcode(); - switch (opcode) { - case llvm::Instruction::FAdd: - SET(lhs + rhs); - continue; - case llvm::Instruction::FMul: - SET(lhs * rhs); - continue; - case llvm::Instruction::FSub: - SET(lhs - rhs); - continue; - default: - bo->dump(); - RELEASE_ASSERT(0, ""); - } - continue; - } else { - bo->dump(); - RELEASE_ASSERT(0, ""); - } - } else if (llvm::GetElementPtrInst *gep = llvm::dyn_cast(it)) { - int64_t base = fetch(gep->getPointerOperand(), dl, symbols).n; - - llvm::User::value_op_iterator begin = gep->value_op_begin(); - ++begin; - std::vector indices(begin, gep->value_op_end()); - - int64_t offset = dl.getIndexedOffset(gep->getPointerOperandType(), indices); - //gep->dump(); - //printf("offset for inst: %ld (base is %lx)\n", offset, base); - SET(base + offset); - continue; - } else if (llvm::AllocaInst *al = llvm::dyn_cast(it)) { - int size = fetch(al->getArraySize(), dl, symbols).n * width(al->getAllocatedType(), dl); - void* ptr = alloca(size); - //void* ptr = malloc(size); - //printf("alloca()'d at %p\n", ptr); - SET((int64_t)ptr); - continue; - } else if (llvm::SIToFPInst *si = llvm::dyn_cast(it)) { - assert(width(si->getOperand(0), dl) == 8); - SET((double)fetch(si->getOperand(0), dl, symbols).n); - continue; - } else if (llvm::BitCastInst *bc = llvm::dyn_cast(it)) { - assert(width(bc->getOperand(0), dl) == 8); - SET(fetch(bc->getOperand(0), dl, symbols)); - continue; - } else if (llvm::IntToPtrInst *bc = llvm::dyn_cast(it)) { - assert(width(bc->getOperand(0), dl) == 8); - SET(fetch(bc->getOperand(0), dl, symbols)); - continue; - } else if (llvm::CallInst *ci = llvm::dyn_cast(it)) { - void* f; - int arg_start; - if (ci->getCalledFunction() && (ci->getCalledFunction()->getName() == "llvm.experimental.patchpoint.void" || ci->getCalledFunction()->getName() == "llvm.experimental.patchpoint.i64")) { - //ci->dump(); - f = (void*)fetch(ci->getArgOperand(2), dl, symbols).n; - arg_start = 4; - } else { - f = (void*)fetch(ci->getCalledValue(), dl, symbols).n; - arg_start = 0; - } - - if (VERBOSITY("interpreter") >= 2) printf("calling %s\n", g.func_addr_registry.getFuncNameAtAddress(f, true).c_str()); - - std::vector args; - int nargs = ci->getNumArgOperands(); - for (int i = arg_start; i < nargs; i++) { - //ci->getArgOperand(i)->dump(); - args.push_back(fetch(ci->getArgOperand(i), dl, symbols)); - } - - int npassed_args = nargs - arg_start; - //printf("%d %d %d\n", nargs, arg_start, npassed_args); - -#ifdef TIME_INTERPRETS - this_us += _t.end(); -#endif - // This is dumb but I don't know how else to do it: - - int mask = 1; - if (ci->getType() == g.double_) - mask = 3; - else - mask = 2; - - for (int i = 0; i < npassed_args; i++) { - mask <<= 1; - if (ci->getOperand(i)->getType() == g.double_) - mask |= 1; - } - - Val r((int64_t)0); - switch (mask) { - case 0b10: - r = reinterpret_cast(f)(); - break; - case 0b11: - r = reinterpret_cast(f)(); - break; - case 0b100: - r = reinterpret_cast(f)(args[0].n); - break; - case 0b101: - r = reinterpret_cast(f)(args[0].d); - break; - case 0b110: - r = reinterpret_cast(f)(args[0].n); - break; - case 0b1000: - r = reinterpret_cast(f)(args[0].n, args[1].n); - break; - case 0b1001: - r = reinterpret_cast(f)(args[0].n, args[1].d); - break; - case 0b1011: - r = reinterpret_cast(f)(args[0].d, args[1].d); - break; - case 0b1111: - r = reinterpret_cast(f)(args[0].d, args[1].d); - break; - case 0b10000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n); - break; - case 0b10001: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].d); - break; - case 0b10011: - r = reinterpret_cast(f)(args[0].n, args[1].d, args[2].d); - break; - case 0b100000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].n); - break; - case 0b100001: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].d); - break; - case 0b100110: - r = reinterpret_cast(f)(args[0].n, args[1].d, args[2].d, args[3].n); - break; - case 0b101010: - r = reinterpret_cast(f)(args[0].d, args[1].n, args[2].d, args[3].n); - break; - case 0b1000000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].n, args[4].n); - break; - case 0b10000000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n); - break; - case 0b100000000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n, args[6].n); - break; - case 0b1000000000: - r = reinterpret_cast(f)(args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n, args[6].n, args[7].n); - break; - default: - it->dump(); - RELEASE_ASSERT(0, "%d", mask); - break; - } - if (ci->getType() != g.void_) - SET(r); - - -#ifdef TIME_INTERPRETS - _t.restart("to interpret", 10000000); -#endif - continue; - } else if (llvm::SelectInst *si = llvm::dyn_cast(it)) { - Val test = fetch(si->getCondition(), dl, symbols); - Val vt = fetch(si->getTrueValue(), dl, symbols); - Val vf = fetch(si->getFalseValue(), dl, symbols); - if (test.b) - SET(vt); - else - SET(vf); - continue; - } else if (llvm::PHINode *phi = llvm::dyn_cast(it)) { - assert(prevblock); - SET(fetch(phi->getIncomingValueForBlock(prevblock), dl, symbols)); - continue; - } else if (llvm::BranchInst *br = llvm::dyn_cast(it)) { - prevblock = curblock; - if (br->isConditional()) { - Val t = fetch(br->getCondition(), dl, symbols); - if (t.b) { - curblock = br->getSuccessor(0); - } else { - curblock = br->getSuccessor(1); - } - } else { - curblock = br->getSuccessor(0); - } - //if (VERBOSITY()) { - //printf("jumped to %s\n", curblock->getName().data()); - //} - break; - } else if (llvm::ReturnInst *ret = llvm::dyn_cast(it)) { - llvm::Value* r = ret->getReturnValue(); - -#ifdef TIME_INTERPRETS - this_us += _t.end(); - static StatCounter us_interpreting("us_interpreting"); - us_interpreting.log(this_us); -#endif - - if (!r) - return NULL; - Val t = fetch(r, dl, symbols); - return t.o; - } - - - it->dump(); - RELEASE_ASSERT(0, ""); - } - } - - RELEASE_ASSERT(0, ""); -} - -} diff --git a/src/codegen/llvm_interpreter.h b/src/codegen/llvm_interpreter.h deleted file mode 100644 index da3e2f74a..000000000 --- a/src/codegen/llvm_interpreter.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_LLVMINTERPRETER_H -#define PYSTON_CODEGEN_LLVMINTERPRETER_H - -namespace llvm { -class Function; -} - -namespace pyston { - -class Box; -class GCVisitor; - -void gatherInterpreterRootsForFrame(GCVisitor *visitor, void* frame_ptr); -Box* interpretFunction(llvm::Function *f, int nargs, Box* arg1, Box* arg2, Box* arg3, Box* *args); - -} - -#endif diff --git a/src/codegen/memmgr.cpp b/src/codegen/memmgr.cpp deleted file mode 100644 index 6037218db..000000000 --- a/src/codegen/memmgr.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Memory.h" - -#include "core/common.h" - -#include "core/util.h" - -#include "codegen/memmgr.h" - -// This code was copy-pasted from SectionMemoryManager.cpp; -// TODO eventually I should remove this using directive -// and recode in my style -using namespace llvm; - -namespace pyston { - -class PystonMemoryManager : public RTDyldMemoryManager { - public: - PystonMemoryManager() { } - virtual ~PystonMemoryManager(); - - virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - StringRef SectionName); - - virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - StringRef SectionName, - bool isReadOnly); - - virtual bool finalizeMemory(std::string *ErrMsg = 0); - - virtual void invalidateInstructionCache(); - - private: - struct MemoryGroup { - SmallVector AllocatedMem; - SmallVector FreeMem; - sys::MemoryBlock Near; - }; - - uint8_t *allocateSection(MemoryGroup &MemGroup, uintptr_t Size, - unsigned Alignment); - - error_code applyMemoryGroupPermissions(MemoryGroup &MemGroup, - unsigned Permissions); - - virtual uint64_t getSymbolAddress(const std::string &Name); - - MemoryGroup CodeMem; - MemoryGroup RWDataMem; - MemoryGroup RODataMem; -}; - -uint8_t *PystonMemoryManager::allocateDataSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName, - bool IsReadOnly) { - //printf("allocating data section: %ld %d %d %s %d\n", Size, Alignment, SectionID, SectionName.data(), IsReadOnly); - //assert(SectionName != ".llvm_stackmaps"); - if (IsReadOnly) - return allocateSection(RODataMem, Size, Alignment); - return allocateSection(RWDataMem, Size, Alignment); -} - -uint8_t *PystonMemoryManager::allocateCodeSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName) { - //printf("allocating code section: %ld %d %d %s\n", Size, Alignment, SectionID, SectionName.data()); - return allocateSection(CodeMem, Size, Alignment); -} - -uint8_t *PystonMemoryManager::allocateSection(MemoryGroup &MemGroup, - uintptr_t Size, - unsigned Alignment) { - if (!Alignment) - Alignment = 16; - - assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); - - uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1)/Alignment + 1); - uintptr_t Addr = 0; - - // Look in the list of free memory regions and use a block there if one - // is available. - for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { - sys::MemoryBlock &MB = MemGroup.FreeMem[i]; - if (MB.size() >= RequiredSize) { - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - // Store cutted free memory block. - MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), - EndOfBlock - Addr - Size); - return (uint8_t*)Addr; - } - } - - // No pre-allocated free block was large enough. Allocate a new memory region. - // Note that all sections get allocated as read-write. The permissions will - // be updated later based on memory group. - // - // FIXME: It would be useful to define a default allocation size (or add - // it as a constructor parameter) to minimize the number of allocations. - // - // FIXME: Initialize the Near member for each memory group to avoid - // interleaving. - error_code ec; - sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(RequiredSize, - &MemGroup.Near, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, - ec); - if (ec) { - // FIXME: Add error propogation to the interface. - return NULL; - } - - // Save this address as the basis for our next request - MemGroup.Near = MB; - - MemGroup.AllocatedMem.push_back(MB); - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - // The allocateMappedMemory may allocate much more memory than we need. In - // this case, we store the unused memory as a free memory block. - unsigned FreeSize = EndOfBlock-Addr-Size; - if (FreeSize > 16) - MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); - - // Return aligned address - return (uint8_t*)Addr; -} - -bool PystonMemoryManager::finalizeMemory(std::string *ErrMsg) -{ - // FIXME: Should in-progress permissions be reverted if an error occurs? - error_code ec; - - // Don't allow free memory blocks to be used after setting protection flags. - CodeMem.FreeMem.clear(); - - // Make code memory executable. - // pyston: also make it writeable so we can patch it later - ec = applyMemoryGroupPermissions(CodeMem, - sys::Memory::MF_READ | sys::Memory::MF_EXEC | sys::Memory::MF_WRITE); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Don't allow free memory blocks to be used after setting protection flags. - RODataMem.FreeMem.clear(); - - // Make read-only data memory read-only. - ec = applyMemoryGroupPermissions(RODataMem, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Read-write data memory already has the correct permissions - - // Some platforms with separate data cache and instruction cache require - // explicit cache flush, otherwise JIT code manipulations (like resolved - // relocations) will get to the data cache but not to the instruction cache. - invalidateInstructionCache(); - - return false; -} - -error_code PystonMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, - unsigned Permissions) { - - for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) { - error_code ec; - ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], - Permissions); - if (ec) { - return ec; - } - } - - return error_code::success(); -} - -void PystonMemoryManager::invalidateInstructionCache() { - for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), - CodeMem.AllocatedMem[i].size()); -} - -uint64_t PystonMemoryManager::getSymbolAddress(const std::string &name) { - uint64_t base = RTDyldMemoryManager::getSymbolAddress(name); - if (base) return base; - - if (startswith(name, "__PRETTY_FUNCTION__")) { - return getSymbolAddress(".L" + name); - } - - printf("getSymbolAddress(%s); %lx\n", name.c_str(), base); - return 0; -} - -PystonMemoryManager::~PystonMemoryManager() { - for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); - for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); - for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i) - sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]); -} - -llvm::RTDyldMemoryManager* createMemoryManager() { - return new PystonMemoryManager(); -} - -} - diff --git a/src/codegen/memmgr.h b/src/codegen/memmgr.h deleted file mode 100644 index 4c4e0b86c..000000000 --- a/src/codegen/memmgr.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_MEMMGR_H -#define PYSTON_CODEGEN_MEMMGR_H - -namespace llvm { -class RTDyldMemoryManager; -} - -namespace pyston { -llvm::RTDyldMemoryManager* createMemoryManager(); -} - -#endif diff --git a/src/codegen/opt/aa.cpp b/src/codegen/opt/aa.cpp deleted file mode 100644 index fbc91798c..000000000 --- a/src/codegen/opt/aa.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Support/raw_ostream.h" - -#ifndef STANDALONE -#include "core/common.h" -#include "core/options.h" - -#include "codegen/codegen.h" - -#else -#define VERBOSITY(...) 1 -#endif - -#include "codegen/opt/escape_analysis.h" -#include "codegen/opt/util.h" - -using namespace llvm; - -namespace llvm { - void initializePystonAAPass(PassRegistry&); -} - -namespace pyston { - -class PystonAA : public ImmutablePass, public AliasAnalysis { - private: - int depth; - - void indent() { - for (int i = 0; i < depth - 1; i++) { - errs() << " "; - } - } - public: - static char ID; // Class identification, replacement for typeinfo - PystonAA() : ImmutablePass(ID), depth(0) { - initializePystonAAPass(*PassRegistry::getPassRegistry()); - } - - void initializePass() override { - AliasAnalysis::InitializeAliasAnalysis(this); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AliasAnalysis::getAnalysisUsage(AU); - AU.addRequired(); - AU.addRequired(); - AU.setPreservesAll(); - } - - AliasResult _alias(const Location &LocA, const Location &LocB) { - AliasResult base = AliasAnalysis::alias(LocA, LocB); - - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "_alias():\n"; - //cast(LocA.Ptr)->getParent()->dump(); - indent(); errs() << LocA.Size << " "; LocA.Ptr->dump(); - indent(); errs() << LocB.Size << " "; LocB.Ptr->dump(); - indent(); errs() << "base: " << base << '\n'; - } - - if (base != MayAlias) - return base; - - if (LocA.Ptr == LocB.Ptr) { - assert(0 && "this should be handled by BasicAA???"); - return MustAlias; - } - - const Location locs[] = {LocA, LocB}; - - for (int i = 0; i < 2; i++) { - const BitCastInst *BI = dyn_cast(locs[i].Ptr); - if (!BI) continue; - - const Value* bc_base = *BI->op_begin(); - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "loc " << i << " is bitcast, recursing\n"; - } - AliasResult bc_base_aliases = alias(locs[i^1], Location(bc_base, locs[i].Size)); - if (VERBOSITY("opt.aa") >= 2) { - indent(); bc_base->dump(); - indent(); errs() << "bc base aliases: " << bc_base_aliases << '\n'; - } - return bc_base_aliases; - } - - { - const GetElementPtrInst *GIa, *GIb; - GIa = dyn_cast(LocA.Ptr); - GIb = dyn_cast(LocB.Ptr); - if (GIa && GIb) { - const Value *baseA, *baseB; - baseA = GIa->getPointerOperand(); - baseB = GIb->getPointerOperand(); - - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "2 geps, recursing\n"; - } - AliasResult bases_alias = alias(Location(baseA), Location(baseB)); - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "2gep base aliases: " << bases_alias << '\n'; - indent(); LocA.Ptr->dump(); - indent(); LocB.Ptr->dump(); - } - - if (bases_alias == NoAlias) - return NoAlias; - - if (bases_alias == MustAlias) { - APInt offsetA(64, 0, true), offsetB(64, 0, true); - const DataLayout *DL = getDataLayout(); - assert(DL); - bool accumA = GIa->accumulateConstantOffset(*DL, offsetA); - bool accumB = GIb->accumulateConstantOffset(*DL, offsetB); - if (accumA && accumB) { - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << offsetA << ' ' << LocA.Size << ' ' << offsetB << ' ' << LocB.Size << '\n'; - } - int sizeA = LocA.Size; - int sizeB = LocB.Size; - if (offsetA == offsetB) { - if (sizeA == sizeB) - return MustAlias; - return PartialAlias; - } else if (offsetA.slt(offsetB)) { - if (APInt(64, sizeA, true).sle(offsetB - offsetA)) - return NoAlias; - return PartialAlias; - } else { - if (APInt(64, sizeB, true).sle(offsetA - offsetB)) - return NoAlias; - return PartialAlias; - } - } - } - - return MayAlias; - //RELEASE_ASSERT(0, ""); - } - } - - for (int i = 0; i < 2; i++) { - const GetElementPtrInst *GI = dyn_cast(locs[i].Ptr); - if (!GI) continue; - - if (!GI->isInBounds()) continue; - //ASSERT(GI->getNumIndices() > 1, "%d %u", i, GI->getNumIndices()); - - const Value* gep_base = GI->getPointerOperand(); - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "loc " << i << " is gep, recursing\n"; - } - AliasResult gep_base_aliases = alias(locs[i^1], Location(gep_base)); - if (VERBOSITY("opt.aa") >= 2) { - indent(); gep_base->dump(); - indent(); errs() << "gep base aliases: " << gep_base_aliases << '\n'; - } - if (gep_base_aliases == NoAlias) - return NoAlias; - return MayAlias; - } - - for (int i = 0; i < 2; i++) { - const CallInst *I = dyn_cast(locs[i].Ptr); - if (!I) continue; - - Function *F = I->getCalledFunction(); - if (!F) continue; - - if (isAllocCall(F->getName())) - return NoAlias; - - //if (F->getName() == "malloc") - //return NoAlias; -// - //if (F->getName() == "_ZN6pyston2gc4Heap10allocSmallEmPPNS0_5BlockES4_") { - //return NoAlias; - //} - - if (F->getName() == "_ZN6pyston2gc13runCollectionEv") { - assert(0); - return NoAlias; - } - } - - return MayAlias; - } - - virtual AliasResult alias(const Location &LocA, const Location &LocB) { - if (VERBOSITY("opt.aa") >= 2 && depth == 0) { - cast(LocA.Ptr)->getParent()->dump(); - } - - depth++; - AliasResult rtn = _alias(LocA, LocB); - if (VERBOSITY("opt.aa") >= 2) { - indent(); errs() << "alias():\n"; - indent(); LocA.Ptr->dump(); - indent(); LocB.Ptr->dump(); - indent(); errs() << "result: " << rtn << '\n'; - } - depth--; - return rtn; - } - - // There are multiple (overloaded) "getModRefInfo" functions in AliasAnalysis, and apparently - // this means you need to add this line: - using AliasAnalysis::getModRefInfo; - virtual ModRefResult getModRefInfo(ImmutableCallSite CS, - const Location &Loc) { - ModRefResult base = AliasAnalysis::getModRefInfo(CS, Loc); - if (!CS.getCalledFunction()) - return base; - - if (VERBOSITY("opt.aa") >= 2) { - errs() << "getModRefInfo():\n"; - CS->dump(); - Loc.Ptr->dump(); - outs() << "base: " << base << '\n'; - } - - ModRefResult mask = ModRef; - - StringRef name = CS.getCalledFunction()->getName(); - if (isAllocCall(name)) { - return NoModRef; - } - - EscapeAnalysis &escape = getAnalysis(); - EscapeAnalysis::EscapeResult escapes = escape.escapes(Loc.Ptr, CS.getInstruction()); - if (escapes != EscapeAnalysis::Escaped) { - StatCounter num_improved("opt_modref_noescape"); - num_improved.log(); - if (VERBOSITY("opt.aa") >= 2) { - errs() << "Was able to show that " << *CS.getInstruction() << " can't modify " << *Loc.Ptr << '\n'; - } - return NoModRef; - } - - /*if (name == "printf" || name == "my_realloc" || name == "print_space_if_necessary" || name == "write") { - mask = Ref; - bool found_alias = false; - for (User::const_op_iterator op_it = CS.arg_begin(), op_end = CS.arg_end(); op_it != op_end; ++op_it) { - if (alias(Loc, Location(op_it->get())) != NoAlias) { - found_alias = true; - break; - } - } - if (!found_alias) - mask = NoModRef; - } else if (name == "snprintf" || name == "str_decref" || name == "read" || name == "file_write") { - mask = ModRef; - bool found_alias = false; - for (User::const_op_iterator op_it = CS.arg_begin(), op_end = CS.arg_end(); op_it != op_end; ++op_it) { - if (alias(Loc, Location(op_it->get())) != NoAlias) { - //errs() << '\n'; - //errs() << *CS.getInstruction() << '\n'; - //errs() << **op_it << '\n'; - found_alias = true; - break; - } - } - if (!found_alias) { - mask = NoModRef; - } - } else if (name == "my_free" || name == "my_malloc" || name == "close" || name == "int_repr") { - mask = NoModRef; - }*/ - - return ModRefResult(mask & base); - } - - virtual void *getAdjustedAnalysisPointer(const void *ID) { - if (ID == &AliasAnalysis::ID) - return (AliasAnalysis*)this; - return this; - } -}; -char PystonAA::ID = 0; - -llvm::ImmutablePass* createPystonAAPass() { - return new PystonAA(); -} - -} - -using namespace pyston; -INITIALIZE_AG_PASS(PystonAA, AliasAnalysis, "pystonaa", - "Pyston AA", - false, true, false) - -namespace { - struct Foo { - Foo() { - initializePystonAAPass(*PassRegistry::getPassRegistry()); - } - } _f; -} - diff --git a/src/codegen/opt/const_classes.cpp b/src/codegen/opt/const_classes.cpp deleted file mode 100644 index 7258a0bc3..000000000 --- a/src/codegen/opt/const_classes.cpp +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/PostDominators.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "core/common.h" -#include "core/options.h" - -#include "codegen/codegen.h" -#include "codegen/irgen/util.h" - -#include "runtime/objmodel.h" -#include "runtime/types.h" - -using namespace llvm; - -namespace pyston { - -#define CLS_DTOR_OFFSET ((const char*)&(((BoxedClass*)0x01)->dtor) - (const char*)0x1) -#define CLS_HASATTRS_OFFSET ((const char*)&(((BoxedClass*)0x01)->hasattrs) - (const char*)0x1) -#define FLAVOR_KINDID_OFFSET ((const char*)&(((ObjectFlavor*)0x01)->kind_id) - (const char*)0x1) - -class ConstClassesPass : public FunctionPass { - private: - void* getGVAddr(GlobalVariable* gv) { - // TODO cache this? - void* handle = dlopen(NULL, RTLD_LAZY); - void* addr = dlsym(handle, gv->getName().data()); - assert(addr); - dlclose(handle); - return addr; - } - BoxedClass* getClassFromGV(GlobalVariable* gv) { - return *(BoxedClass**)getGVAddr(gv); - } - - ObjectFlavor* getFlavorFromGV(GlobalVariable* gv) { - return (ObjectFlavor*)getGVAddr(gv); - } - - void replaceUsesWithConstant(llvm::Value* v, uintptr_t val) { - if (isa(v->getType())) - v->replaceAllUsesWith(embedConstantPtr((void*)val, v->getType())); - else - v->replaceAllUsesWith(getConstantInt(val, v->getType())); - } - - bool handleBool(LoadInst *li, GlobalVariable *gv) { - if (VERBOSITY()) { - llvm::errs() << "Constant-folding this load: " << *li << '\n'; - } - if (gv->getName() == "True") - li->replaceAllUsesWith(embedConstantPtr(True, g.llvm_bool_type_ptr)); - else - li->replaceAllUsesWith(embedConstantPtr(False, g.llvm_bool_type_ptr)); - return true; - } - - bool handleFlavor(LoadInst *li, ConstantExpr *gepce) { - if (VERBOSITY("opt") >= 1) { - errs() << "\nFound this load of a flavor attr:\n" << *li << '\n'; - } - - GetElementPtrInst *gep = cast(gepce->getAsInstruction()); - APInt ap_offset(64, 0, true); - bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); - delete gep; - assert(success); - int64_t offset = ap_offset.getSExtValue(); - - if (offset == FLAVOR_KINDID_OFFSET) { - ObjectFlavor* flavor = getFlavorFromGV(cast(gepce->getOperand(0))); - replaceUsesWithConstant(li, flavor->kind_id); - return true; - } else { - ASSERT(0, "%ld", offset); - return false; - } - - assert(0); - return false; - } - - bool handleCls(LoadInst *li, GlobalVariable *gv) { - bool changed = true; - - if (VERBOSITY("opt") >= 1) { - errs() << "\nFound load of class-typed global variable:\n" << *li << '\n'; - } - - BoxedClass *cls = getClassFromGV(gv); - if (!cls->is_constant) { - assert(0 && "what globally-resolved classes are not constant??"); - if (VERBOSITY("opt") >= 1) { - errs() << gv->getName() << " is not constant; moving on\n"; - } - return false; - } - - std::vector to_remove; - for (Value::use_iterator use_it = li->use_begin(), use_end = li->use_end(); use_it != use_end; ++use_it) { - if (CallInst *call = dyn_cast(*use_it)) { - if (call->getCalledFunction()->getName() == "_maybeDecrefCls") { - errs() << "Found decrefcls call: " << *call << '\n'; - if (!isUserDefined(cls)) { - // Don't delete right away; I think that invalidates the iterator - // we're currently iterating over - to_remove.push_back(call); - } - } - continue; - } - - GetElementPtrInst *gep = dyn_cast(*use_it); - if (!gep) { - //errs() << "Not a gep: " << **use_it << '\n'; - continue; - } - - APInt ap_offset(64, 0, true); - bool success = gep->accumulateConstantOffset(*g.tm->getDataLayout(), ap_offset); - assert(success); - int64_t offset = ap_offset.getSExtValue(); - - errs() << "Found a gep at offset " << offset << ": " << *gep << '\n'; - - for (Value::use_iterator gep_use_it = gep->use_begin(), gep_use_end = gep->use_end(); gep_use_it != gep_use_end; ++gep_use_it) { - LoadInst *gep_load = dyn_cast(*gep_use_it); - if (!gep_load) { - //errs() << "Not a load: " << **gep_use_it << '\n'; - continue; - } - - - errs() << "Found a load: " << *gep_load << '\n'; - - if (offset == CLS_DTOR_OFFSET) { - errs() << "Dtor; replacing with " << cls->dtor << "\n"; - replaceUsesWithConstant(gep_load, (uintptr_t)cls->dtor); - changed = true; - } else if (offset == CLS_HASATTRS_OFFSET) { - errs() << "Hasattrs; replacing with " << cls->hasattrs << "\n"; - replaceUsesWithConstant(gep_load, cls->hasattrs); - changed = true; - } - } - - } - - for (int i = 0; i < to_remove.size(); i++) { - to_remove[i]->eraseFromParent(); - changed = true; - } - - if (VERBOSITY()) { - llvm::errs() << "Constant-folding this load: " << *li << '\n'; - } - li->replaceAllUsesWith(embedConstantPtr(cls, g.llvm_class_type_ptr)); - - changed = true; - return changed; - } - - public: - static char ID; - ConstClassesPass() : FunctionPass(ID) {} - - virtual void getAnalysisUsage(AnalysisUsage &info) const { - info.setPreservesCFG(); - } - - virtual bool runOnFunction(Function &F) { - //F.dump(); - bool changed = false; - for (inst_iterator inst_it = inst_begin(F), _inst_end = inst_end(F); inst_it != _inst_end; ++inst_it) { - LoadInst *li = dyn_cast(&*inst_it); - if (!li) continue; - - ConstantExpr *ce = dyn_cast(li->getOperand(0)); - // Not 100% sure what the isGEPWithNoNotionalOverIndexing() means, but - // at least it checks if it's a gep: - if (ce && ce->isGEPWithNoNotionalOverIndexing() && ce->getOperand(0)->getType() == g.llvm_flavor_type_ptr) { - changed = handleFlavor(li, ce); - } - - GlobalVariable *gv = dyn_cast(li->getOperand(0)); - if (!gv) continue; - - llvm::Type* gv_t = gv->getType(); - - if (gv_t == g.llvm_bool_type_ptr->getPointerTo()) { - changed = handleBool(li, gv) || changed; - continue; - } - - if (gv_t == g.llvm_class_type_ptr->getPointerTo()) { - changed = handleCls(li, gv) || changed; - continue; - } - } - - return changed; - } -}; -char ConstClassesPass::ID = 0; - -FunctionPass* createConstClassesPass() { - return new ConstClassesPass(); -} - -} - -static RegisterPass X("const_classes", "Use the fact that builtin classes are constant and their attributes can be constant-folded", true, false); - - - diff --git a/src/codegen/opt/dead_allocs.cpp b/src/codegen/opt/dead_allocs.cpp deleted file mode 100644 index b6ca90e6a..000000000 --- a/src/codegen/opt/dead_allocs.cpp +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/PostDominators.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" - -#include "codegen/irgen/util.h" -#include "codegen/opt/util.h" - -using namespace llvm; - -//#undef VERBOSITY -//#define VERBOSITY(...) 2 - -namespace pyston { - -class DeadAllocsPass : public FunctionPass { - private: - struct ChainInfo { - // there can be cyclic dependencies; use this to track those: - std::unordered_set seen; - - // Instructions that are free to be deleted if the chain is dead: - std::vector deletions; - // Loads that have to be remapped if the chain is dead: - std::vector loads; - }; - - bool canBeRead(llvm::Instruction *v, ChainInfo &chain) { - if (chain.seen.count(v)) - return false; - chain.seen.insert(v); - - for (Value::use_iterator use_it = v->use_begin(), use_end = v->use_end(); use_it != use_end; ++use_it) { - if (GetElementPtrInst *gep = dyn_cast(*use_it)) { - if (canBeRead(gep, chain)) - return true; - continue; - } - - if (BitCastInst *bc = dyn_cast(*use_it)) { - if (canBeRead(bc, chain)) - return true; - continue; - } - - if (PHINode *phi = dyn_cast(*use_it)) { - if (canBeRead(phi, chain)) - return true; - continue; - } - - - // Can't call canBeRead after this point: - chain.seen.insert(cast(*use_it)); - - if (StoreInst *si = dyn_cast(*use_it)) { - if (si->getPointerOperand() == v) { - chain.deletions.push_back(si); - continue; - } else { - if (VERBOSITY() >= 2) errs() << "Not dead; used here: " << *si << '\n'; - return true; - } - } - - if (MemSetInst *msi = dyn_cast(*use_it)) { - assert(v == msi->getArgOperand(0)); - chain.deletions.push_back(msi); - continue; - } - - if (CallInst *si = dyn_cast(*use_it)) { - if (VERBOSITY() >= 2) errs() << "Not dead; used here: " << *si << '\n'; - return true; - } - - if (ReturnInst *ret = dyn_cast(*use_it)) { - if (VERBOSITY() >= 2) errs() << "Not dead; used here: " << *ret << '\n'; - return true; - } - - if (LoadInst *li = dyn_cast(*use_it)) { - assert(li->getPointerOperand() == v); - chain.loads.push_back(li); - continue; - } - - errs() << **use_it << '\n'; - RELEASE_ASSERT(0, ""); - } - - chain.deletions.push_back(v); - return false; - } - - bool isDerivedFrom(Value* derived, Instruction* ancestor) { - if (derived == ancestor) - return true; - - if (GetElementPtrInst *gep = dyn_cast(derived)) { - return isDerivedFrom(gep->getPointerOperand(), ancestor); - } - - if (BitCastInst *bc = dyn_cast(derived)) { - return isDerivedFrom(bc->getOperand(0), ancestor); - } - - derived->dump(); - assert(0); - return false; - } - - Value* deriveSimilarly(Value* derived, Value* ancestor, Value* new_ancestor, Instruction *insert_before, std::vector &added) { - if (derived == ancestor) - return new_ancestor; - - if (GetElementPtrInst *gep = dyn_cast(derived)) { - std::vector indices; - for (GetElementPtrInst::op_iterator it = gep->idx_begin(), end = gep->idx_end(); it != end; ++it) { - indices.push_back(it->get()); - } - - Value* new_parent = deriveSimilarly(gep->getPointerOperand(), ancestor, new_ancestor, insert_before, added); - - Instruction* rtn = GetElementPtrInst::Create(new_parent, indices, "t", insert_before); - if (VERBOSITY() >= 2) errs() << "Added: " << *rtn << '\n'; - added.push_back(rtn); - return rtn; - } - - if (BitCastInst *bc = dyn_cast(derived)) { - Value* new_parent = deriveSimilarly(bc->getOperand(0), ancestor, new_ancestor, insert_before, added); - Instruction* rtn = new BitCastInst(new_parent, bc->getType(), "t", insert_before); - added.push_back(rtn); - if (VERBOSITY() >= 2) errs() << "Added: " << *rtn << '\n'; - return rtn; - } - - - derived->dump(); - RELEASE_ASSERT(0, ""); - } - - // Given a pointer that we're interested in, and an instruction that could potentially change the value of - // that pointer, return a Value that represents what was stored to the pointer. - // If the instruction has no effect on the pointer, returns NULL. - // - // TODO maybe this should take an AliasAnalysis::Location instead of the bare ptr? - Value* extractLoadValue(Value* ptr, Instruction* inst, ChainInfo &chain) { - // We've already determined all of the instructions that are related to this memory access, - // so we can just check to see if this instruction is potentially-related to our pointer: - if (chain.seen.count(inst) == 0) - return NULL; - - AliasAnalysis* aa = &getAnalysis(); - assert(aa); - DataLayout* dl = &getAnalysis(); - assert(dl); - - Type *elt_type = cast(ptr->getType())->getElementType(); - AliasAnalysis::Location ptr_loc(ptr, dl->getTypeStoreSize(elt_type)); - - if (StoreInst *si = dyn_cast(inst)) { - AliasAnalysis::AliasResult ar = aa->alias(ptr_loc, aa->getLocation(si)); - if (ar == AliasAnalysis::NoAlias) - return NULL; - - if (ar == AliasAnalysis::MustAlias) { - if (ptr->getType() == si->getPointerOperand()->getType()) { - return si->getValueOperand(); - } - - if (dl->getTypeStoreSize(elt_type) == dl->getTypeStoreSize(si->getValueOperand()->getType())) { - Instruction::CastOps cast_opcode = CastInst::getCastOpcode(si->getValueOperand(), true, elt_type, true); - CastInst *ci = CastInst::Create(cast_opcode, si->getValueOperand(), elt_type, "t", si); - return ci; - } - - si->dump(); - RELEASE_ASSERT(0, ""); - } - errs() << ar << ' ' << *inst << '\n'; - assert(ar != AliasAnalysis::MayAlias); - assert(ar != AliasAnalysis::PartialAlias); - RELEASE_ASSERT(0, ""); - } - - if (LoadInst *li = dyn_cast(inst)) { - // TODO: could optimize this by just returning this load, which would (hopefully) - // just end up doing the scanning once): - //if (li->getPointerOperand() == ptr) { - //return li; - //} - return NULL; - } - - if (isa(inst)) { - return NULL; - } - - if (isa(inst)) { - return NULL; - } - - if (PHINode* phi = dyn_cast(inst)) { - if (phi == ptr) { - assert(0 && "unimplemented"); - } - - // Right now we only handle the case that `ptr` is directly derived from phi. - // In this case, push the derivation up into the previous blocks, and then - // get a phi of the resolved loads. - // Note that it's possible that some of the incoming branches don't come from the - // allocation that we're trying to get rid of; in this case, just leave - // those branches as unresolved loads. - assert(isDerivedFrom(ptr, phi)); - - PHINode* load_phi = PHINode::Create(elt_type, phi->getNumIncomingValues(), "t", phi); - - if (VERBOSITY() >= 2) errs() << "Derived from phi: " << *phi << "; pushing back and adding " << *load_phi << "\n"; - for (int i = 0, e = phi->getNumIncomingValues(); i < e; i++) { - BasicBlock* prev_bb = phi->getIncomingBlock(i); - Value* prev_ptr = phi->getIncomingValue(i); - - std::vector added; - Value* prev_derived = deriveSimilarly(ptr, phi, prev_ptr, prev_bb->getTerminator(), added); - if (VERBOSITY() >= 2) errs() << "Phi-recursing on " << *prev_derived << '\n'; - std::unordered_map seen; - - llvm::Value* prev_resolved = getLoadValFrom(prev_derived, prev_bb, seen, chain); - if (prev_resolved == NULL) { - if (VERBOSITY() >= 2) errs() << "Wasn't able to resolve " << *prev_derived << "; just emitting a load\n"; - prev_resolved = new LoadInst(prev_derived, "t", prev_bb->getTerminator()); - } else { - if (VERBOSITY() >= 2) errs() << "Resolved " << *prev_derived << " to " << *prev_resolved << "; deleting the temporary instructions\n"; - for (int i = added.size() - 1; i >= 0; i--) { - if (VERBOSITY() >= 2) errs() << "Deleting temporary " << *added[i] << '\n'; - added[i]->eraseFromParent(); - } - } - //errs() << "Got " << *prev_resolved << " for " << *prev_derived << '\n'; - load_phi->addIncoming(prev_resolved, prev_bb); - } - return load_phi; - } - - if (GetElementPtrInst* gep = dyn_cast(inst)) { - return NULL; - } - - if (CallInst* ci = dyn_cast(inst)) { - if (isAllocCall(ci)) - return NULL; - - inst->dump(); - RELEASE_ASSERT(0, ""); - } - - inst->dump(); - RELEASE_ASSERT(0, ""); - } - - // Extract a Value corresponding to the value of this pointer, potentially traversing the CFG. - // Starts looking a the end of this BB and working backwards. - Value* getLoadValFrom(Value* ptr, BasicBlock* bb, std::unordered_map &seen, ChainInfo &chain) { - for (auto it = bb->rbegin(), end = bb->rend(); it != end; ++it) { - Value* v = extractLoadValue(ptr, &*it, chain); - if (v == NULL) - continue; - return v; - } - //errs() << "Not in bb " << bb << ", so trying to do phi-reconstruction\n"; - return getLoadValFromPrevious(ptr, bb, seen, chain); - } - - // Extract a Value corresponding to the value of this pointer, potentially traversing the CFG. - // Starts looking a the beginning of this BB, ie at its predecessors - Value* getLoadValFromPrevious(Value* ptr, BasicBlock* bb, std::unordered_map &seen, ChainInfo &chain) { - Value* &r = seen[bb]; - if (r != NULL) - return r; - - auto prev_bb = bb->getUniquePredecessor(); - if (prev_bb) { - return r = getLoadValFrom(ptr, prev_bb, seen, chain); - } - - PHINode* phi = PHINode::Create(cast(ptr->getType())->getElementType(), bb->getNumUses(), "t", bb->getFirstNonPHI()); - r = phi; - if (VERBOSITY() >= 2) errs() << "Added phi " << *phi << " in " << bb->getName() << '\n'; - - int num_predecessors = 0; - for (auto prev_bb = pred_begin(bb), end = pred_end(bb); prev_bb != end; ++prev_bb) { - num_predecessors++; - - if (VERBOSITY() >= 2) errs() << "Recursing into " << (*prev_bb)->getName() << '\n'; - Value* v = getLoadValFrom(ptr, *prev_bb, seen, chain); - if (VERBOSITY() >= 2) errs() << "Done recursing into " << (*prev_bb)->getName() << '\n'; - - assert(v); - phi->addIncoming(v, *prev_bb); - } - - // TODO should just have known this from the start - if (num_predecessors == 0) { - phi->eraseFromParent(); - r = NULL; - return NULL; - } - - if (VERBOSITY("opt") >= 1) errs() << "Finished adding phi in " << bb->getName() << ": " << *phi << '\n'; - return phi; - } - - // Remap a load that we have determined points to non-escaped memory. - // - // Maybe this could be implemented in terms of AA + GVN? - // This is pretty similar, but with slightly different assumptions about the - // memory model so I'm not sure it's a natural fit (not saying it can't be done)> - void remapLoad(LoadInst* li, ChainInfo &chain) { - if (VERBOSITY("opt")) { - //li->getParent()->getParent()->dump(); - errs() << "\nRemapping " << *li << '\n'; - } - - BasicBlock::reverse_iterator it = li->getParent()->rbegin(); - while (&*it != li) { - ++it; - } - ++it; - - Value* ptr = li->getPointerOperand(); - while (it != li->getParent()->rend()) { - Value* new_v = extractLoadValue(ptr, &*it, chain); - if (new_v == NULL) { - ++it; - continue; - } - - assert(new_v); - if (VERBOSITY("opt") >= 1) errs() << "Remapped to: " << *new_v << '\n'; - li->replaceAllUsesWith(new_v); - li->eraseFromParent(); - return; - } - - std::unordered_map seen; - Value* new_v = getLoadValFromPrevious(li->getPointerOperand(), li->getParent(), seen, chain); - assert(new_v); - if (VERBOSITY("opt") >= 1) errs() << "Remapped to: " << *new_v << '\n'; - li->replaceAllUsesWith(new_v); - li->eraseFromParent(); - } - - public: - static char ID; - DeadAllocsPass() : FunctionPass(ID) {} - - virtual void getAnalysisUsage(AnalysisUsage &info) const { - info.setPreservesCFG(); - info.addRequiredTransitive(); - info.addRequiredTransitive(); - } - - virtual bool runOnFunction(Function &F) { - int num_changed = 0; - - StatCounter sc_numchains("opt_dead_chains"); - StatCounter sc_numdeleted("opt_dead_insts"); - StatCounter sc_numremapped("opt_dead_remappedloads"); - - std::vector dead_chains; - for (inst_iterator inst_it = inst_begin(F), _inst_end = inst_end(F); inst_it != _inst_end; ++inst_it) { - if (!isAllocCall(dyn_cast(&*inst_it))) - continue; - - if (VERBOSITY("opt") >= 2) { - errs() << "\nFound alloc:\n" << *inst_it << '\n'; - } - - ChainInfo chain; - bool escapes = canBeRead(&*inst_it, chain); - if (escapes) - continue; - - if (VERBOSITY("opt") >= 1) { - errs() << "\nFound dead alloc:" << *inst_it << '\n'; - errs() << "Taking along with it:\n"; - for (auto I : chain.deletions) { - errs() << *I << '\n'; - } - errs() << "\nLoads that need to be remapped:\n"; - for (auto I : chain.loads) { - errs() << *I << '\n'; - } - } - - // TODO: bad, lots of copying - dead_chains.push_back(chain); - sc_numchains.log(); - - } - - //dumpPrettyIR(&F); - //int i = 0; - for (auto chain : dead_chains) { - sc_numremapped.log(chain.loads.size()); - for (LoadInst* L : chain.loads) { - remapLoad(L, chain); - } - - sc_numdeleted.log(chain.deletions.size()); - for (auto I : chain.deletions) { - I->eraseFromParent(); - } - } - - return num_changed > 0; - } -}; -char DeadAllocsPass::ID = 0; - -FunctionPass* createDeadAllocsPass() { - return new DeadAllocsPass(); -} - -} - -static RegisterPass X("dead_allocs", "Kill allocations that don't escape", true, false); - diff --git a/src/codegen/opt/escape_analysis.cpp b/src/codegen/opt/escape_analysis.cpp deleted file mode 100644 index caf58f121..000000000 --- a/src/codegen/opt/escape_analysis.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/PostDominators.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" - -#include "codegen/opt/escape_analysis.h" -#include "codegen/opt/util.h" - -using namespace llvm; - -namespace pyston { - -EscapeAnalysis::~EscapeAnalysis() { - for (ChainInfo *chain : chains) { - delete chain; - } -} - -void EscapeAnalysis::getAnalysisUsage(llvm::AnalysisUsage &info) const { - info.setPreservesCFG(); - info.addRequiredTransitive(); -} - -bool EscapeAnalysis::runOnFunction(Function &F) { - if (VERBOSITY("opt") >= 1) outs() << "Running escape analysis on " << F.getName() << '\n'; - - for (inst_iterator inst_it = inst_begin(F), _inst_end = inst_end(F); inst_it != _inst_end; ++inst_it) { - CallInst *alloc = dyn_cast(&*inst_it); - if (!alloc || !isAllocCall(alloc)) - continue; - - ChainInfo *chain = new ChainInfo(alloc); - chains.push_back(chain); - - // Calculating derived pointers, and finding escape points - { - // Instructions in the queue to be visited: - std::deque queue; - // Instructions we've fully visited: - std::unordered_set checked; - - queue.push_back(alloc); - - while (queue.size()) { - Instruction* next = queue.back(); - queue.pop_back(); - - if (checked.count(next)) - continue; - - checked.insert(next); - - for (Value::use_iterator use_it = next->use_begin(), use_end = next->use_end(); use_it != use_end; ++use_it) { - if (GetElementPtrInst *gep = dyn_cast(*use_it)) { - queue.push_back(gep); - chain->derived.insert(gep); - chain_by_pointer[gep] = chain; - continue; - } - - if (CastInst *bc = dyn_cast(*use_it)) { - queue.push_back(bc); - chain->derived.insert(bc); - chain_by_pointer[bc] = chain; - continue; - } - - if (PHINode *phi = dyn_cast(*use_it)) { - queue.push_back(phi); - chain->derived.insert(phi); - chain_by_pointer[phi] = chain; - continue; - } - - if (isa(*use_it)) { - continue; - } - - if (ReturnInst *ret = dyn_cast(*use_it)) { - if (VERBOSITY() >= 2) errs() << "Not dead; used here: " << *ret << '\n'; - chain->escape_points.insert(ret); - continue; - } - - - - - - - if (StoreInst *si = dyn_cast(*use_it)) { - if (si->getPointerOperand() == next) { - } else { - assert(si->getValueOperand() == next); - if (VERBOSITY() >= 2) errs() << "Escapes here: " << *si << '\n'; - chain->escape_points.insert(si); - } - continue; - } - - if (CallInst *si = dyn_cast(*use_it)) { - if (VERBOSITY() >= 2) errs() << "Escapes here: " << *si << '\n'; - chain->escape_points.insert(si); - continue; - } - - - - use_it->dump(); - RELEASE_ASSERT(0, ""); - } - } - } - - // Calculating BB-level escape-ness - { - std::deque queue; - - for (auto I : chain->escape_points) { - chain->bb_escapes[I->getParent()] = BBPartialEscape; - queue.insert(queue.end(), succ_begin(I->getParent()), succ_end(I->getParent())); - } - - while (queue.size()) { - const BasicBlock* bb = queue.back(); - queue.pop_back(); - - if (chain->bb_escapes[bb] == BBFullEscape) - continue; - - chain->bb_escapes[bb] = BBFullEscape; - queue.insert(queue.end(), succ_begin(bb), succ_end(bb)); - } - - for (BasicBlock &bb : F) { - if (chain->bb_escapes.count(&bb) == 0) - chain->bb_escapes[&bb] = BBNoEscape; - - //outs() << bb.getName() << ' ' << chain->bb_escapes[&bb] << '\n'; - } - } - } - - - return false; -} - -EscapeAnalysis::EscapeResult EscapeAnalysis::escapes(const Value* ptr, const Instruction *at_instruction) { - assert(ptr); - assert(at_instruction); - - if (chain_by_pointer.count(ptr) == 0) - return Escaped; - - ChainInfo *chain = chain_by_pointer[ptr]; - assert(chain); - - if (chain->escape_points.size() == 0) { - //ptr->dump(); - return NoEscape; - } - - BBEscape bb_escape = chain->bb_escapes[at_instruction->getParent()]; - if (bb_escape == BBNoEscape) - return WillEscape; - if (bb_escape == BBFullEscape) - return Escaped; - - // This pointer escapes at some point in this bb. - // If the at_instruction occurs before any of the escape points, then we're fine. - assert(bb_escape == BBPartialEscape); - for (const Instruction &I : *at_instruction->getParent()) { - if (chain->escape_points.count(&I)) - return Escaped; - if (&I == at_instruction) - return WillEscape; - } - - RELEASE_ASSERT(0, ""); -} - - - -char EscapeAnalysis::ID = 0; -static RegisterPass X("escape_analysis", "Escape analysis", false, true); - -FunctionPass* createEscapeAnalysisPass() { - return new EscapeAnalysis(); -} - -} - diff --git a/src/codegen/opt/escape_analysis.h b/src/codegen/opt/escape_analysis.h deleted file mode 100644 index d3a824695..000000000 --- a/src/codegen/opt/escape_analysis.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_OPT_ESCAPEANALYSIS_H -#define PYSTON_CODEGEN_OPT_ESCAPEANALYSIS_H - -#include "llvm/Pass.h" - -namespace pyston { - -class EscapeAnalysis : public llvm::FunctionPass { - private: - enum BBEscape { - BBNoEscape, // at all points in this bb, the pointer hasn't escaped - BBPartialEscape, // at some points it hasn't escaped, but at some it has - BBFullEscape, // at all points in this bb, the pointer has escaped - }; - - struct ChainInfo { - llvm::Value* allocation; - - std::unordered_set derived; - - std::unordered_set escape_points; - - //// Instructions that are free to be deleted if the chain is dead: - //std::vector deletions; - //// Loads that have to be remapped if the chain is dead: - //std::vector loads; - - std::unordered_map bb_escapes; - - ChainInfo(llvm::Value* alloc) : allocation(alloc) {} - }; - std::vector chains; - std::unordered_map chain_by_pointer; - - public: - static char ID; - EscapeAnalysis() : llvm::FunctionPass(ID) {} - ~EscapeAnalysis(); - - void getAnalysisUsage(llvm::AnalysisUsage &info) const override; - bool runOnFunction(llvm::Function &F) override; - - enum EscapeResult { - // This pointer has already escaped, so arbitrary code could be modifying it - Escaped, - // This point has not escaped, but will escape later; non-local code can't modify it, - // but might read it later - WillEscape, - // This pointer never escapes. - NoEscape, - }; - - EscapeResult escapes(const llvm::Value* ptr, const llvm::Instruction *at_instruction); -}; - -} - - -#endif diff --git a/src/codegen/opt/inliner.cpp b/src/codegen/opt/inliner.cpp deleted file mode 100644 index b3251e95f..000000000 --- a/src/codegen/opt/inliner.cpp +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -#include "llvm/PassManager.h" -#include "llvm/Analysis/InlineCost.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/ValueMapper.h" - -#include "core/options.h" -#include "core/stats.h" - -#include "core/util.h" - -#include "codegen/codegen.h" -#include "codegen/opt/inliner.h" - -//#undef VERBOSITY -//#define VERBOSITY(x) 2 - -namespace pyston { - -class MyMaterializer : public llvm::ValueMaterializer { - private: - llvm::Module *new_module; - public: - MyMaterializer(llvm::Module* new_module) : new_module(new_module) { - } - virtual llvm::Value* materializeValueFor(llvm::Value* v) { - //llvm::errs() << "materializing\n"; - //v->dump(); - - llvm::Value *r = NULL; - if (llvm::Function *f = llvm::dyn_cast(v)) { - //llvm::errs() << "is function\n"; - r = new_module->getOrInsertFunction(f->getName(), f->getFunctionType()); - } else if (llvm::GlobalVariable *gv = llvm::dyn_cast(v)) { - //llvm::errs() << " is gv\n"; - assert(gv->getLinkage() != llvm::GlobalVariable::PrivateLinkage); - r = new_module->getOrInsertGlobal(gv->getName(), gv->getType()->getElementType()); - } else if (llvm::LoadInst *load = llvm::dyn_cast(v)) { - //llvm::errs() << " is LoadInst\n"; - //load->getPointerOperand()->dump(); - llvm::GlobalVariable *gv = llvm::dyn_cast(load->getPointerOperand()); - r = v; - } else if (llvm::GlobalAlias *alias = llvm::dyn_cast(v)) { - llvm::Value* addressee = llvm::cast(materializeValueFor(alias->getAliasedGlobal())); - assert(addressee); - assert(alias->getType() == addressee->getType()); - r = addressee; - //r = new llvm::GlobalAlias(alias->getType(), alias->getLinkage(), alias->getName(), addressee, new_module); - } else if (llvm::isa(v)) { - //llvm::errs() << " is a constant\n"; - r = NULL; - } else { - r = v; - } - - //if (r) - //r->dump(); - //llvm::errs() << "---\n"; - return r; - } -}; - -class MyInliningPass : public llvm::FunctionPass { - public: - static char ID; - static bool initialized; - static llvm::Module *fake_module; - - int threshold; - MyInliningPass(int threshold=275) : FunctionPass(ID), threshold(threshold) {} - - static void initialize() { - if (!initialized) { - llvm::initializeInlineCostAnalysisPass(*llvm::PassRegistry::getPassRegistry()); - llvm::initializeSimpleInlinerPass(*llvm::PassRegistry::getPassRegistry()); - llvm::initializeTargetTransformInfoAnalysisGroup(*llvm::PassRegistry::getPassRegistry()); - - fake_module = new llvm::Module("fake", g.context); - - initialized = true; - } - } - - virtual const char* getPassName() const { - return "Pyston inlining pass"; - } - - bool _runOnFunction(llvm::Function &f) { - Timer _t2("(sum)"); - Timer _t("initializing"); - initialize(); - _t.split("overhead"); - - //f.dump(); - - llvm::Module* cur_module = f.getParent(); - - llvm::PassManager fake_pm; - llvm::InlineCostAnalysis* cost_analysis = new llvm::InlineCostAnalysis(); - fake_pm.add(cost_analysis); - //llvm::errs() << "doing fake run\n"; - fake_pm.run(*fake_module); - //llvm::errs() << "done with fake run\n"; - - bool did_any_inlining = false; - - // TODO I haven't gotten the callgraph-updating part of the inliner to work, - // so it's not easy to tell what callsites have been inlined into (ie added to) - // the function. - // One simple-but-not-great way to handle it is to just iterate over the entire function - // multiple times and re-inline things until we don't want to inline any more; - // NPASSES controls the maximum number of times to attempt that. - // Right now we actually don't need that, since we only inline fully-optimized - // functions (from the stdlib), and those will already have had inlining - // applied recursively. - const int NPASSES = 1; - for (int passnum = 0; passnum < NPASSES; passnum++) { - _t.split("collecting calls"); - - std::vector calls; - for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) { - llvm::CallInst* call = llvm::dyn_cast(&(*I)); - // From Inliner.cpp: - if (!call || llvm::isa(call)) - continue; - //I->dump(); - llvm::CallSite CS(call); - - llvm::Value *v = CS.getCalledValue(); - llvm::ConstantExpr *ce = llvm::dyn_cast(v); - if (!ce) - continue; - - assert(ce->isCast()); - llvm::ConstantInt *l_addr = llvm::cast(ce->getOperand(0)); - int64_t addr = l_addr->getSExtValue(); - - if (addr == (int64_t)printf) - continue; - llvm::Function *f = g.func_addr_registry.getLLVMFuncAtAddress((void*)addr); - if (f == NULL) { - if (VERBOSITY()) { - printf("Giving up on inlining %s:\n", g.func_addr_registry.getFuncNameAtAddress((void*)addr, true).c_str()); - call->dump(); - } - continue; - } - - // We load the bitcode lazily, so check if we haven't yet fully loaded the function: - if (f->isMaterializable()) - f->Materialize(); - - // It could still be a declaration, though I think the code won't generate this case any more: - if (f->isDeclaration()) - continue; - - // Keep this section as a release_assert since the code-to-be-inlined, as well as the inlining - // decisions, can be different in release mode: - int op_idx = 0; - for (llvm::Function::arg_iterator it = f->arg_begin(), end = f->arg_end(); it != end; ++it, ++op_idx) { - llvm::Type* op_type =call->getOperand(op_idx)->getType(); - if (it->getType() != op_type) { - llvm::errs() << f->getName() << " has arg " << op_idx << " mismatched!\n"; - llvm::errs() << "Given "; - op_type->dump(); - llvm::errs() << " but underlying function expected "; - it->getType()->dump(); - llvm::errs() << '\n'; - } - RELEASE_ASSERT(it->getType() == call->getOperand(op_idx)->getType(), ""); - } - - assert(!f->isDeclaration()); - CS.setCalledFunction(f); - calls.push_back(CS); - } - - //assert(0 && "TODO"); - //printf("%ld\n", calls.size()); - - bool did_inline = false; - _t.split("doing inlining"); - while (calls.size()) { - llvm::CallSite cs = calls.back(); - calls.pop_back(); - - //if (VERBOSITY("irgen.inlining") >= 1) { - //llvm::errs() << "Evaluating callsite "; - //cs->dump(); - //} - llvm::InlineCost IC = cost_analysis->getInlineCost(cs, threshold); - bool do_inline = false; - if (IC.isAlways()) { - if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "always inline\n"; - do_inline = true; - } else if (IC.isNever()) { - if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "never inline\n"; - do_inline = false; - } else { - if (VERBOSITY("irgen.inlining") >= 2) llvm::errs() << "Inline cost: " << IC.getCost() << '\n'; - do_inline = (bool)IC; - } - - if (VERBOSITY("irgen.inlining") >= 1) { - if (!do_inline) - llvm::outs() << "not "; - llvm::outs() << "inlining "; - cs->dump(); - } - - if (do_inline) { - static StatCounter num_inlines("num_inlines"); - num_inlines.log(); - - //llvm::CallGraph cg(*f.getParent()); - ////cg.addToCallGraph(cs->getCalledFunction()); - //llvm::InlineFunctionInfo InlineInfo(&cg); - - llvm::InlineFunctionInfo InlineInfo; - bool inlined = llvm::InlineFunction(cs, InlineInfo, false); - did_inline = did_inline || inlined; - did_any_inlining = did_any_inlining || inlined; - - //if (inlined) - //f.dump(); - } - } - - if (!did_inline) { - if (passnum >= NPASSES - 1 && VERBOSITY("irgen.inlining")) - printf("quitting after %d passes\n", passnum + 1); - break; - } - } - - // TODO would be nice to break out here and not have to rematerialize the function; - // I think I have to do that even if no inlining happened from the "setCalledFunction" call above. - // I thought that'd just change the CS object, but maybe it changes the underlying instruction as well? - //if (!did_any_inlining) - //return false; - - _t.split("remapping"); - - llvm::ValueToValueMapTy VMap; - for (llvm::Function::iterator I = f.begin(), E = f.end(); I != E; ++I) { - VMap[I] = I; - } - MyMaterializer materializer(cur_module); - for (llvm::inst_iterator I = llvm::inst_begin(f), E = llvm::inst_end(f); I != E; ++I) { - RemapInstruction(&(*I), VMap, llvm::RF_None, NULL, &materializer); - } - - _t.split("cleaning up"); - - std::vector to_remove; - for (llvm::Module::global_iterator I = cur_module->global_begin(), E = cur_module->global_end(); I != E; ++I) { - if (I->use_empty()) { - to_remove.push_back(I); - continue; - } - } - - for (int i = 0 ; i < to_remove.size(); i++) { - to_remove[i]->eraseFromParent(); - } - - for (llvm::Module::iterator I = cur_module->begin(), E = cur_module->end(); I != E; ) { - if (!I->isDeclaration()) { - ++I; - continue; - } - - if (I->use_empty()) { - I = cur_module->getFunctionList().erase(I); - } else { - ++I; - } - } - - return did_any_inlining; - } - - virtual bool runOnFunction(llvm::Function &f) { - Timer _t("inlining"); - - bool rtn = _runOnFunction(f); - - static StatCounter us_inlining("us_compiling_optimizing_inlining"); - long us = _t.end(); - us_inlining.log(us); - - return rtn; - } -}; -char MyInliningPass::ID = 0; -bool MyInliningPass::initialized = false; -llvm::Module* MyInliningPass::fake_module = 0; -static llvm::RegisterPass X("myinliner", "Function-level inliner", false, false); - -llvm::FunctionPass *makeFPInliner(int threshold) { - return new MyInliningPass(threshold); -} - -} diff --git a/src/codegen/opt/inliner.h b/src/codegen/opt/inliner.h deleted file mode 100644 index e05c4681b..000000000 --- a/src/codegen/opt/inliner.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_OPT_INLINER_H -#define PYSTON_CODEGEN_OPT_INLINER_H - -namespace llvm { -class FunctionPass; -} -namespace pyston { -llvm::FunctionPass* makeFPInliner(int threshold); -} - -#endif diff --git a/src/codegen/opt/mallocs_nonnull.cpp b/src/codegen/opt/mallocs_nonnull.cpp deleted file mode 100644 index 58ceb0869..000000000 --- a/src/codegen/opt/mallocs_nonnull.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/PostDominators.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Support/raw_ostream.h" - -#include "core/common.h" -#include "core/options.h" - -using namespace llvm; - -namespace pyston { - -// TODO Copy-paste -static bool isMallocCall(const CallInst *CI) { - if (!CI) - return false; - - Function *Callee = CI->getCalledFunction(); - if (Callee == 0 || !Callee->isDeclaration()) - return false; - if (Callee->getName() != "malloc" /*&& - Callee->getName() != "my_malloc" && - Callee->getName() != "_Znwj" && // operator new(unsigned int) - Callee->getName() != "_Znwm" && // operator new(unsigned long) - Callee->getName() != "_Znaj" && // operator new[](unsigned int) - Callee->getName() != "_Znam"*/) // operator new[](unsigned long) - return false; - - // Check malloc prototype. - // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin - // attribute will exist. - FunctionType *FTy = Callee->getFunctionType(); - return FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && - FTy->getNumParams() == 1 && - (FTy->getParamType(0)->isIntegerTy(32) || - FTy->getParamType(0)->isIntegerTy(64)); -} - -/// isFreeCall - Returns non-null if the value is a call to the builtin free() -static const CallInst *isFreeCall(const Value *I) { - const CallInst *CI = dyn_cast(I); - if (!CI) - return 0; - Function *Callee = CI->getCalledFunction(); - if (Callee == 0 || !Callee->isDeclaration()) - return 0; - - if (Callee->getName() != "free" /*&& - Callee->getName() != "my_free" && - Callee->getName() != "_ZdlPv" && // operator delete(void*) - Callee->getName() != "_ZdaPv"*/) // operator delete[](void*) - return 0; - - // Check free prototype. - // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin - // attribute will exist. - FunctionType *FTy = Callee->getFunctionType(); - if (!FTy->getReturnType()->isVoidTy()) - return 0; - if (FTy->getNumParams() != 1) - return 0; - if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) - return 0; - - return CI; -} - -class ComparisonFinder : public InstVisitor { -private: - bool any_changes; - std::deque to_process; - Instruction* processing; - -public: - ComparisonFinder(CallInst* malloc) : any_changes(false) { - to_process.push_back(malloc); - } - - bool elide_comparisons() { - while (to_process.size()) { - processing = to_process.front(); - to_process.pop_front(); - - //errs() << "processing: " << *processing << '\n'; - bool changed = false; - do { - changed = false; - for (Value::use_iterator use_it = processing->use_begin(), use_end = processing->use_end(); use_it != use_end; ++use_it) { - //errs() << "looking at: " << **use_it << '\n'; - changed = visit(cast(*use_it)); - if (changed) - break; - } - } while (changed); - } - return any_changes; - } - - bool visitBitCastInst(BitCastInst &inst) { - to_process.push_back(&inst); - return false; - } - - bool visitICmpInst(ICmpInst &inst) { - //errs() << "got icmp instruction! " << inst << '\n'; - - bool changed = false; - if (inst.getPredicate() == CmpInst::ICMP_EQ) { - assert(inst.getNumOperands() == 2); - - if (inst.getOperand(1) == processing) { - inst.swapOperands(); - changed = true; - any_changes = true; - } - assert(dyn_cast(inst.getOperand(0)) == processing); - Value* other = inst.getOperand(1); - if (isa(other)) { - if (VERBOSITY("opt") >= 2) { - errs() << inst << '\n'; - errs() << "replacing with false!\n"; - } - - Value* new_value = ConstantInt::getFalse(other->getContext()); - inst.replaceAllUsesWith(new_value); - inst.eraseFromParent(); - changed = true; - any_changes = true; - } - } - return changed; - } - - bool visitInstruction(Instruction &inst) { - //errs() << "got misc instruction: " << inst << '\n'; - return false; - } -}; - -class MallocsNonNullPass : public FunctionPass { - public: - static char ID; - MallocsNonNullPass() : FunctionPass(ID) {} - - virtual void getAnalysisUsage(AnalysisUsage &info) const { - info.setPreservesCFG(); - } - - virtual bool runOnFunction(Function &F) { - int num_changed = 0; - for (inst_iterator inst_it = inst_begin(F), _inst_end = inst_end(F); inst_it != _inst_end; ++inst_it) { - if (!isMallocCall(dyn_cast(&*inst_it))) - continue; - - if (VERBOSITY("opt") >= 2) { - errs() << "\nFound malloc call:\n" << *inst_it << '\n'; - } - num_changed += ComparisonFinder(cast(&*inst_it)).elide_comparisons(); - } - - return num_changed > 0; - } -}; -char MallocsNonNullPass::ID = 0; - -FunctionPass* createMallocsNonNullPass() { - return new MallocsNonNullPass(); -} - -} - -static RegisterPass X("mallocs_nonnull", "Use the fact that malloc() doesnt return NULL", true, false); - - - diff --git a/src/codegen/opt/passes.h b/src/codegen/opt/passes.h deleted file mode 100644 index b3309a83e..000000000 --- a/src/codegen/opt/passes.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_OPT_PASSES_H -#define PYSTON_CODEGEN_OPT_PASSES_H - -namespace llvm { -class FunctionPass; -class ImmutablePass; -} - -namespace pyston { -llvm::ImmutablePass* createPystonAAPass(); -llvm::FunctionPass* createMallocsNonNullPass(); -llvm::FunctionPass* createConstClassesPass(); -llvm::FunctionPass* createDeadAllocsPass(); -} - -#endif diff --git a/src/codegen/opt/util.cpp b/src/codegen/opt/util.cpp deleted file mode 100644 index 6c72b8810..000000000 --- a/src/codegen/opt/util.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "llvm/IR/Function.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instructions.h" - -#include "codegen/opt/util.h" - -namespace pyston { - -bool isAllocCall(const std::string &name) { - if (name == "malloc") - return true; - - if (name == "_ZN6pyston2gc4Heap10allocSmallEmPPNS0_5BlockES4_") - return true; - - return false; -} - -bool isAllocCall(const llvm::CallInst *CI) { - if (!CI) - return false; - - llvm::Function *Callee = CI->getCalledFunction(); - if (Callee == 0 || !Callee->isDeclaration()) - return false; - - return isAllocCall(Callee->getName()); -} - -} diff --git a/src/codegen/opt/util.h b/src/codegen/opt/util.h deleted file mode 100644 index 4720d2ecb..000000000 --- a/src/codegen/opt/util.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_OPT_UTIL_H -#define PYSTON_CODEGEN_OPT_UTIL_H - -#include - -namespace pyston { - -bool isAllocCall(const std::string &name); -bool isAllocCall(const llvm::CallInst *CI); - -} - -#endif diff --git a/src/codegen/osrentry.h b/src/codegen/osrentry.h deleted file mode 100644 index 715489def..000000000 --- a/src/codegen/osrentry.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_OSRENTRY_H -#define PYSTON_CODEGEN_OSRENTRY_H - -#include - -namespace llvm { -class Function; -} - - -namespace pyston { - -class StackMap; - -class OSREntryDescriptor { - private: - OSREntryDescriptor(CompiledFunction *from_cf, AST_Jump *backedge) : cf(from_cf), backedge(backedge) { - } - public: - CompiledFunction *const cf; - AST_Jump* const backedge; - typedef std::map ArgMap; - ArgMap args; - - static OSREntryDescriptor* create(CompiledFunction *from_cf, AST_Jump* backedge) { - return new OSREntryDescriptor(from_cf, backedge); - } -}; - -class OSRExit { - private: - public: - CompiledFunction * const parent_cf; - OSREntryDescriptor *entry; - - OSRExit(CompiledFunction *parent_cf, OSREntryDescriptor *entry) : parent_cf(parent_cf), entry(entry) { - } -}; - - -} - -#endif diff --git a/src/codegen/parse_ast.py b/src/codegen/parse_ast.py deleted file mode 100644 index a72975078..000000000 --- a/src/codegen/parse_ast.py +++ /dev/null @@ -1,164 +0,0 @@ -import _ast -import struct -import sys -from types import NoneType - -def _print_str(s, f): - assert len(s) < 2**16 - f.write(struct.pack(">H", len(s))) - f.write(s) - -TYPE_MAP = { - _ast.alias: 1, - _ast.arguments: 2, - _ast.Assert: 3, - _ast.Assign: 4, - _ast.Attribute: 5, - _ast.AugAssign: 6, - _ast.BinOp: 7, - _ast.BoolOp: 8, - _ast.Call: 9, - _ast.ClassDef: 10, - _ast.Compare: 11, - _ast.comprehension: 12, - _ast.Delete: 13, - _ast.Dict: 14, - _ast.Exec: 16, - _ast.ExceptHandler: 17, - _ast.ExtSlice: 18, - _ast.Expr: 19, - _ast.For: 20, - _ast.FunctionDef: 21, - _ast.GeneratorExp: 22, - _ast.Global: 23, - _ast.If: 24, - _ast.IfExp: 25, - _ast.Import: 26, - _ast.ImportFrom: 27, - _ast.Index: 28, - _ast.keyword: 29, - _ast.Lambda: 30, - _ast.List: 31, - _ast.ListComp: 32, - _ast.Module: 33, - _ast.Num: 34, - _ast.Name: 35, - _ast.Pass: 37, - _ast.Pow: 38, - _ast.Print: 39, - _ast.Raise: 40, - _ast.Repr: 41, - _ast.Return: 42, - _ast.Slice: 44, - _ast.Str: 45, - _ast.Subscript: 46, - _ast.TryExcept: 47, - _ast.TryFinally: 48, - _ast.Tuple: 49, - _ast.UnaryOp: 50, - _ast.With: 51, - _ast.While: 52, - _ast.Yield: 53, - - _ast.Store: 54, - _ast.Load: 55, - _ast.Param: 56, - _ast.Not: 57, - _ast.In: 58, - _ast.Is: 59, - _ast.IsNot: 60, - _ast.Or: 61, - _ast.And: 62, - _ast.Eq: 63, - _ast.NotEq: 64, - _ast.NotIn: 65, - _ast.GtE: 66, - _ast.Gt: 67, - _ast.Mod: 68, - _ast.Add: 69, - _ast.Continue: 70, - _ast.Lt: 71, - _ast.LtE: 72, - _ast.Break: 73, - _ast.Sub: 74, - _ast.Del: 75, - _ast.Mult: 76, - _ast.Div: 77, - _ast.USub: 78, - _ast.BitAnd: 79, - _ast.BitOr: 80, - _ast.BitXor: 81, - _ast.RShift: 82, - _ast.LShift: 83, - _ast.Invert: 84, - _ast.UAdd: 85, - _ast.FloorDiv: 86, - } - -if sys.version_info >= (2,7): - TYPE_MAP[_ast.DictComp] = 15 - TYPE_MAP[_ast.Set] = 43 - -def convert(n, f): - assert n is None or isinstance(n, _ast.AST), repr(n) - type_idx = TYPE_MAP[type(n)] if n else 0 - f.write(struct.pack(">B", type_idx)) - if n is None: - return - if isinstance(n, (_ast.operator, _ast.expr_context, _ast.boolop, _ast.cmpop, _ast.unaryop)): - return - - f.write('\xae') - - if isinstance(n, _ast.Num): - if isinstance(n.n, int): - f.write('\x10') - elif isinstance(n.n, float): - f.write('\x20') - else: - raise Exception(type(n.n)) - - # print n, sorted(n.__dict__.items()) - for k, v in sorted(n.__dict__.items()): - if k.startswith('_'): - continue - - if k == "vararg" and v is None: - v = "" - if k == "asname" and v is None: - v = "" - # elif k in ('col_offset', 'lineno'): - # continue - - if isinstance(v, list): - assert len(v) < 2**16 - f.write(struct.pack(">H", len(v))) - if isinstance(n, _ast.Global): - assert k == "names" - for el in v: - _print_str(el, f) - else: - for el in v: - convert(el, f) - elif isinstance(v, str): - _print_str(v, f) - elif isinstance(v, bool): - f.write(struct.pack("B", v)) - elif isinstance(v, int): - f.write(struct.pack(">q", v)) - elif isinstance(v, float): - f.write(struct.pack(">d", v)) - elif v is None or isinstance(v, _ast.AST): - convert(v, f) - else: - raise Exception((n, k, repr(v))) - -if __name__ == "__main__": - import time - start = time.time() - fn = sys.argv[1] - s = open(fn).read() - m = compile(s, fn, "exec", _ast.PyCF_ONLY_AST) - - convert(m, sys.stdout) - diff --git a/src/codegen/parser.cpp b/src/codegen/parser.cpp deleted file mode 100644 index 4c0a2e015..000000000 --- a/src/codegen/parser.cpp +++ /dev/null @@ -1,784 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "core/ast.h" -#include "core/util.h" - -//#undef VERBOSITY -//#define VERBOSITY(x) 2 - -namespace pyston { - -class BufferedReader { - private: - static const int BUFSIZE = 1024; - char buf[BUFSIZE]; - int start, end; - FILE *fp; - - void ensure(int num) { - if (end - start < num) { - fill(); - } - } - - public: - void fill() { - memmove(buf, buf+start, end-start); - end -= start; - start = 0; - end += fread(buf + end, 1, BUFSIZE - end, fp); - if (VERBOSITY("parsing") >= 2) - printf("filled, now at %d-%d\n", start, end); - } - - BufferedReader(FILE* fp) : start(0), end(0), fp(fp) { - } - - int bytesBuffered() { - return (end - start); - } - - uint8_t readByte() { - ensure(1); - assert(end > start); - if (VERBOSITY("parsing") >= 2) - printf("readByte, now %d %d\n", start+1, end); - return buf[start++]; - } - uint16_t readShort() { - return (readByte() << 8) | (readByte()); - } - uint32_t readUInt() { - return (readShort() << 16) | (readShort()); - } - uint64_t readULL() { - return ((uint64_t)readUInt() << 32) | (readUInt()); - } - double readDouble() { - union { - uint64_t raw; - double d; - }; - raw = readULL(); - return d; - } -}; - -AST* readASTMisc(BufferedReader *reader); -AST_expr* readASTExpr(BufferedReader *reader); -AST_stmt* readASTStmt(BufferedReader *reader); - -static std::string readString(BufferedReader *reader) { - int strlen = reader->readShort(); - std::vector chars; - for (int i = 0; i < strlen; i++) { - chars.push_back(reader->readByte()); - } - return std::string(chars.begin(), chars.end()); -} - -static void readStringVector(std::vector &vec, BufferedReader *reader) { - int num_elts = reader->readShort(); - if (VERBOSITY("parsing") >= 2) - printf("%d elts to read\n", num_elts); - for (int i = 0; i < num_elts; i++) { - vec.push_back(readString(reader)); - } -} - -static void readStmtVector(std::vector &vec, BufferedReader *reader) { - int num_elts = reader->readShort(); - if (VERBOSITY("parsing") >= 2) - printf("%d elts to read\n", num_elts); - for (int i = 0; i < num_elts; i++) { - vec.push_back(readASTStmt(reader)); - } -} - -static void readExprVector(std::vector &vec, BufferedReader *reader) { - int num_elts = reader->readShort(); - if (VERBOSITY("parsing") >= 2) - printf("%d elts to read\n", num_elts); - for (int i = 0; i < num_elts; i++) { - vec.push_back(readASTExpr(reader)); - } -} - -static void readMiscVector(std::vector &vec, BufferedReader *reader) { - int num_elts = reader->readShort(); - if (VERBOSITY("parsing") >= 2) - printf("%d elts to read\n", num_elts); - for (int i = 0; i < num_elts; i++) { - vec.push_back(readASTMisc(reader)); - } -} - -static int readColOffset(BufferedReader *reader) { - int rtn = reader->readULL(); - // offsets out of this range are almost certainly parse bugs: - ASSERT(rtn >= 0 && rtn < 100000, "%d", rtn); - return rtn; -} - -AST_alias* read_alias(BufferedReader *reader) { - AST_alias *rtn = new AST_alias(); - - rtn->asname = readString(reader); - rtn->col_offset = -1; - rtn->lineno = -1; - rtn->name = readString(reader); - - return rtn; -} - -AST_arguments* read_arguments(BufferedReader *reader) { - if (VERBOSITY("parsing") >= 2) - printf("reading arguments\n"); - AST_arguments *rtn = new AST_arguments(); - - readExprVector(rtn->args, reader); - rtn->col_offset = -1; - readExprVector(rtn->defaults, reader); - rtn->kwarg = readASTExpr(reader); - rtn->lineno = -1; - //rtn->vararg = readASTExpr(reader); - rtn->vararg = readString(reader); - return rtn; -} - -AST_Assign* read_assign(BufferedReader *reader) { - AST_Assign *rtn = new AST_Assign(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - readExprVector(rtn->targets, reader); - rtn->value = readASTExpr(reader); - return rtn; -} - -AST_Attribute* read_attribute(BufferedReader *reader) { - AST_Attribute *rtn = new AST_Attribute(); - - rtn->attr = readString(reader); - rtn->col_offset = readColOffset(reader); - rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte(); - rtn->lineno = reader->readULL(); - rtn->value = readASTExpr(reader); - return rtn; -} - -AST_expr* read_binop(BufferedReader *reader) { - AST_BinOp *rtn = new AST_BinOp(); - - rtn->col_offset = readColOffset(reader); - rtn->left = readASTExpr(reader); - rtn->lineno = reader->readULL(); - rtn->op_type = (AST_TYPE::AST_TYPE)reader->readByte(); - rtn->right = readASTExpr(reader); - - return rtn; -} - -AST_expr* read_boolop(BufferedReader *reader) { - AST_BoolOp *rtn = new AST_BoolOp(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - rtn->op_type = (AST_TYPE::AST_TYPE)reader->readByte(); - readExprVector(rtn->values, reader); - - return rtn; -} - -AST_Break* read_break(BufferedReader *reader) { - AST_Break *rtn = new AST_Break(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - - return rtn; -} - -AST_Call* read_call(BufferedReader *reader) { - AST_Call *rtn = new AST_Call(); - - readExprVector(rtn->args, reader); - rtn->col_offset = readColOffset(reader); - rtn->func = readASTExpr(reader); - - std::vector keyword_vec; - readMiscVector(keyword_vec, reader); - for (int i = 0; i < keyword_vec.size(); i++) { - assert(keyword_vec[i]->type == AST_TYPE::keyword); - rtn->keywords.push_back(static_cast(keyword_vec[i])); - } - - rtn->kwargs = readASTExpr(reader); - rtn->lineno = reader->readULL(); - rtn->starargs = readASTExpr(reader); - return rtn; -} - -AST_expr* read_compare(BufferedReader *reader) { - AST_Compare *rtn = new AST_Compare(); - - rtn->col_offset = readColOffset(reader); - readExprVector(rtn->comparators, reader); - rtn->left = readASTExpr(reader); - rtn->lineno = reader->readULL(); - - int num_ops = reader->readShort(); - assert(num_ops == rtn->comparators.size()); - for (int i = 0; i < num_ops; i++) { - rtn->ops.push_back((AST_TYPE::AST_TYPE)reader->readByte()); - } - - /*{ - assert(rtn->ops.size() == 1); - AST_Attribute *func = new AST_Attribute(); - func->type = AST_TYPE::Attribute; - func->attr = getOpName(rtn->ops[0]); - func->col_offset = rtn->col_offset; - func->ctx_type = AST_TYPE::Load; - func->lineno = rtn->lineno; - func->value = rtn->left; - - AST_Call *call = new AST_Call(); - call->type = AST_TYPE::Call; - call->args.push_back(rtn->comparators[0]); - call->col_offset = rtn->col_offset; - call->func = func; - call->kwargs = NULL; - call->lineno = rtn->lineno; - call->starargs = NULL; - return call; - }*/ - - return rtn; -} - -AST_ClassDef* read_classdef(BufferedReader *reader) { - AST_ClassDef *rtn = new AST_ClassDef(); - - readExprVector(rtn->bases, reader); - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - readExprVector(rtn->decorator_list, reader); - rtn->lineno = reader->readULL(); - rtn->name = readString(reader); - - return rtn; -} - -AST_Continue* read_continue(BufferedReader *reader) { - AST_Continue *rtn = new AST_Continue(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - - return rtn; -} - -AST_Dict* read_dict(BufferedReader *reader) { - AST_Dict *rtn = new AST_Dict(); - - rtn->col_offset = readColOffset(reader); - readExprVector(rtn->keys, reader); - rtn->lineno = reader->readULL(); - readExprVector(rtn->values, reader); - - assert(rtn->keys.size() == rtn->values.size()); - return rtn; -} - -AST_Expr* read_expr(BufferedReader *reader) { - AST_Expr *rtn = new AST_Expr(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - rtn->value = readASTExpr(reader); - return rtn; -} - -AST_For* read_for(BufferedReader *reader) { - AST_For *rtn = new AST_For(); - - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - rtn->iter = readASTExpr(reader); - rtn->lineno = reader->readULL(); - readStmtVector(rtn->orelse, reader); - rtn->target = readASTExpr(reader); - return rtn; -} - -AST_FunctionDef* read_functiondef(BufferedReader *reader) { - if (VERBOSITY("parsing") >= 2) - printf("reading functiondef\n"); - AST_FunctionDef *rtn = new AST_FunctionDef(); - - rtn->args = static_cast(readASTMisc(reader)); - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - readExprVector(rtn->decorator_list, reader); - rtn->lineno = reader->readULL(); - rtn->name = readString(reader); - return rtn; -} - -AST_Global* read_global(BufferedReader *reader) { - AST_Global *rtn = new AST_Global(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - readStringVector(rtn->names, reader); - return rtn; -} - -AST_If* read_if(BufferedReader *reader) { - AST_If *rtn = new AST_If(); - - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - readStmtVector(rtn->orelse, reader); - rtn->test = readASTExpr(reader); - return rtn; -} - -AST_Import* read_import(BufferedReader *reader) { - AST_Import *rtn = new AST_Import(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - - int num_elts = reader->readShort(); - for (int i = 0; i < num_elts; i++) { - AST* elt = readASTMisc(reader); - assert(elt->type == AST_TYPE::alias); - rtn->names.push_back(static_cast(elt)); - } - return rtn; -} - -AST_Index* read_index(BufferedReader *reader) { - AST_Index *rtn = new AST_Index(); - - rtn->col_offset = -1; - rtn->lineno = -1; - rtn->value = readASTExpr(reader); - assert(rtn->value); - return rtn; -} - -AST_keyword* read_keyword(BufferedReader *reader) { - AST_keyword *rtn = new AST_keyword(); - - rtn->arg = readString(reader); - rtn->col_offset = -1; - rtn->lineno = -1; - rtn->value = readASTExpr(reader); - return rtn; -} - -AST_List* read_list(BufferedReader *reader) { - AST_List *rtn = new AST_List(); - - rtn->col_offset = readColOffset(reader); - rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte(); - readExprVector(rtn->elts, reader); - rtn->lineno = reader->readULL(); - return rtn; -} - -AST_Module* read_module(BufferedReader *reader) { - if (VERBOSITY("parsing") >= 2) - printf("reading module\n"); - AST_Module *rtn = new AST_Module(); - - readStmtVector(rtn->body, reader); - rtn->col_offset = -1; - rtn->lineno = -1; - return rtn; -} - -AST_Name* read_name(BufferedReader *reader) { - AST_Name *rtn = new AST_Name(); - - rtn->col_offset = readColOffset(reader); - rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte(); - rtn->id = readString(reader); - rtn->lineno = reader->readULL(); - return rtn; -} - -AST_Num* read_num(BufferedReader *reader) { - AST_Num *rtn = new AST_Num(); - - rtn->num_type = (AST_Num::NumType)reader->readByte(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - - if (rtn->num_type == AST_Num::INT) { - rtn->n_int = reader->readULL(); // automatic conversion to signed - } else if (rtn->num_type == AST_Num::FLOAT) { - rtn->n_float = reader->readDouble(); - } else { - RELEASE_ASSERT(0, "%d", rtn->num_type); - } - return rtn; -} - -AST_Pass* read_pass(BufferedReader *reader) { - AST_Pass *rtn = new AST_Pass(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - return rtn; -} - -AST_Print* read_print(BufferedReader *reader) { - AST_Print *rtn = new AST_Print(); - - rtn->col_offset = readColOffset(reader); - rtn->dest = readASTExpr(reader); - rtn->lineno = reader->readULL(); - rtn->nl = reader->readByte(); - readExprVector(rtn->values, reader); - return rtn; -} - -AST_Return* read_return(BufferedReader *reader) { - AST_Return *rtn = new AST_Return(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - rtn->value = readASTExpr(reader); - return rtn; -} - -AST_Slice* read_slice(BufferedReader *reader) { - AST_Slice *rtn = new AST_Slice(); - - rtn->col_offset = -1; - rtn->lineno = -1; - rtn->lower = readASTExpr(reader); - rtn->step = readASTExpr(reader); - rtn->upper = readASTExpr(reader); - - return rtn; -} - -AST_Str* read_str(BufferedReader *reader) { - AST_Str *rtn = new AST_Str(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - rtn->s = readString(reader); - - return rtn; -} - -AST_Subscript* read_subscript(BufferedReader *reader) { - AST_Subscript *rtn = new AST_Subscript(); - - rtn->col_offset = readColOffset(reader); - rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte(); - rtn->lineno = reader->readULL(); - rtn->slice = readASTExpr(reader); - rtn->value = readASTExpr(reader); - - return rtn; -} - -AST_Tuple* read_tuple(BufferedReader *reader) { - AST_Tuple *rtn = new AST_Tuple(); - - rtn->col_offset = readColOffset(reader); - rtn->ctx_type = (AST_TYPE::AST_TYPE)reader->readByte(); - readExprVector(rtn->elts, reader); - rtn->lineno = reader->readULL(); - - return rtn; -} - -AST_UnaryOp* read_unaryop(BufferedReader *reader) { - AST_UnaryOp *rtn = new AST_UnaryOp(); - - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - rtn->op_type = (AST_TYPE::AST_TYPE)reader->readByte(); - rtn->operand = readASTExpr(reader); - - return rtn; -} - -AST_While* read_while(BufferedReader *reader) { - AST_While *rtn = new AST_While(); - - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - rtn->lineno = reader->readULL(); - readStmtVector(rtn->orelse, reader); - rtn->test = readASTExpr(reader); - - return rtn; -} - -AST_With* read_with(BufferedReader *reader) { - AST_With *rtn = new AST_With(); - - readStmtVector(rtn->body, reader); - rtn->col_offset = readColOffset(reader); - rtn->context_expr = readASTExpr(reader); - rtn->lineno = reader->readULL(); - rtn->optional_vars = readASTExpr(reader); - - return rtn; -} - -AST_expr* readASTExpr(BufferedReader *reader) { - uint8_t type = reader->readByte(); - if (VERBOSITY("parsing") >= 2) - printf("type = %d\n", type); - if (type == 0) - return NULL; - - uint8_t checkbyte = reader->readByte(); - assert(checkbyte == 0xae); - - switch (type) { - case AST_TYPE::Attribute: - return read_attribute(reader); - case AST_TYPE::BinOp: - return read_binop(reader); - case AST_TYPE::BoolOp: - return read_boolop(reader); - case AST_TYPE::Call: - return read_call(reader); - case AST_TYPE::Compare: - return read_compare(reader); - case AST_TYPE::Dict: - return read_dict(reader); - case AST_TYPE::Index: - return read_index(reader); - case AST_TYPE::List: - return read_list(reader); - case AST_TYPE::Name: - return read_name(reader); - case AST_TYPE::Num: - return read_num(reader); - case AST_TYPE::Slice: - return read_slice(reader); - case AST_TYPE::Str: - return read_str(reader); - case AST_TYPE::Subscript: - return read_subscript(reader); - case AST_TYPE::Tuple: - return read_tuple(reader); - case AST_TYPE::UnaryOp: - return read_unaryop(reader); - default: - fprintf(stderr, "Unknown expr node type (parser.cpp:" STRINGIFY(__LINE__) "): %d\n", type); - abort(); - break; - } -} - -AST_stmt* readASTStmt(BufferedReader *reader) { - uint8_t type = reader->readByte(); - if (VERBOSITY("parsing") >= 2) - printf("type = %d\n", type); - if (type == 0) - return NULL; - - uint8_t checkbyte = reader->readByte(); - assert(checkbyte == 0xae); - - switch (type) { - case AST_TYPE::Assign: - return read_assign(reader); - case AST_TYPE::Break: - return read_break(reader); - case AST_TYPE::ClassDef: - return read_classdef(reader); - case AST_TYPE::Continue: - return read_continue(reader); - case AST_TYPE::Expr: - return read_expr(reader); - case AST_TYPE::For: - return read_for(reader); - case AST_TYPE::FunctionDef: - return read_functiondef(reader); - case AST_TYPE::Global: - return read_global(reader); - case AST_TYPE::If: - return read_if(reader); - case AST_TYPE::Import: - return read_import(reader); - case AST_TYPE::Pass: - return read_pass(reader); - case AST_TYPE::Print: - return read_print(reader); - case AST_TYPE::Return: - return read_return(reader); - case AST_TYPE::While: - return read_while(reader); - case AST_TYPE::With: - return read_with(reader); - default: - fprintf(stderr, "Unknown stmt node type (parser.cpp:" STRINGIFY(__LINE__) "): %d\n", type); - exit(1); - break; - } -} - -AST* readASTMisc(BufferedReader *reader) { - uint8_t type = reader->readByte(); - if (VERBOSITY("parsing") >= 2) - printf("type = %d\n", type); - if (type == 0) - return NULL; - - uint8_t checkbyte = reader->readByte(); - assert(checkbyte == 0xae); - - switch (type) { - case AST_TYPE::alias: - return read_alias(reader); - case AST_TYPE::arguments: - return read_arguments(reader); - case AST_TYPE::keyword: - return read_keyword(reader); - case AST_TYPE::Module: - return read_module(reader); - default: - fprintf(stderr, "Unknown node type (parser.cpp:" STRINGIFY(__LINE__) "): %d\n", type); - exit(1); - break; - } -} - -AST_Module* parse(const char* fn) { - Timer _t("parsing"); - - std::string cmdline = "python codegen/parse_ast.py "; - cmdline += fn; - FILE *fp = popen(cmdline.c_str(), "r"); - - BufferedReader *reader = new BufferedReader(fp); - AST* rtn = readASTMisc(reader); - reader->fill(); - ASSERT(reader->bytesBuffered() == 0, "%d", reader->bytesBuffered()); - delete reader; - - int code = pclose(fp); - assert(code == 0); - - assert(rtn->type == AST_TYPE::Module); - - long us = _t.end(); - static StatCounter us_parsing("us_parsing"); - us_parsing.log(us); - - return static_cast(rtn); -} - -#define MAGIC_STRING "a\ncf" -#define MAGIC_STRING_LENGTH 4 - -static void _reparse(const char* fn, const std::string &cache_fn) { - std::string cmdline = std::string("python -S codegen/parse_ast.py ") + fn; - FILE *parser = popen(cmdline.c_str(), "r"); - FILE *cache_fp = fopen(cache_fn.c_str(), "w"); - assert(cache_fp); - - fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp); - - char buf[80]; - while (true) { - int nread = fread(buf, 1, 80, parser); - if (nread == 0) - break; - fwrite(buf, 1, nread, cache_fp); - } - int code = pclose(parser); - assert(code == 0); - fclose(cache_fp); -} - -// Parsing the file is somewhat expensive since we have to shell out to cpython; -// it's not a huge deal right now, but this caching version can significantly cut down -// on the startup time (40ms -> 10ms). -AST_Module* caching_parse(const char* fn) { - Timer _t("parsing"); - - int code; - std::string cache_fn = std::string(fn) + "c"; - - struct stat source_stat, cache_stat; - code = stat(fn, &source_stat); - assert(code == 0); - code = stat(cache_fn.c_str(), &cache_stat); - if (code != 0 || cache_stat.st_mtime < source_stat.st_mtime || - (cache_stat.st_mtime == source_stat.st_mtime && cache_stat.st_mtim.tv_nsec < source_stat.st_mtim.tv_nsec)) { - _reparse(fn, cache_fn); - } - - FILE *fp = fopen(cache_fn.c_str(), "r"); - assert(fp); - - while (true) { - char buf[MAGIC_STRING_LENGTH]; - int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp); - if (read != 4 || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) { - fclose(fp); - _reparse(fn, cache_fn); - - fp = fopen(cache_fn.c_str(), "r"); - assert(fp); - } else { - break; - } - } - - BufferedReader *reader = new BufferedReader(fp); - AST* rtn = readASTMisc(reader); - reader->fill(); - assert(reader->bytesBuffered() == 0); - delete reader; - - assert(rtn->type == AST_TYPE::Module); - - long us = _t.end(); - static StatCounter us_parsing("us_parsing"); - us_parsing.log(us); - - return static_cast(rtn); -} - -} diff --git a/src/codegen/parser.h b/src/codegen/parser.h deleted file mode 100644 index 929bc834f..000000000 --- a/src/codegen/parser.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_PARSER_H -#define PYSTON_CODEGEN_PARSER_H - -namespace pyston { - -class AST_Module; - -AST_Module* parse(const char* fn); -AST_Module* caching_parse(const char* fn); - -} - -#endif diff --git a/src/codegen/patchpoints.cpp b/src/codegen/patchpoints.cpp deleted file mode 100644 index 773962707..000000000 --- a/src/codegen/patchpoints.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "asm_writing/icinfo.h" - -#include "codegen/patchpoints.h" -#include "codegen/stackmaps.h" - -namespace pyston { - -int PatchpointSetupInfo::totalSize() const { - int call_size = 13; - if (getCallingConvention() != llvm::CallingConv::C) { - // have no idea what the precise number is: - call_size = 128; - } - return num_slots * slot_size + call_size; -} -int64_t PatchpointSetupInfo::getPatchpointId() const { - return pp_id; -} - -static std::unordered_map new_patchpoints_by_id; - -PatchpointSetupInfo* PatchpointSetupInfo::initialize(bool has_return_value, int num_slots, int slot_size, CompiledFunction *parent_cf, patchpoints::PatchpointType type) { - static int64_t next_id = 100; - int64_t id = next_id++; - - PatchpointSetupInfo* rtn = new PatchpointSetupInfo(id, type, num_slots, slot_size, parent_cf, has_return_value); - new_patchpoints_by_id[id] = rtn; - return rtn; -} - -namespace patchpoints { - -void processStackmap(StackMap* stackmap) { - int nrecords = stackmap ? stackmap->records.size() : 0; - - for (int i = 0; i < nrecords; i++) { - StackMap::Record *r = stackmap->records[i]; - - assert(stackmap->stack_size_records.size() == 1); - const StackMap::StackSizeRecord &stack_size_record = stackmap->stack_size_records[0]; - int stack_size = stack_size_record.stack_size; - - PatchpointSetupInfo* pp = new_patchpoints_by_id[r->id]; - assert(pp); - - bool has_scratch = (pp->numScratchBytes() != 0); - int scratch_rbp_offset = 0; - if (has_scratch) { - assert(r->locations.size() == 1); - - StackMap::Record::Location l = r->locations[0]; - - static const int DWARF_RBP_REGNUM = 6; - - assert(l.type == 2); // "Direct" - assert(l.regnum == DWARF_RBP_REGNUM); - scratch_rbp_offset = l.offset; - } else { - assert(r->locations.size() == 0); - } - - uint8_t* func_addr = (uint8_t*)pp->parent_cf->code; - assert(func_addr); - uint8_t* start_addr = func_addr + r->offset; - - std::unordered_set live_outs; - for (auto live_out : r->live_outs) { - live_outs.insert(live_out.regnum); - } - - // llvm doesn't consider callee-save registers to be live - // if they're never allocated, but I think it makes much more - // sense to track them as live_outs. - // Unfortunately this means we need to be conservative about it unless - // we can change llvm's behavior. - live_outs.insert(3); - live_outs.insert(12); - live_outs.insert(13); - live_outs.insert(14); - live_outs.insert(15); - - registerCompiledPatchpoint(start_addr, pp, StackInfo({stack_size, has_scratch, pp->numScratchBytes(), scratch_rbp_offset}), std::move(live_outs)); - } - - for (std::unordered_map::iterator it = - new_patchpoints_by_id.begin(), end = new_patchpoints_by_id.end(); it != end; ++it) { - delete it->second; - } - new_patchpoints_by_id.clear(); -} - -PatchpointSetupInfo* createGenericPatchpoint(CompiledFunction *parent_cf, bool has_return_value, int size) { - return PatchpointSetupInfo::initialize(has_return_value, 1, size, parent_cf, Generic); -} - -PatchpointSetupInfo* createGetattrPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 1, 128, parent_cf, Getattr); -} - -PatchpointSetupInfo* createGetitemPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 1, 128, parent_cf, Getitem); -} - -PatchpointSetupInfo* createSetitemPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 1, 144, parent_cf, Setitem); -} - -PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(false, 2, 128, parent_cf, Setattr); -} - -PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction *parent_cf, int num_args) { - return PatchpointSetupInfo::initialize(true, 3, 256 + 36 * num_args, parent_cf, Callsite); -} - -PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 1, 80, parent_cf, GetGlobal); -} - -PatchpointSetupInfo* createBinexpPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 4, 160, parent_cf, Binexp); -} - -PatchpointSetupInfo* createNonzeroPatchpoint(CompiledFunction *parent_cf) { - return PatchpointSetupInfo::initialize(true, 1, 64, parent_cf, Nonzero); -} - -} // namespace patchpoints - -} // namespace pyston diff --git a/src/codegen/patchpoints.h b/src/codegen/patchpoints.h deleted file mode 100644 index 154efa1d5..000000000 --- a/src/codegen/patchpoints.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_PATCHPOINTS_H -#define PYSTON_CODEGEN_PATCHPOINTS_H - -#include -#include - -#include "llvm/IR/CallingConv.h" - -namespace pyston { - -namespace patchpoints { - -enum PatchpointType { - Generic, - Callsite, - GetGlobal, - Getattr, - Setattr, - Getitem, - Setitem, - Binexp, - Nonzero, -}; - -} - -class CompiledFunction; - -class PatchpointSetupInfo { - private: - PatchpointSetupInfo(int64_t pp_id, patchpoints::PatchpointType type, int num_slots, int slot_size, CompiledFunction* parent_cf, bool has_return_value) : - pp_id(pp_id), type(type), num_slots(num_slots), slot_size(slot_size), has_return_value(has_return_value), parent_cf(parent_cf) { - } - - const int64_t pp_id; - public: - const patchpoints::PatchpointType type; - - const int num_slots, slot_size; - const bool has_return_value; - CompiledFunction * const parent_cf; - void* metadata; - - int totalSize() const; - int64_t getPatchpointId() const; - bool hasReturnValue() const { return has_return_value; } - - int numScratchBytes() const { return 64; } - - llvm::CallingConv::ID getCallingConvention() const { - // The plan is to switch probably everything over to PreseveAll (and potentially AnyReg), - // but for only switch Getattr so the testing can be localized: - if (type == patchpoints::Getattr || type == patchpoints::Setattr) - return llvm::CallingConv::PreserveAll; - - return llvm::CallingConv::C; - } - - static PatchpointSetupInfo* initialize(bool has_return_value, int num_slots, int slot_size, CompiledFunction* parent_cf, patchpoints::PatchpointType type); -}; - -struct StackMap; - -namespace patchpoints { - -void processStackmap(StackMap* stackmap); - -PatchpointSetupInfo* createGenericPatchpoint(CompiledFunction* parent_cf, bool has_return_value, int size); -PatchpointSetupInfo* createCallsitePatchpoint(CompiledFunction* parent_cf, int num_args); -PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createGetattrPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createSetattrPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createGetitemPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createSetitemPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createBinexpPatchpoint(CompiledFunction* parent_cf); -PatchpointSetupInfo* createNonzeroPatchpoint(CompiledFunction* parent_cf); - -} - -} // namespace pyston - -#endif diff --git a/src/codegen/profiling/dumprof.cpp b/src/codegen/profiling/dumprof.cpp deleted file mode 100644 index d51098346..000000000 --- a/src/codegen/profiling/dumprof.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -#include "core/common.h" -#include "core/options.h" - -#include "codegen/profiling/profiling.h" - -namespace pyston { - -class DumpJITEventListener : public llvm::JITEventListener { - private: - public: - virtual void NotifyObjectEmitted(const llvm::ObjectImage &Obj); -}; - -static int num = 0; -void DumpJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - llvm::error_code code; - - std::ostringstream os(""); - os << "jit" << ++num << ".o"; - FILE* f = fopen(os.str().c_str(), "w"); - fwrite(Obj.getData().data(), 1, Obj.getData().size(), f); - fclose(f); -} - -llvm::JITEventListener* makeDumpJITEventListener() { - if (DUMPJIT) - return new DumpJITEventListener(); - return NULL; -} -static RegisterHelper X(makeDumpJITEventListener); - -} diff --git a/src/codegen/profiling/oprofile.cpp b/src/codegen/profiling/oprofile.cpp deleted file mode 100644 index b8e753d6f..000000000 --- a/src/codegen/profiling/oprofile.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -#include - -#include "core/common.h" -#include "core/options.h" - -#include "codegen/profiling/profiling.h" - -namespace pyston { - -class OprofileJITEventListener : public llvm::JITEventListener { - private: - op_agent_t agent; - public: - OprofileJITEventListener() { - agent = op_open_agent(); - assert(agent); - } - - virtual ~OprofileJITEventListener() { - op_close_agent(agent); - } - - virtual void NotifyObjectEmitted(const llvm::ObjectImage &Obj); -}; - -void OprofileJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - if (VERBOSITY() >= 1) - printf("An object has been emitted:\n"); - - llvm::error_code code; - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;) { - llvm::object::SymbolRef::Type type; - code = I->getType(type); - assert(!code); - if (type == llvm::object::SymbolRef::ST_Function) { - llvm::StringRef name; - uint64_t addr, size; - code = I->getName(name); - assert(!code); - code = I->getAddress(addr); - assert(!code); - code = I->getSize(size); - assert(!code); - - if (VERBOSITY() >= 1) - printf("registering with oprofile: %s %p 0x%lx\n", name.data(), (void*)addr, size); - int r = op_write_native_code(agent, name.data(), addr, (void*)addr, size); - assert(r == 0); - //} else { - //llvm::StringRef name; - //code = I->getName(name); - //assert(!code); - //printf("Skipping %s\n", name.data()); - } - ++I; - } -} - -llvm::JITEventListener* makeOprofileJITEventListener() { - return new OprofileJITEventListener(); -} -static RegisterHelper X(makeOprofileJITEventListener); - -} diff --git a/src/codegen/profiling/pprof.cpp b/src/codegen/profiling/pprof.cpp deleted file mode 100644 index 5f6e25bb3..000000000 --- a/src/codegen/profiling/pprof.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -#include "core/common.h" -#include "core/options.h" - -#include "codegen/profiling/profiling.h" - -namespace pyston { - -class PprofJITEventListener : public llvm::JITEventListener { - private: - FILE *of; - public: - PprofJITEventListener() { - of = fopen("pprof.jit", "w"); - } - virtual ~PprofJITEventListener() { - fclose(of); - } - - virtual void NotifyObjectEmitted(const llvm::ObjectImage &Obj); -}; - -void PprofJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - llvm::error_code code; - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;) { - llvm::object::SymbolRef::Type type; - code = I->getType(type); - assert(!code); - if (type == llvm::object::SymbolRef::ST_Function) { - llvm::StringRef name; - uint64_t addr, size; - code = I->getName(name); - assert(!code); - code = I->getAddress(addr); - assert(!code); - code = I->getSize(size); - assert(!code); - - //fprintf(of, "%lx-%lx: %s\n", addr, addr + size, name.data()); - //if (VERBOSITY() >= 1) - //printf("%lx-%lx: %s\n", addr, addr + size, name.data()); - fprintf(of, "%lx %lx %s\n", addr, addr + size, name.data()); - if (VERBOSITY() >= 1) - printf("%lx %lx %s\n", addr, addr + size, name.data()); - } - ++I; - } -} - -llvm::JITEventListener* makePprofJITEventListener() { - return new PprofJITEventListener(); -} -static RegisterHelper X(makePprofJITEventListener); - -} diff --git a/src/codegen/profiling/process_pprof.py b/src/codegen/profiling/process_pprof.py deleted file mode 100644 index 6c69e8e65..000000000 --- a/src/codegen/profiling/process_pprof.py +++ /dev/null @@ -1,55 +0,0 @@ -import sys - -class RangeLookup(object): - def __init__(self): - self.ranges = [] - - def register(self, start, end, name): - self.ranges.append((start, end, name)) - - def lookup(self, addr): - for start, end, name in self.ranges: - if start <= addr < end: - return "jit:" + name - return hex(addr) - -if __name__ == "__main__": - raw_fn = sys.argv[1] - jit_fns = sys.argv[2:] - - ranger = RangeLookup() - - for fn in jit_fns: - for l in open(fn): - start, end, name = l.split(' ', 2) - name = name.strip() - - ranger.register(int(start, 16), int(end, 16), name) - - mode = 0 - for l in open(raw_fn): - l = l.strip() - if mode == 0: - assert l == "--- symbol" - mode = 1 - print l - elif mode == 1: - assert l == "binary=jit_pprof" - mode = 2 - print l - elif mode == 3: - print l - elif mode == 2: - if l == "---": - mode = 3 - print l - else: - addr, curname = l.split(' ', 1) - if addr != curname: - print l - else: - addr_int = int(addr, 16) - print addr, ranger.lookup(addr_int) - else: - assert 0, mode - diff --git a/src/codegen/profiling/profiling.cpp b/src/codegen/profiling/profiling.cpp deleted file mode 100644 index 16278b19c..000000000 --- a/src/codegen/profiling/profiling.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "codegen/profiling/profiling.h" - -namespace pyston { - -typedef llvm::JITEventListener* (*Ctor)(); -static Ctor ctors[16]; -static int num_ctors = 0; -std::vector makeJITEventListeners() { - std::vector rtn; - for (int i = 0; i < num_ctors; i++) { - rtn.push_back(ctors[i]()); - } - return rtn; -} - -void registerProfileListenerCtor(llvm::JITEventListener* (*c)()) { - assert(num_ctors < sizeof(ctors) / sizeof(ctors[0])); - ctors[num_ctors] = c; - num_ctors++; -} - -} diff --git a/src/codegen/profiling/profiling.h b/src/codegen/profiling/profiling.h deleted file mode 100644 index b13285ef0..000000000 --- a/src/codegen/profiling/profiling.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_PROFILING_PROFILING_H -#define PYSTON_CODEGEN_PROFILING_PROFILING_H - -#include - -#include "llvm/ExecutionEngine/ExecutionEngine.h" - -namespace pyston { - -std::vector makeJITEventListeners(); - -void registerProfileListenerCtor(llvm::JITEventListener* (*)()); -class RegisterHelper { - public: - RegisterHelper(llvm::JITEventListener* (*ctor)()) { - registerProfileListenerCtor(ctor); - } -}; - -} - -#endif - diff --git a/src/codegen/runtime_hooks.cpp b/src/codegen/runtime_hooks.cpp deleted file mode 100644 index d8b5c0219..000000000 --- a/src/codegen/runtime_hooks.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/JIT.h" -#include "llvm/IR/Module.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/PassManager.h" - -#include "core/types.h" - -#include "codegen/runtime_hooks.h" -#include "codegen/codegen.h" -#include "codegen/irgen.h" -#include "codegen/irgen/hooks.h" -#include "codegen/irgen/util.h" - -#include "runtime/int.h" -#include "runtime/float.h" -#include "runtime/gc_runtime.h" -#include "runtime/types.h" -#include "runtime/objmodel.h" - -#include "runtime/inline/boxing.h" - -namespace pyston { - -static llvm::Function* lookupFunction(const std::string &name) { - llvm::Function *r = g.stdlib_module->getFunction(name); - ASSERT(r, "Couldn't find '%s'", name.c_str()); - return r; -} - -static llvm::Value* getFunc(void* func, const char* name) { - llvm::Function *f = lookupFunction(name); - ASSERT(f, "%s", name); - g.func_addr_registry.registerFunction(name, func, 0, f); - return embedConstantPtr(func, f->getType()); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::ArrayRef arg_types, bool varargs=false) { - llvm::FunctionType *ft = llvm::FunctionType::get(rtn_type, arg_types, varargs); - return embedConstantPtr(func, ft->getPointerTo()); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, bool varargs=false) { - return addFunc(func, rtn_type, llvm::ArrayRef(), varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, bool varargs=false) { - llvm::Type* array[] = {arg1}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, llvm::Type* arg3, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2, arg3}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, llvm::Type* arg3, llvm::Type* arg4, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2, arg3, arg4}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, llvm::Type* arg3, llvm::Type* arg4, llvm::Type* arg5, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2, arg3, arg4, arg5}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, llvm::Type* arg3, llvm::Type* arg4, llvm::Type* arg5, llvm::Type* arg6, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2, arg3, arg4, arg5, arg6}; - return addFunc(func, rtn_type, array, varargs); -} - -static llvm::Value* addFunc(void *func, llvm::Type* rtn_type, llvm::Type* arg1, llvm::Type* arg2, llvm::Type* arg3, llvm::Type* arg4, llvm::Type* arg5, llvm::Type* arg6, llvm::Type* arg7, bool varargs=false) { - llvm::Type* array[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7}; - return addFunc(func, rtn_type, array, varargs); -} - -void initGlobalFuncs(GlobalState &g) { - g.llvm_opaque_type = llvm::StructType::create(g.context, "opaque"); - - g.llvm_clfunction_type_ptr = lookupFunction("boxCLFunction")->arg_begin()->getType(); - g.llvm_module_type_ptr = lookupFunction("createModule")->getReturnType(); - g.llvm_bool_type_ptr = lookupFunction("boxBool")->getReturnType(); - - g.llvm_value_type_ptr = lookupFunction("getattr")->getReturnType(); - g.llvm_value_type = g.llvm_value_type_ptr->getSequentialElementType(); - //g.llvm_class_type_ptr = llvm::cast(g.llvm_value_type)->getElementType(0); - //g.llvm_class_type = g.llvm_class_type_ptr->getSequentialElementType(); - g.llvm_class_type = g.stdlib_module->getTypeByName("class.pyston::BoxedClass"); - assert(g.llvm_class_type); - g.llvm_class_type_ptr = g.llvm_class_type->getPointerTo(); - - g.llvm_flavor_type = g.stdlib_module->getTypeByName("class.pyston::ObjectFlavor"); - assert(g.llvm_flavor_type); - g.llvm_flavor_type_ptr = g.llvm_flavor_type->getPointerTo(); - - g.llvm_str_type_ptr = lookupFunction("boxStringPtr")->arg_begin()->getType(); - - -#define GET(N) g.funcs.N = getFunc((void*)N, STRINGIFY(N)) - - g.funcs.printf = addFunc((void*)printf, g.i8_ptr, true); - g.funcs.my_assert = getFunc((void*)my_assert, "my_assert"); - g.funcs.malloc = addFunc((void*)malloc, g.i8_ptr, g.i64); - g.funcs.free = addFunc((void*)free, g.void_, g.i8_ptr); - - GET(boxCLFunction); - GET(unboxCLFunction); - GET(createClass); - GET(boxInt); - GET(unboxInt); - GET(boxFloat); - GET(unboxFloat); - GET(boxStringPtr); - GET(boxInstanceMethod); - GET(boxBool); - GET(unboxBool); - GET(createTuple); - GET(createList); - GET(createDict); - GET(createSlice); - - GET(getattr); - GET(setattr); - GET(getitem); - GET(setitem); - GET(getGlobal); - GET(binop); - GET(compare); - GET(nonzero); - GET(print); - GET(unboxedLen); - GET(getclsattr); - GET(unaryop); - GET(import); - - GET(checkUnpackingLength); - GET(raiseAttributeError); - GET(raiseAttributeErrorStr); - GET(raiseNotIterableError); - GET(assertNameDefined); - - GET(printFloat); - GET(listAppendInternal); - - GET(dump); - - g.funcs.runtimeCall = getFunc((void*)runtimeCall, "runtimeCall"); - g.funcs.runtimeCall0 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64); - g.funcs.runtimeCall1 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.llvm_value_type_ptr); - g.funcs.runtimeCall2 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr); - g.funcs.runtimeCall3 = addFunc((void*)runtimeCall, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr); - - g.funcs.callattr = getFunc((void*)callattr, "callattr"); - g.funcs.callattr0 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i64); - g.funcs.callattr1 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i64, g.llvm_value_type_ptr); - g.funcs.callattr2 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr); - g.funcs.callattr3 = addFunc((void*)callattr, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_str_type_ptr, g.i1, g.i64, g.llvm_value_type_ptr, g.llvm_value_type_ptr, g.llvm_value_type_ptr); - - g.funcs.reoptCompiledFunc = addFunc((void*)reoptCompiledFunc, g.i8_ptr, g.i8_ptr); - g.funcs.compilePartialFunc = addFunc((void*)compilePartialFunc, g.i8_ptr, g.i8_ptr); - - g.funcs.div_i64_i64 = getFunc((void*)div_i64_i64, "div_i64_i64"); - g.funcs.mod_i64_i64 = getFunc((void*)mod_i64_i64, "mod_i64_i64"); - g.funcs.pow_i64_i64 = getFunc((void*)pow_i64_i64, "pow_i64_i64"); - - GET(div_float_float); - GET(mod_float_float); - GET(pow_float_float); -} - -} diff --git a/src/codegen/runtime_hooks.h b/src/codegen/runtime_hooks.h deleted file mode 100644 index c637d1bc0..000000000 --- a/src/codegen/runtime_hooks.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_RUNTIMEHOOKS_H -#define PYSTON_CODEGEN_RUNTIMEHOOKS_H - -namespace pyston { - -struct GlobalFuncs { - llvm::Value *printf, *my_assert, *malloc, *free; - - llvm::Value *boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxStringPtr, *boxCLFunction, *unboxCLFunction, *boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createClass; - llvm::Value *getattr, *setattr, *print, *nonzero, *binop, *compare, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import; - llvm::Value *checkUnpackingLength, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, *assertNameDefined; - llvm::Value *printFloat, *listAppendInternal; - llvm::Value *dump; - llvm::Value *runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall; - llvm::Value *callattr0, *callattr1, *callattr2, *callattr3, *callattr; - llvm::Value *reoptCompiledFunc, *compilePartialFunc; - - llvm::Value *div_i64_i64, *mod_i64_i64, *pow_i64_i64; - llvm::Value *div_float_float, *mod_float_float, *pow_float_float; -}; - -} - -#endif diff --git a/src/codegen/stackmaps.cpp b/src/codegen/stackmaps.cpp deleted file mode 100644 index 91563703d..000000000 --- a/src/codegen/stackmaps.cpp +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" -#include "llvm/Object/ObjectFile.h" - -#include "core/options.h" - -#include "codegen/codegen.h" -#include "codegen/stackmaps.h" - -//#undef VERBOSITY -//#define VERBOSITY() 2 - -namespace pyston { - -// TODO shouldn't be recording this in a global variable -static StackMap *cur_map = NULL; -StackMap* parseStackMap() { - StackMap* rtn = cur_map; - cur_map = NULL; - return rtn; -} - -class StackmapJITEventListener : public llvm::JITEventListener { - private: - public: - virtual void NotifyObjectEmitted(const llvm::ObjectImage&); -}; - -void StackmapJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - //llvm::outs() << "An object has been emitted:\n"; - - llvm::error_code code; - - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;) { - llvm::StringRef name; - code = I->getName(name); - assert(!code); - - if (name == "__LLVM_StackMaps") { - uint64_t stackmap_offset; - code = I->getFileOffset(stackmap_offset); - assert(!code); - //code = I->getSize(stackmap_size); - //assert(stackmap_size > 0); - //assert(!code); - if (VERBOSITY() >= 2) printf("Found the stackmaps at stackmap_offset 0x%lx\n", stackmap_offset); - - assert(cur_map == NULL); - cur_map = new StackMap(); - - union { - const int8_t* i8; - const int16_t* i16; - const int32_t* i32; - const int64_t* i64; - const uint8_t* u8; - const uint16_t* u16; - const uint32_t* u32; - const uint64_t* u64; - const StackMap::Record::Location* record_loc; - const StackMap::Record::LiveOut* record_liveout; - const StackMap::StackSizeRecord* size_record; - } ptr; - const int8_t* start_ptr = ptr.i8 = (const int8_t*)Obj.getData().data() + stackmap_offset; - - cur_map->header = *ptr.u32++; // header - -#if LLVMREV < 200481 - int nfunctions = 0; -#else - int nfunctions = *ptr.u32++; -#endif - int nconstants = *ptr.u32++; - int nrecords = *ptr.u32++; - - if (VERBOSITY() >= 2) printf("%d functions\n", nfunctions); - for (int i = 0; i < nfunctions; i++) { - const StackMap::StackSizeRecord &size_record = *ptr.size_record++; - cur_map->stack_size_records.push_back(size_record); - if (VERBOSITY() >= 2) printf("function %d: offset 0x%lx, stack size 0x%lx\n", i, size_record.offset, size_record.stack_size); - } - - if (VERBOSITY() >= 2) printf("%d constants\n", nconstants); - - for (int i = 0; i < nconstants; i++) { - uint64_t constant = *ptr.u64++; - if (VERBOSITY() >= 2) printf("Constant %d: %ld\n", i, constant); - cur_map->constants.push_back(constant); - } - - if (VERBOSITY() >= 2) printf("%d records\n", nrecords); - - for (int i = 0; i < nrecords; i++) { - StackMap::Record *record = new StackMap::Record(); - cur_map->records.push_back(record); - - record->id = *ptr.u64++; - record->offset = *ptr.u32++; - record->flags = *ptr.u16++; // reserved (record flags) - - int numlocations = *ptr.u16++; - - if (VERBOSITY() >= 2) printf("Stackmap record %ld at 0x%x has %d locations:\n", record->id, record->offset, numlocations); - for (int j = 0; j < numlocations; j++) { - assert(sizeof(StackMap::Record::Location) == sizeof(*ptr.u64)); - const StackMap::Record::Location &r = *ptr.record_loc++; - record->locations.push_back(r); - - // from http://lxr.free-electrons.com/source/tools/perf/arch/x86/util/dwarf-regs.c - // TODO this probably can be fetched more portably from the llvm target files - const char *dwarf_reg_names[] = { - "%rax", - "%rdx", - "%rcx", - "%rbx", - "%rsi", - "%rdi", - "%rbp", - "%rsp", - "%r8", - "%r9", - "%r10", - "%r11", - "%r12", - "%r13", - "%r14", - "%r15", - }; - if (VERBOSITY() >= 2) { - if (r.type == 1) { - printf("Location %d: type %d (reg), reg %d (%s), offset %d\n", j, r.type, r.regnum, dwarf_reg_names[r.regnum], r.offset); - } else { - printf("Location %d: type %d, reg %d, offset %d\n", j, r.type, r.regnum, r.offset); - } - } - } - - ptr.u16++; // padding - int num_live_outs = *ptr.u16++; - for (int i = 0; i < num_live_outs; i++) { - const StackMap::Record::LiveOut &r = *ptr.record_liveout++; - record->live_outs.push_back(r); - - if (VERBOSITY() >= 2) { - printf("Live out %d: reg #%d (?), size %d\n", i, r.regnum, r.size); - } - } - if (num_live_outs % 2 == 0) - ptr.u32++; // pad to 8-byte boundary - } - -#ifndef NDEBUG - uint64_t stackmap_size; - llvm::object::section_iterator section(Obj.end_sections()); - code = I->getSection(section); - assert(!code); - code = section->getSize(stackmap_size); - assert(stackmap_size > 0); - assert(!code); - - ASSERT(ptr.i8 - start_ptr == stackmap_size, "%ld %ld", ptr.i8 - start_ptr, stackmap_size); -#endif - } - -#if LLVMREV < 200442 - I = I.increment(code); -#else - ++I; -#endif - } -} - -llvm::JITEventListener* makeStackMapListener() { - return new StackmapJITEventListener(); -} - -} diff --git a/src/codegen/stackmaps.h b/src/codegen/stackmaps.h deleted file mode 100644 index 529e73a2a..000000000 --- a/src/codegen/stackmaps.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CODEGEN_STACKMAPS_H -#define PYSTON_CODEGEN_STACKMAPS_H - -#include - -namespace llvm { -class JITEventListener; -} - -namespace pyston { - -struct StackMap { - struct __attribute__((__packed__)) StackSizeRecord { - uint64_t offset; - uint64_t stack_size; - }; - - struct Record { - struct __attribute__((__packed__)) Location { - uint8_t type; - uint8_t flags; - uint16_t regnum; - int32_t offset; - }; - - struct __attribute__((__packed__)) LiveOut { - uint16_t regnum; - uint8_t reserved; - uint8_t size; - }; - - uint64_t id; - uint32_t offset; - uint16_t flags; - std::vector locations; - std::vector live_outs; - }; - - std::vector stack_size_records; - uint32_t header; - std::vector constants; - std::vector records; -}; - -StackMap* parseStackMap(); -llvm::JITEventListener* makeStackMapListener(); - -} - -#endif diff --git a/src/codegen/unwinding.cpp b/src/codegen/unwinding.cpp deleted file mode 100644 index cc51013d9..000000000 --- a/src/codegen/unwinding.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "llvm/DebugInfo.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectImage.h" - -#include "codegen/codegen.h" - -namespace pyston { - -class TracebacksEventListener : public llvm::JITEventListener { - public: - void NotifyObjectEmitted(const llvm::ObjectImage &Obj) { - llvm::DIContext* Context = llvm::DIContext::getDWARFContext(Obj.getObjectFile()); - - llvm::error_code ec; - for (llvm::object::symbol_iterator I = Obj.begin_symbols(), - E = Obj.end_symbols(); - I != E && !ec; - ++I) { - std::string SourceFileName; - - llvm::object::SymbolRef::Type SymType; - if (I->getType(SymType)) continue; - if (SymType == llvm::object::SymbolRef::ST_Function) { - llvm::StringRef Name; - uint64_t Addr; - uint64_t Size; - if (I->getName(Name)) continue; - if (I->getAddress(Addr)) continue; - if (I->getSize(Size)) continue; - - llvm::DILineInfoTable lines = Context->getLineInfoForAddressRange(Addr, Size, llvm::DILineInfoSpecifier::FunctionName | llvm::DILineInfoSpecifier::FileLineInfo); - for (int i = 0; i < lines.size(); i++) { - //printf("%s:%d, %s: %lx\n", lines[i].second.getFileName(), lines[i].second.getLine(), lines[i].second.getFunctionName(), lines[i].first); - } - } - } - - } -}; - -std::string getPythonFuncAt(void* addr, void* sp) { - return ""; -} - -llvm::JITEventListener* makeTracebacksListener() { - return new TracebacksEventListener(); -} - -} diff --git a/src/core/ast.cpp b/src/core/ast.cpp deleted file mode 100644 index 4353565e2..000000000 --- a/src/core/ast.cpp +++ /dev/null @@ -1,1120 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -#include "core/ast.h" -#include "core/cfg.h" - -#define FUTURE_DIVISION 0 - -namespace pyston { - -std::string getOpSymbol(int op_type) { - switch (op_type) { - case AST_TYPE::Add: - return "+"; - case AST_TYPE::BitAnd: - return "&"; - case AST_TYPE::BitOr: - return "|"; - case AST_TYPE::BitXor: - return "^"; - case AST_TYPE::Div: - return "/"; - case AST_TYPE::Eq: - return "=="; - case AST_TYPE::FloorDiv: - return "//"; - case AST_TYPE::LShift: - return "<<"; - case AST_TYPE::Lt: - return "<"; - case AST_TYPE::LtE: - return "<="; - case AST_TYPE::Gt: - return ">"; - case AST_TYPE::GtE: - return ">="; - case AST_TYPE::Invert: - return "~"; - case AST_TYPE::Is: - return "is"; - case AST_TYPE::IsNot: - return "is not"; - case AST_TYPE::Mod: - return "%"; - case AST_TYPE::Mult: - return "*"; - case AST_TYPE::Not: - return "not"; - case AST_TYPE::NotEq: - return "!="; - case AST_TYPE::Pow: - return "**"; - case AST_TYPE::RShift: - return ">>"; - case AST_TYPE::Sub: - return "-"; - case AST_TYPE::UAdd: - return "+"; - case AST_TYPE::USub: - return "-"; - default: - fprintf(stderr, "Unknown op type (ast.cpp:" STRINGIFY(__LINE__) "): %d\n", op_type); - abort(); - } -} - -std::string getOpName(int op_type) { - assert(op_type != AST_TYPE::Is); - assert(op_type != AST_TYPE::IsNot); - - switch (op_type) { - case AST_TYPE::Add: - return "__add__"; - case AST_TYPE::BitAnd: - return "__and__"; - case AST_TYPE::BitOr: - return "__or__"; - case AST_TYPE::BitXor: - return "__xor__"; - case AST_TYPE::Div: - if (FUTURE_DIVISION) - return "__truediv__"; - else - return "__div__"; - case AST_TYPE::Eq: - return "__eq__"; - case AST_TYPE::FloorDiv: - return "__floordiv__"; - case AST_TYPE::LShift: - return "__lshift__"; - case AST_TYPE::Lt: - return "__lt__"; - case AST_TYPE::LtE: - return "__le__"; - case AST_TYPE::Gt: - return "__gt__"; - case AST_TYPE::GtE: - return "__ge__"; - case AST_TYPE::Invert: - return "__invert__"; - case AST_TYPE::Mod: - return "__mod__"; - case AST_TYPE::Mult: - return "__mul__"; - case AST_TYPE::Not: - return "__nonzero__"; - case AST_TYPE::NotEq: - return "__ne__"; - case AST_TYPE::Pow: - return "__pow__"; - case AST_TYPE::RShift: - return "__rshift__"; - case AST_TYPE::Sub: - return "__sub__"; - case AST_TYPE::UAdd: - return "__pos__"; - case AST_TYPE::USub: - return "__neg__"; - default: - fprintf(stderr, "Unknown op type (ast.cpp:" STRINGIFY(__LINE__) "): %d\n", op_type); - abort(); - } -} - -std::string getReverseOpName(int op_type) { - if (op_type == AST_TYPE::Lt) - return getOpName(AST_TYPE::GtE); - if (op_type == AST_TYPE::LtE) - return getOpName(AST_TYPE::Gt); - if (op_type == AST_TYPE::Gt) - return getOpName(AST_TYPE::LtE); - if (op_type == AST_TYPE::GtE) - return getOpName(AST_TYPE::Lt); - if (op_type == AST_TYPE::NotEq) - return getOpName(AST_TYPE::NotEq); - if (op_type == AST_TYPE::Eq) - return getOpName(AST_TYPE::Eq); - - std::string normal_name = getOpName(op_type); - return "__r" + normal_name.substr(2); -} - -template -static void visitVector(const std::vector &vec, ASTVisitor *v) { - for (int i = 0; i < vec.size(); i++) { - vec[i]->accept(v); - } -} - -void AST_alias::accept(ASTVisitor *v) { - bool skip = v->visit_alias(this); - if (skip) return; -} - -void AST_arguments::accept(ASTVisitor *v) { - bool skip = v->visit_arguments(this); - if (skip) return; - - visitVector(defaults, v); - visitVector(args, v); - if (kwarg) kwarg->accept(v); -} - -void AST_Assign::accept(ASTVisitor *v) { - bool skip = v->visit_assign(this); - if (skip) return; - - value->accept(v); - for (int i = 0; i < targets.size(); i++) { - // Targets are assigned to left-to-right, so this is valid: - // x = x.a = object() - // but this is not: - // x.a = x = object() - targets[i]->accept(v); - } -} - -void AST_Assign::accept_stmt(StmtVisitor *v) { - v->visit_assign(this); -} - -void AST_Attribute::accept(ASTVisitor *v) { - bool skip = v->visit_attribute(this); - if (skip) return; - - value->accept(v); -} - -void* AST_Attribute::accept_expr(ExprVisitor *v) { - return v->visit_attribute(this); -} - -void AST_BinOp::accept(ASTVisitor *v) { - bool skip = v->visit_binop(this); - if (skip) return; - - left->accept(v); - right->accept(v); -} - -void* AST_BinOp::accept_expr(ExprVisitor *v) { - return v->visit_binop(this); -} - -void AST_BoolOp::accept(ASTVisitor *v) { - bool skip = v->visit_boolop(this); - if (skip) return; - - visitVector(values, v); -} - -void* AST_BoolOp::accept_expr(ExprVisitor *v) { - return v->visit_boolop(this); -} - -void AST_Break::accept(ASTVisitor *v) { - bool skip = v->visit_break(this); - if (skip) return; -} - -void AST_Break::accept_stmt(StmtVisitor *v) { - v->visit_break(this); -} - -void AST_Call::accept(ASTVisitor *v) { - bool skip = v->visit_call(this); - if (skip) return; - - func->accept(v); - visitVector(args, v); - visitVector(keywords, v); - if (starargs) starargs->accept(v); - if (kwargs) kwargs->accept(v); -} - -void* AST_Call::accept_expr(ExprVisitor *v) { - return v->visit_call(this); -} - -void AST_Compare::accept(ASTVisitor *v) { - bool skip = v->visit_compare(this); - if (skip) return; - - left->accept(v); - visitVector(comparators, v); -} - -void* AST_Compare::accept_expr(ExprVisitor *v) { - return v->visit_compare(this); -} - -void AST_ClassDef::accept(ASTVisitor *v) { - bool skip = v->visit_classdef(this); - if (skip) return; - - visitVector(this->bases, v); - visitVector(this->decorator_list, v); - visitVector(this->body, v); -} - -void AST_ClassDef::accept_stmt(StmtVisitor *v) { - v->visit_classdef(this); -} - -void AST_Continue::accept(ASTVisitor *v) { - bool skip = v->visit_continue(this); - if (skip) return; -} - -void AST_Continue::accept_stmt(StmtVisitor *v) { - v->visit_continue(this); -} - -void AST_Dict::accept(ASTVisitor *v) { - bool skip = v->visit_dict(this); - if (skip) return; - - for (int i = 0; i < keys.size(); i++) { - keys[i]->accept(v); - values[i]->accept(v); - } -} - -void* AST_Dict::accept_expr(ExprVisitor *v) { - return v->visit_dict(this); -} - -void AST_Expr::accept(ASTVisitor *v) { - bool skip = v->visit_expr(this); - if (skip) return; - - value->accept(v); -} - -void AST_Expr::accept_stmt(StmtVisitor *v) { - v->visit_expr(this); -} - -void AST_For::accept(ASTVisitor *v) { - bool skip = v->visit_for(this); - if (skip) return; - - iter->accept(v); - target->accept(v); - visitVector(body, v); - visitVector(orelse, v); -} - -void AST_For::accept_stmt(StmtVisitor *v) { - v->visit_for(this); -} - -void AST_FunctionDef::accept(ASTVisitor *v) { - bool skip = v->visit_functiondef(this); - if (skip) return; - - visitVector(decorator_list, v); - args->accept(v); - visitVector(body, v); -} - -void AST_FunctionDef::accept_stmt(StmtVisitor *v) { - v->visit_functiondef(this); -} - -void AST_Global::accept(ASTVisitor *v) { - bool skip = v->visit_global(this); - if (skip) return; -} - -void AST_Global::accept_stmt(StmtVisitor *v) { - v->visit_global(this); -} - -void AST_If::accept(ASTVisitor *v) { - bool skip = v->visit_if(this); - if (skip) return; - - test->accept(v); - visitVector(body, v); - visitVector(orelse, v); -} - -void AST_If::accept_stmt(StmtVisitor *v) { - v->visit_if(this); -} - -void AST_Import::accept(ASTVisitor *v) { - bool skip = v->visit_import(this); - if (skip) return; - - visitVector(names, v); -} - -void AST_Import::accept_stmt(StmtVisitor *v) { - v->visit_import(this); -} - -void AST_Index::accept(ASTVisitor *v) { - bool skip = v->visit_index(this); - if (skip) return; - - this->value->accept(v); -} - -void* AST_Index::accept_expr(ExprVisitor *v) { - return v->visit_index(this); -} - -void AST_keyword::accept(ASTVisitor *v) { - bool skip = v->visit_keyword(this); - if (skip) return; - - value->accept(v); -} - -void AST_List::accept(ASTVisitor *v) { - bool skip = v->visit_list(this); - if (skip) return; - - visitVector(elts, v); -} - -void* AST_List::accept_expr(ExprVisitor *v) { - return v->visit_list(this); -} - -void AST_Module::accept(ASTVisitor *v) { - bool skip = v->visit_module(this); - if (skip) return; - - visitVector(body, v); -} - -void AST_Name::accept(ASTVisitor *v) { - bool skip = v->visit_name(this); -} - -void* AST_Name::accept_expr(ExprVisitor *v) { - return v->visit_name(this); -} - -void AST_Num::accept(ASTVisitor *v) { - bool skip = v->visit_num(this); -} - -void* AST_Num::accept_expr(ExprVisitor *v) { - return v->visit_num(this); -} - -void AST_Pass::accept(ASTVisitor *v) { - bool skip = v->visit_pass(this); -} - -void AST_Pass::accept_stmt(StmtVisitor *v) { - v->visit_pass(this); -} - -void AST_Print::accept(ASTVisitor *v) { - bool skip = v->visit_print(this); - if (skip) return; - - if (dest) dest->accept(v); - visitVector(values, v); -} - -void AST_Print::accept_stmt(StmtVisitor *v) { - v->visit_print(this); -} - -void AST_Return::accept(ASTVisitor *v) { - bool skip = v->visit_return(this); - if (skip) return; - - if (value) value->accept(v); -} - -void AST_Return::accept_stmt(StmtVisitor *v) { - v->visit_return(this); -} - -void AST_Slice::accept(ASTVisitor *v) { - bool skip = v->visit_slice(this); - if (skip) return; - - if (lower) lower->accept(v); - if (upper) upper->accept(v); - if (step) step->accept(v); -} - -void* AST_Slice::accept_expr(ExprVisitor *v) { - return v->visit_slice(this); -} - -void AST_Str::accept(ASTVisitor *v) { - bool skip = v->visit_str(this); - if (skip) return; -} - -void* AST_Str::accept_expr(ExprVisitor *v) { - return v->visit_str(this); -} - -void AST_Subscript::accept(ASTVisitor *v) { - bool skip = v->visit_subscript(this); - if (skip) return; - - this->value->accept(v); - this->slice->accept(v); -} - -void* AST_Subscript::accept_expr(ExprVisitor *v) { - return v->visit_subscript(this); -} - -void AST_Tuple::accept(ASTVisitor *v) { - bool skip = v->visit_tuple(this); - if (skip) return; - - visitVector(elts, v); -} - -void* AST_Tuple::accept_expr(ExprVisitor *v) { - return v->visit_tuple(this); -} - -void AST_UnaryOp::accept(ASTVisitor *v) { - bool skip = v->visit_unaryop(this); - if (skip) return; - - operand->accept(v); -} - -void* AST_UnaryOp::accept_expr(ExprVisitor *v) { - return v->visit_unaryop(this); -} - -void AST_While::accept(ASTVisitor *v) { - bool skip = v->visit_while(this); - if (skip) return; - - test->accept(v); - visitVector(body, v); - visitVector(orelse, v); -} - -void AST_While::accept_stmt(StmtVisitor *v) { - v->visit_while(this); -} - -void AST_With::accept(ASTVisitor *v) { - bool skip = v->visit_with(this); - if (skip) return; - - context_expr->accept(v); - if (optional_vars) optional_vars->accept(v); - visitVector(body, v); -} - -void AST_With::accept_stmt(StmtVisitor *v) { - v->visit_with(this); -} - - -void AST_Branch::accept(ASTVisitor *v) { - bool skip = v->visit_branch(this); - if (skip) return; - - test->accept(v); -} - -void AST_Branch::accept_stmt(StmtVisitor *v) { - v->visit_branch(this); -} - - -void AST_Jump::accept(ASTVisitor *v) { - bool skip = v->visit_jump(this); - if (skip) return; -} - -void AST_Jump::accept_stmt(StmtVisitor *v) { - v->visit_jump(this); -} - -void AST_ClsAttribute::accept(ASTVisitor *v) { - bool skip = v->visit_clsattribute(this); - if (skip) return; - - value->accept(v); -} - -void* AST_ClsAttribute::accept_expr(ExprVisitor *v) { - return v->visit_clsattribute(this); -} - - - - -void print_ast(AST* ast) { - PrintVisitor v; - ast->accept(&v); -} - -void PrintVisitor::printIndent() { - for (int i = 0; i < indent; i++) { - putchar(' '); - } -} - -bool PrintVisitor::visit_alias(AST_alias *node) { - printf("%s", node->name.c_str()); - if (node->asname.size()) - printf(" as %s", node->asname.c_str()); - return true; -} - -bool PrintVisitor::visit_arguments(AST_arguments *node) { - int nargs = node->args.size(); - int ndefault = node->defaults.size(); - for (int i = 0; i < nargs; i++) { - if (i > 0) printf(", "); - - node->args[i]->accept(this); - if (i >= nargs - ndefault) { - printf("="); - node->defaults[i - (nargs - ndefault)]->accept(this); - } - } - return true; -} - -bool PrintVisitor::visit_assign(AST_Assign *node) { - for (int i = 0; i < node->targets.size(); i++) { - node->targets[i]->accept(this); - printf(" = "); - } - node->value->accept(this); - return true; -} - -bool PrintVisitor::visit_attribute(AST_Attribute *node) { - node->value->accept(this); - putchar('.'); - printf("%s", node->attr.c_str()); - return true; -} - -bool PrintVisitor::visit_binop(AST_BinOp *node) { - node->left->accept(this); - switch (node->op_type) { - case AST_TYPE::Add: - putchar('+'); - break; - case AST_TYPE::BitAnd: - putchar('&'); - break; - case AST_TYPE::BitOr: - putchar('|'); - break; - case AST_TYPE::BitXor: - putchar('^'); - break; - case AST_TYPE::Div: - putchar('/'); - break; - case AST_TYPE::LShift: - printf("<<"); - break; - case AST_TYPE::RShift: - printf(">>"); - break; - case AST_TYPE::Pow: - printf("**"); - break; - case AST_TYPE::Mod: - putchar('%'); - break; - case AST_TYPE::Mult: - putchar('*'); - break; - case AST_TYPE::Sub: - putchar('-'); - break; - default: - printf("<%d>", node->op_type); - break; - } - node->right->accept(this); - return true; -} - -bool PrintVisitor::visit_boolop(AST_BoolOp *node) { - for (int i = 0; i < node->values.size(); i++) { - node->values[i]->accept(this); - - if (i == node->values.size() - 1) continue; - switch (node->op_type) { - case AST_TYPE::And: - printf(" and "); - break; - case AST_TYPE::Or: - printf(" or "); - break; - default: - ASSERT(0, "%d", node->op_type); - break; - } - } - return true; -} - -bool PrintVisitor::visit_break(AST_Break *node) { - printf("break"); - return true; -} - -bool PrintVisitor::visit_call(AST_Call *node) { - node->func->accept(this); - printf("("); - - bool prevarg = false; - for (int i = 0; i < node->args.size(); i++) { - if (prevarg) printf(", "); - node->args[i]->accept(this); - prevarg = true; - } - for (int i = 0; i < node->keywords.size(); i++) { - if (prevarg) printf(", "); - node->keywords[i]->accept(this); - prevarg = true; - } - if (node->starargs) { - if (prevarg) printf(", "); - node->starargs->accept(this); - prevarg = true; - } - if (node->kwargs) { - if (prevarg) printf(", "); - node->kwargs->accept(this); - prevarg = true; - } - printf(")"); - return true; -} - -bool PrintVisitor::visit_compare(AST_Compare *node) { - node->left->accept(this); - - for (int i = 0; i < node->ops.size(); i++) { - std::string symbol = getOpSymbol(node->ops[i]); - printf(" %s ", symbol.c_str()); - - node->comparators[i]->accept(this); - } - - return true; -} - -bool PrintVisitor::visit_classdef(AST_ClassDef *node) { - for (int i = 0, n = node->decorator_list.size(); i < n; i++) { - printf("@"); - node->decorator_list[i]->accept(this); - printf("\n"); - printIndent(); - } - printf("class %s(", node->name.c_str()); - for (int i = 0, n = node->bases.size(); i < n; i++) { - if (i) - printf(", "); - node->bases[i]->accept(this); - } - printf(")"); - - indent += 4; - for (int i = 0, n = node->body.size(); i < n; i++) { - printf("\n"); - printIndent(); - node->body[i]->accept(this); - } - indent -= 4; - - return true; -} - -bool PrintVisitor::visit_continue(AST_Continue *node) { - printf("continue"); - return true; -} - -bool PrintVisitor::visit_dict(AST_Dict *node) { - printf("{"); - for (int i = 0; i < node->keys.size(); i++) { - if (i > 0) printf(", "); - node->keys[i]->accept(this); - printf(":"); - node->values[i]->accept(this); - } - printf("}"); - return true; -} - -bool PrintVisitor::visit_expr(AST_Expr *node) { - return false; -} - -bool PrintVisitor::visit_for(AST_For *node) { - printf("\n"); - return true; -} - -bool PrintVisitor::visit_functiondef(AST_FunctionDef *node) { - assert(node->decorator_list.size() == 0); - printf("def %s(", node->name.c_str()); - node->args->accept(this); - printf(")"); - - indent += 4; - for (int i = 0; i < node->body.size(); i++) { - printf("\n"); - printIndent(); - node->body[i]->accept(this); - } - indent -= 4; - return true; -} - -bool PrintVisitor::visit_global(AST_Global *node) { - printf("global "); - for (int i = 0; i < node->names.size(); i++) { - if (i > 0) printf(", "); - printf("%s", node->names[i].c_str()); - } - return true; -} - -bool PrintVisitor::visit_if(AST_If *node) { - printf("if "); - node->test->accept(this); - printf(":\n"); - - indent += 4; - for(int i = 0; i < node->body.size(); i++) { - printIndent(); - node->body[i]->accept(this); - printf("\n"); - } - indent -= 4; - - if (node->orelse.size()) { - printIndent(); - bool elif = false; - - if (node->orelse.size() == 1 && node->orelse[0]->type == AST_TYPE::If) - elif = true; - - if (elif) { - printf("el"); - } else { - printf("else:\n"); - indent += 4; - } - for(int i = 0; i < node->orelse.size(); i++) { - if (i) printf("\n"); - printIndent(); - node->orelse[i]->accept(this); - } - if (!elif) - indent -= 4; - } - return true; -} - -bool PrintVisitor::visit_import(AST_Import *node) { - printf("import "); - for (int i = 0; i < node->names.size(); i++) { - if (i > 0) printf(", "); - node->names[i]->accept(this); - } - return true; -} - -bool PrintVisitor::visit_index(AST_Index *node) { - return false; -} - -bool PrintVisitor::visit_list(AST_List *node) { - printf("["); - for (int i = 0, n = node->elts.size(); i < n; ++i) { - if (i > 0) - printf(", "); - node->elts[i]->accept(this); - } - printf("]"); - return true; -} - -bool PrintVisitor::visit_keyword(AST_keyword *node) { - printf("%s=", node->arg.c_str()); - node->value->accept(this); - return true; -} - -bool PrintVisitor::visit_module(AST_Module *node) { - //printf("\n"); - for (int i = 0; i < node->body.size(); i++) { - node->body[i]->accept(this); - printf("\n"); - } - return true; -} - -bool PrintVisitor::visit_name(AST_Name *node) { - printf("%s", node->id.c_str()); - return false; -} - -bool PrintVisitor::visit_num(AST_Num *node) { - if (node->num_type == AST_Num::INT) { - printf("%ld", node->n_int); - } else if (node->num_type == AST_Num::FLOAT) { - printf("%f", node->n_float); - } else { - RELEASE_ASSERT(0, ""); - } - return false; -} - -bool PrintVisitor::visit_pass(AST_Pass *node) { - printf("pass"); - return true; -} - -bool PrintVisitor::visit_print(AST_Print *node) { - printf("print "); - if (node->dest) { - printf(">>"); - node->dest->accept(this); - printf(", "); - } - for (int i = 0; i < node->values.size(); i++) { - if (i > 0) - printf(", "); - node->values[i]->accept(this); - } - if (!node->nl) - printf(","); - return true; -} - -bool PrintVisitor::visit_return(AST_Return *node) { - printf("return "); - return false; -} - -bool PrintVisitor::visit_slice(AST_Slice *node) { - if (node->lower) - node->lower->accept(this); - if (node->upper || node->step) - putchar(':'); - if (node->upper) - node->upper->accept(this); - if (node->step) { - putchar(':'); - node->step->accept(this); - } - return true; -} - -bool PrintVisitor::visit_str(AST_Str *node) { - printf("\"%s\"", node->s.c_str()); - return false; -} - -bool PrintVisitor::visit_subscript(AST_Subscript *node) { - node->value->accept(this); - printf("["); - node->slice->accept(this); - printf("]"); - return true; -} - -bool PrintVisitor::visit_tuple(AST_Tuple *node) { - printf("("); - int n = node->elts.size(); - for (int i = 0; i < n; i++) { - if (i) printf(", "); - node->elts[i]->accept(this); - } - if (n == 1) - printf(","); - printf(")"); - return true; -} - -bool PrintVisitor::visit_unaryop(AST_UnaryOp *node) { - switch (node->op_type) { - case AST_TYPE::Invert: - printf("~"); - break; - case AST_TYPE::Not: - printf("not "); - break; - case AST_TYPE::UAdd: - printf("+"); - break; - case AST_TYPE::USub: - printf("-"); - break; - default: - RELEASE_ASSERT(0, "%s", getOpName(node->op_type).c_str()); - break; - } - node->operand->accept(this); - return true; -} - -bool PrintVisitor::visit_while(AST_While *node) { - printf("while "); - node->test->accept(this); - printf("\n"); - - indent += 4; - for (int i = 0; i < node->body.size(); i++) { - printIndent(); - node->body[i]->accept(this); - printf("\n"); - } - indent -= 4; - - if (node->orelse.size()) { - printIndent(); - printf("else\n"); - indent += 4; - for (int i = 0; i < node->orelse.size(); i++) { - printIndent(); - node->orelse[i]->accept(this); - printf("\n"); - } - indent -= 4; - } - return true; -} - -bool PrintVisitor::visit_with(AST_With *node) { - printf("with "); - node->context_expr->accept(this); - if (node->optional_vars) { - printf(" as "); - node->optional_vars->accept(this); - printf(":\n"); - } - - indent += 4; - for (int i = 0; i < node->body.size(); i++) { - if (i > 0) printf("\n"); - printIndent(); - node->body[i]->accept(this); - } - indent -= 4; - - return true; -} - -bool PrintVisitor::visit_branch(AST_Branch *node) { - printf("if "); - node->test->accept(this); - printf(" goto %d else goto %d", node->iftrue->idx, node->iffalse->idx); - return true; -} - -bool PrintVisitor::visit_jump(AST_Jump *node) { - printf("goto %d", node->target->idx); - return true; -} - -bool PrintVisitor::visit_clsattribute(AST_ClsAttribute *node) { - //printf("getclsattr("); - //node->value->accept(this); - //printf(", '%s')", node->attr.c_str()); - node->value->accept(this); - printf(":%s", node->attr.c_str()); - return true; -} - -class FlattenVisitor : public ASTVisitor { - private: - std::vector *output; - bool expand_scopes; - public: - FlattenVisitor(std::vector *output, bool expand_scopes) : output(output), expand_scopes(expand_scopes) { - } - - virtual bool visit_alias(AST_alias *node) { output->push_back(node); return false; } - virtual bool visit_arguments(AST_arguments *node) { output->push_back(node); return false; } - virtual bool visit_assign(AST_Assign *node) { output->push_back(node); return false; } - virtual bool visit_attribute(AST_Attribute *node) { output->push_back(node); return false; } - virtual bool visit_binop(AST_BinOp *node) { output->push_back(node); return false; } - virtual bool visit_boolop(AST_BoolOp *node) { output->push_back(node); return false; } - virtual bool visit_break(AST_Break *node) { output->push_back(node); return false; } - virtual bool visit_call(AST_Call *node) { output->push_back(node); return false; } - virtual bool visit_classdef(AST_ClassDef *node) { output->push_back(node); return !expand_scopes; } - virtual bool visit_compare(AST_Compare *node) { output->push_back(node); return false; } - virtual bool visit_continue(AST_Continue *node) { output->push_back(node); return false; } - virtual bool visit_dict(AST_Dict *node) { output->push_back(node); return false; } - virtual bool visit_expr(AST_Expr *node) { output->push_back(node); return false; } - virtual bool visit_for(AST_For *node) { output->push_back(node); return !expand_scopes; } - virtual bool visit_functiondef(AST_FunctionDef *node) { output->push_back(node); return !expand_scopes; } - virtual bool visit_if(AST_If *node) { output->push_back(node); return false; } - virtual bool visit_import(AST_Import *node) { output->push_back(node); return false; } - virtual bool visit_index(AST_Index *node) { output->push_back(node); return false; } - virtual bool visit_keyword(AST_keyword *node) { output->push_back(node); return false; } - virtual bool visit_list(AST_List *node) { output->push_back(node); return false; } - virtual bool visit_module(AST_Module *node) { output->push_back(node); return !expand_scopes; } - virtual bool visit_name(AST_Name *node) { output->push_back(node); return false; } - virtual bool visit_num(AST_Num *node) { output->push_back(node); return false; } - virtual bool visit_pass(AST_Pass *node) { output->push_back(node); return false; } - virtual bool visit_print(AST_Print *node) { output->push_back(node); return false; } - virtual bool visit_return(AST_Return *node) { output->push_back(node); return false; } - virtual bool visit_slice(AST_Slice *node) { output->push_back(node); return false; } - virtual bool visit_str(AST_Str *node) { output->push_back(node); return false; } - virtual bool visit_subscript(AST_Subscript *node) { output->push_back(node); return false; } - virtual bool visit_tuple(AST_Tuple *node) { output->push_back(node); return false; } - virtual bool visit_unaryop(AST_UnaryOp *node) { output->push_back(node); return false; } - virtual bool visit_while(AST_While *node) { output->push_back(node); return false; } - virtual bool visit_with(AST_With *node) { output->push_back(node); return false; } - - virtual bool visit_branch(AST_Branch *node) { output->push_back(node); return false; } - virtual bool visit_jump(AST_Jump *node) { output->push_back(node); return false; } - virtual bool visit_clsattribute(AST_ClsAttribute *node) { output->push_back(node); return false; } -}; - -std::vector* flatten(std::vector &roots, bool expand_scopes) { - std::vector *rtn = new std::vector(); - FlattenVisitor visitor(rtn, expand_scopes); - - for (int i = 0; i < roots.size(); i++) { - roots[i]->accept(&visitor); - } - return rtn; -} - -} diff --git a/src/core/ast.h b/src/core/ast.h deleted file mode 100644 index 15e6dd2d7..000000000 --- a/src/core/ast.h +++ /dev/null @@ -1,779 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_AST_H -#define PYSTON_CORE_AST_H - -#include -#include -#include -#include -#include - -namespace pyston { - -namespace AST_TYPE { - // These are in a pretty random order (started off alphabetical but then I had to add more). - // These can be changed freely as long as parse_ast.py is also updated - enum AST_TYPE { - alias = 1, - arguments = 2, - Assert = 3, - Assign = 4, - Attribute = 5, - AugAssign = 6, - BinOp = 7, - BoolOp = 8, - Call = 9, - ClassDef = 10, - Compare = 11, - comprehension = 12, - Delete = 13, - Dict = 14, - Exec = 16, - ExceptHandler = 17, - ExtSlice = 18, - Expr = 19, - For = 20, - FunctionDef = 21, - GeneratorExp = 22, - Global = 23, - If = 24, - IfExp = 25, - Import = 26, - ImportFrom = 27, - Index = 28, - keyword = 29, - Lambda = 30, - List = 31, - ListComp = 32, - Module = 33, - Num = 34, - Name = 35, - Pass = 37, - Pow = 38, - Print = 39, - Raise = 40, - Repr = 41, - Return = 42, - Slice = 44, - Str = 45, - Subscript = 46, - TryExcept = 47, - TryFinally = 48, - Tuple = 49, - UnaryOp = 50, - With = 51, - While = 52, - Yield = 53, - - Store = 54, - Load = 55, - Param = 56, - Not = 57, - In = 58, - Is = 59, - IsNot = 60, - Or = 61, - And = 62, - Eq = 63, - NotEq = 64, - NotIn = 65, - GtE = 66, - Gt = 67, - Mod = 68, - Add = 69, - Continue = 70, - Lt = 71, - LtE = 72, - Break = 73, - Sub = 74, - Del = 75, - Mult = 76, - Div = 77, - USub = 78, - BitAnd = 79, - BitOr = 80, - BitXor = 81, - RShift = 82, - LShift = 83, - Invert = 84, - UAdd = 85, - FloorDiv = 86, - - DictComp = 15, - Set = 43, - - // Pseudo-nodes that are specific to this compiler: - Branch = 200, - Jump = 201, - ClsAttribute = 202, - }; -}; - -class ASTVisitor; -class ExprVisitor; -class StmtVisitor; -class AST_keyword; - -class AST { - public: - const AST_TYPE::AST_TYPE type; - uint32_t lineno, col_offset; - - virtual void accept(ASTVisitor *v) = 0; - - AST(AST_TYPE::AST_TYPE type) : type(type) {} -}; - -class AST_expr : public AST { - public: - virtual void* accept_expr(ExprVisitor *v) = 0; - - AST_expr(AST_TYPE::AST_TYPE type) : AST(type) {} -}; - -class AST_stmt : public AST { - public: - virtual void accept_stmt(StmtVisitor *v) = 0; - - AST_stmt(AST_TYPE::AST_TYPE type) : AST(type) {} -}; - - - -class AST_alias : public AST { - public: - std::string name, asname; - - virtual void accept(ASTVisitor *v); - - AST_alias() : AST(AST_TYPE::alias) {} -}; - -class AST_arguments : public AST { - public: - // no lineno, col_offset attributes - std::vector args, defaults; - AST_expr *kwarg; - std::string vararg; - - virtual void accept(ASTVisitor *v); - - AST_arguments() : AST(AST_TYPE::arguments) {} -}; - -class AST_Assign : public AST_stmt { - public: - std::vector targets; - AST_expr* value; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Assign() : AST_stmt(AST_TYPE::Assign) {} -}; - -class AST_Attribute : public AST_expr { - public: - AST_expr* value; - AST_TYPE::AST_TYPE ctx_type; - std::string attr; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Attribute() : AST_expr(AST_TYPE::Attribute) {} -}; - -class AST_BinOp : public AST_expr { - public: - AST_TYPE::AST_TYPE op_type; - AST_expr *left, *right; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_BinOp() : AST_expr(AST_TYPE::BinOp) {} -}; - -class AST_BoolOp : public AST_expr { - public: - AST_TYPE::AST_TYPE op_type; - std::vector values; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_BoolOp() : AST_expr(AST_TYPE::BoolOp) {} -}; - -class AST_Break : public AST_stmt { - public: - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Break() : AST_stmt(AST_TYPE::Break) {} -}; - -class AST_Call : public AST_expr { - public: - AST_expr *starargs, *kwargs, *func; - std::vector args; - std::vector keywords; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Call() : AST_expr(AST_TYPE::Call) {} -}; - -class AST_Compare : public AST_expr { - public: - std::vector ops; - std::vector comparators; - AST_expr* left; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Compare() : AST_expr(AST_TYPE::Compare) {} -}; - -class AST_ClassDef : public AST_stmt { - public: - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - std::vector bases, decorator_list; - std::vector body; - std::string name; - - AST_ClassDef() : AST_stmt(AST_TYPE::ClassDef) {} -}; - -class AST_Continue : public AST_stmt { - public: - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Continue() : AST_stmt(AST_TYPE::Continue) {} -}; - -class AST_Dict : public AST_expr { - public: - std::vector keys, values; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Dict() : AST_expr(AST_TYPE::Dict) {} -}; - -class AST_Expr : public AST_stmt { - public: - AST_expr* value; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Expr() : AST_stmt(AST_TYPE::Expr) {} -}; - -class AST_For : public AST_stmt { - public: - const static int TYPE = AST_TYPE::For; - std::vector body, orelse; - AST_expr *target, *iter; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_For() : AST_stmt(AST_TYPE::For) {} -}; - -class AST_FunctionDef : public AST_stmt { - public: - const static int TYPE = AST_TYPE::FunctionDef; - std::vector body; - std::vector decorator_list; - std::string name; - AST_arguments *args; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_FunctionDef() : AST_stmt(AST_TYPE::FunctionDef) {} -}; - -class AST_Global : public AST_stmt { - public: - std::vector names; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Global() : AST_stmt(AST_TYPE::Global) {} -}; - -class AST_If : public AST_stmt { - public: - std::vector body, orelse; - AST_expr* test; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_If() : AST_stmt(AST_TYPE::If) {} -}; - -class AST_Import : public AST_stmt { - public: - std::vector names; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Import() : AST_stmt(AST_TYPE::Import) {} -}; - -class AST_Index : public AST_expr { - public: - const static AST_TYPE::AST_TYPE TYPE = AST_TYPE::Index; - AST_expr *value; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Index() : AST_expr(AST_TYPE::Index) {} -}; - -class AST_keyword : public AST { - public: - // no lineno, col_offset attributes - AST_expr *value; - std::string arg; - - virtual void accept(ASTVisitor *v); - - AST_keyword() : AST(AST_TYPE::keyword) {} -}; - -class AST_List : public AST_expr { - public: - const static AST_TYPE::AST_TYPE TYPE = AST_TYPE::List; - - std::vector elts; - AST_TYPE::AST_TYPE ctx_type; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_List() : AST_expr(AST_TYPE::List) {} -}; - -class AST_Module : public AST { - public: - // no lineno, col_offset attributes - const static AST_TYPE::AST_TYPE TYPE = AST_TYPE::Module; - std::vector body; - - virtual void accept(ASTVisitor *v); - - AST_Module() : AST(AST_TYPE::Module) {} -}; - -class AST_Name : public AST_expr { - public: - const static AST_TYPE::AST_TYPE TYPE = AST_TYPE::Name; - AST_TYPE::AST_TYPE ctx_type; - std::string id; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Name() : AST_expr(AST_TYPE::Name) {} -}; - -class AST_Num : public AST_expr { - public: - enum NumType { - // These values must correspond to the values in parse_ast.py - INT = 0x10, - FLOAT = 0x20, - } num_type; - - union { - int64_t n_int; - double n_float; - }; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Num() : AST_expr(AST_TYPE::Num) {} -}; - -class AST_Pass : public AST_stmt { - public: - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Pass() : AST_stmt(AST_TYPE::Pass) {} -}; - -class AST_Print : public AST_stmt { - public: - AST_expr* dest; - bool nl; - std::vector values; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Print() : AST_stmt(AST_TYPE::Print) {} -}; - -class AST_Return : public AST_stmt { - public: - AST_expr* value; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Return() : AST_stmt(AST_TYPE::Return) {} -}; - -class AST_Slice : public AST_expr { - public: - AST_expr *lower, *upper, *step; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Slice() : AST_expr(AST_TYPE::Slice) {} -}; - -class AST_Str : public AST_expr { - public: - std::string s; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Str() : AST_expr(AST_TYPE::Str) {} -}; - -class AST_Subscript : public AST_expr { - public: - AST_expr *value, *slice; - AST_TYPE::AST_TYPE ctx_type; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Subscript() : AST_expr(AST_TYPE::Subscript) {} -}; - -class AST_Tuple : public AST_expr { - public: - std::vector elts; - AST_TYPE::AST_TYPE ctx_type; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_Tuple() : AST_expr(AST_TYPE::Tuple) {} -}; - -class AST_UnaryOp : public AST_expr { - public: - AST_expr *operand; - AST_TYPE::AST_TYPE op_type; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_UnaryOp() : AST_expr(AST_TYPE::UnaryOp) {} -}; - -class AST_While : public AST_stmt { - public: - AST_expr *test; - std::vector body, orelse; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_While() : AST_stmt(AST_TYPE::While) {} -}; - -class AST_With : public AST_stmt { - public: - AST_expr *optional_vars, *context_expr; - std::vector body; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_With() : AST_stmt(AST_TYPE::With) {} -}; - - -// AST pseudo-nodes that will get added during CFG-construction. These don't exist in the input AST, but adding them in -// lets us avoid creating a completely new IR for this phase - -class CFGBlock; - -class AST_Branch : public AST_stmt { - public: - AST_expr *test; - CFGBlock *iftrue, *iffalse; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Branch() : AST_stmt(AST_TYPE::Branch) {} -}; - -class AST_Jump : public AST_stmt { - public: - CFGBlock *target; - - virtual void accept(ASTVisitor *v); - virtual void accept_stmt(StmtVisitor *v); - - AST_Jump() : AST_stmt(AST_TYPE::Jump) {} -}; - -class AST_ClsAttribute : public AST_expr { - public: - AST_expr *value; - std::string attr; - - virtual void accept(ASTVisitor *v); - virtual void* accept_expr(ExprVisitor *v); - - AST_ClsAttribute() : AST_expr(AST_TYPE::ClsAttribute) {} -}; - - -class ASTVisitor { - protected: - public: - virtual ~ASTVisitor() {} - - virtual bool visit_alias(AST_alias *node) { assert(0); abort(); } - virtual bool visit_arguments(AST_arguments *node) { assert(0); abort(); } - virtual bool visit_assign(AST_Assign *node) { assert(0); abort(); } - virtual bool visit_attribute(AST_Attribute *node) { assert(0); abort(); } - virtual bool visit_binop(AST_BinOp *node) { assert(0); abort(); } - virtual bool visit_boolop(AST_BoolOp *node) { assert(0); abort(); } - virtual bool visit_break(AST_Break *node) { assert(0); abort(); } - virtual bool visit_call(AST_Call *node) { assert(0); abort(); } - virtual bool visit_clsattribute(AST_ClsAttribute *node) { assert(0); abort(); } - virtual bool visit_compare(AST_Compare *node) { assert(0); abort(); } - virtual bool visit_classdef(AST_ClassDef *node) { assert(0); abort(); } - virtual bool visit_continue(AST_Continue *node) { assert(0); abort(); } - virtual bool visit_dict(AST_Dict *node) { assert(0); abort(); } - virtual bool visit_expr(AST_Expr *node) { assert(0); abort(); } - virtual bool visit_for(AST_For *node) { assert(0); abort(); } - virtual bool visit_functiondef(AST_FunctionDef *node) { assert(0); abort(); } - virtual bool visit_global(AST_Global *node) { assert(0); abort(); } - virtual bool visit_if(AST_If *node) { assert(0); abort(); } - virtual bool visit_import(AST_Import *node) { assert(0); abort(); } - virtual bool visit_index(AST_Index *node) { assert(0); abort(); } - virtual bool visit_keyword(AST_keyword *node) { assert(0); abort(); } - virtual bool visit_list(AST_List *node) { assert(0); abort(); } - virtual bool visit_module(AST_Module *node) { assert(0); abort(); } - virtual bool visit_name(AST_Name *node) { assert(0); abort(); } - virtual bool visit_num(AST_Num *node) { assert(0); abort(); } - virtual bool visit_pass(AST_Pass *node) { assert(0); abort(); } - virtual bool visit_print(AST_Print *node) { assert(0); abort(); } - virtual bool visit_return(AST_Return *node) { assert(0); abort(); } - virtual bool visit_slice(AST_Slice *node) { assert(0); abort(); } - virtual bool visit_str(AST_Str *node) { assert(0); abort(); } - virtual bool visit_subscript(AST_Subscript *node) { assert(0); abort(); } - virtual bool visit_tuple(AST_Tuple *node) { assert(0); abort(); } - virtual bool visit_unaryop(AST_UnaryOp *node) { assert(0); abort(); } - virtual bool visit_while(AST_While *node) { assert(0); abort(); } - virtual bool visit_with(AST_With *node) { assert(0); abort(); } - - virtual bool visit_branch(AST_Branch *node) { assert(0); abort(); } - virtual bool visit_jump(AST_Jump *node) { assert(0); abort(); } -}; - -class NoopASTVisitor : public ASTVisitor { - protected: - public: - virtual ~NoopASTVisitor() {} - - virtual bool visit_alias(AST_alias *node) { return false; } - virtual bool visit_arguments(AST_arguments *node) { return false; } - virtual bool visit_assign(AST_Assign *node) { return false; } - virtual bool visit_attribute(AST_Attribute *node) { return false; } - virtual bool visit_binop(AST_BinOp *node) { return false; } - virtual bool visit_boolop(AST_BoolOp *node) { return false; } - virtual bool visit_break(AST_Break *node) { return false; } - virtual bool visit_call(AST_Call *node) { return false; } - virtual bool visit_clsattribute(AST_ClsAttribute *node) { return false; } - virtual bool visit_compare(AST_Compare *node) { return false; } - virtual bool visit_classdef(AST_ClassDef *node) { return false; } - virtual bool visit_continue(AST_Continue *node) { return false; } - virtual bool visit_dict(AST_Dict *node) { return false; } - virtual bool visit_expr(AST_Expr *node) { return false; } - virtual bool visit_for(AST_For *node) { return false; } - virtual bool visit_functiondef(AST_FunctionDef *node) { return false; } - virtual bool visit_global(AST_Global *node) { return false; } - virtual bool visit_if(AST_If *node) { return false; } - virtual bool visit_import(AST_Import *node) { return false; } - virtual bool visit_index(AST_Index *node) { return false; } - virtual bool visit_keyword(AST_keyword *node) { return false; } - virtual bool visit_list(AST_List *node) { return false; } - virtual bool visit_module(AST_Module *node) { return false; } - virtual bool visit_name(AST_Name *node) { return false; } - virtual bool visit_num(AST_Num *node) { return false; } - virtual bool visit_pass(AST_Pass *node) { return false; } - virtual bool visit_print(AST_Print *node) { return false; } - virtual bool visit_return(AST_Return *node) { return false; } - virtual bool visit_slice(AST_Slice *node) { return false; } - virtual bool visit_str(AST_Str *node) { return false; } - virtual bool visit_subscript(AST_Subscript *node) { return false; } - virtual bool visit_tuple(AST_Tuple *node) { return false; } - virtual bool visit_unaryop(AST_UnaryOp *node) { return false; } - virtual bool visit_while(AST_While *node) { return false; } - virtual bool visit_with(AST_With *node) { return false; } - - virtual bool visit_branch(AST_Branch *node) { return false; } - virtual bool visit_jump(AST_Jump *node) { return false; } -}; - -class ExprVisitor { - protected: - public: - virtual ~ExprVisitor() {} - - virtual void* visit_attribute(AST_Attribute *node) { assert(0); abort(); } - virtual void* visit_binop(AST_BinOp *node) { assert(0); abort(); } - virtual void* visit_boolop(AST_BoolOp *node) { assert(0); abort(); } - virtual void* visit_call(AST_Call *node) { assert(0); abort(); } - virtual void* visit_clsattribute(AST_ClsAttribute *node) { assert(0); abort(); } - virtual void* visit_compare(AST_Compare *node) { assert(0); abort(); } - virtual void* visit_dict(AST_Dict *node) { assert(0); abort(); } - virtual void* visit_index(AST_Index *node) { assert(0); abort(); } - virtual void* visit_list(AST_List *node) { assert(0); abort(); } - virtual void* visit_name(AST_Name *node) { assert(0); abort(); } - virtual void* visit_num(AST_Num *node) { assert(0); abort(); } - virtual void* visit_slice(AST_Slice *node) { assert(0); abort(); } - virtual void* visit_str(AST_Str *node) { assert(0); abort(); } - virtual void* visit_subscript(AST_Subscript *node) { assert(0); abort(); } - virtual void* visit_tuple(AST_Tuple *node) { assert(0); abort(); } - virtual void* visit_unaryop(AST_UnaryOp *node) { assert(0); abort(); } -}; - -class StmtVisitor { - protected: - public: - virtual ~StmtVisitor() {} - - virtual void visit_assign(AST_Assign *node) { assert(0); abort(); } - virtual void visit_break(AST_Break *node) { assert(0); abort(); } - virtual void visit_classdef(AST_ClassDef *node) { assert(0); abort(); } - virtual void visit_continue(AST_Continue *node) { assert(0); abort(); } - virtual void visit_expr(AST_Expr *node) { assert(0); abort(); } - virtual void visit_for(AST_For *node) { assert(0); abort(); } - virtual void visit_functiondef(AST_FunctionDef *node) { assert(0); abort(); } - virtual void visit_global(AST_Global *node) { assert(0); abort(); } - virtual void visit_if(AST_If *node) { assert(0); abort(); } - virtual void visit_import(AST_Import *node) { assert(0); abort(); } - virtual void visit_pass(AST_Pass *node) { assert(0); abort(); } - virtual void visit_print(AST_Print *node) { assert(0); abort(); } - virtual void visit_return(AST_Return *node) { assert(0); abort(); } - virtual void visit_while(AST_While *node) { assert(0); abort(); } - virtual void visit_with(AST_With *node) { assert(0); abort(); } - - virtual void visit_branch(AST_Branch *node) { assert(0); abort(); } - virtual void visit_jump(AST_Jump *node) { assert(0); abort(); } -}; - -void print_ast(AST *ast); -class PrintVisitor : public ASTVisitor { - private: - int indent; - void printIndent(); - public: - PrintVisitor(int indent=0) : indent(indent) {} - virtual ~PrintVisitor() {} - - virtual bool visit_alias(AST_alias *node); - virtual bool visit_arguments(AST_arguments *node); - virtual bool visit_assign(AST_Assign *node); - virtual bool visit_attribute(AST_Attribute *node); - virtual bool visit_binop(AST_BinOp *node); - virtual bool visit_boolop(AST_BoolOp *node); - virtual bool visit_break(AST_Break *node); - virtual bool visit_call(AST_Call *node); - virtual bool visit_compare(AST_Compare *node); - virtual bool visit_classdef(AST_ClassDef *node); - virtual bool visit_clsattribute(AST_ClsAttribute *node); - virtual bool visit_continue(AST_Continue *node); - virtual bool visit_dict(AST_Dict *node); - virtual bool visit_expr(AST_Expr *node); - virtual bool visit_for(AST_For *node); - virtual bool visit_functiondef(AST_FunctionDef *node); - virtual bool visit_global(AST_Global *node); - virtual bool visit_if(AST_If *node); - virtual bool visit_import(AST_Import *node); - virtual bool visit_index(AST_Index *node); - virtual bool visit_keyword(AST_keyword *node); - virtual bool visit_list(AST_List *node); - virtual bool visit_module(AST_Module *node); - virtual bool visit_name(AST_Name *node); - virtual bool visit_num(AST_Num *node); - virtual bool visit_pass(AST_Pass *node); - virtual bool visit_print(AST_Print *node); - virtual bool visit_return(AST_Return *node); - virtual bool visit_slice(AST_Slice *node); - virtual bool visit_str(AST_Str *node); - virtual bool visit_subscript(AST_Subscript *node); - virtual bool visit_tuple(AST_Tuple *node); - virtual bool visit_unaryop(AST_UnaryOp *node); - virtual bool visit_while(AST_While *node); - virtual bool visit_with(AST_With *node); - - virtual bool visit_branch(AST_Branch *node); - virtual bool visit_jump(AST_Jump *node); -}; - -// Given an AST node, return a vector of the node plus all its descendents. -// This is useful for analyses that care more about the constituent nodes than the -// exact tree structure; ex, finding all "global" directives. -std::vector* flatten(std::vector &roots, bool expand_scopes); -// Similar to the flatten() function, but filters for a specific type of ast nodes: -template -std::vector* findNodes(std::vector &roots, bool expand_scopes) { - std::vector *rtn = new std::vector(); - std::vector *flattened = flatten(roots, expand_scopes); - for (int i = 0; i < flattened->size(); i++) { - AST* n = (*flattened)[i]; - if (n->type == T::TYPE) - rtn->push_back(reinterpret_cast(n)); - } - delete flattened; - return rtn; -} - -}; - -#endif diff --git a/src/core/cfg.cpp b/src/core/cfg.cpp deleted file mode 100644 index 3a0949d2f..000000000 --- a/src/core/cfg.cpp +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "core/options.h" - -#include "core/ast.h" -#include "core/cfg.h" - -namespace pyston { - -void CFGBlock::connectTo(CFGBlock *successor, bool allow_backedge) { - if (!allow_backedge) { - assert(this->idx >= 0); - ASSERT(successor->idx == -1 || successor->idx > this->idx, "edge from %d to %d", this->idx, successor->idx); - } - successors.push_back(successor); - successor->predecessors.push_back(this); -} - -class CFGVisitor : public ASTVisitor { - private: - AST_TYPE::AST_TYPE root_type; - CFG *cfg; - CFGBlock *curblock; - - struct LoopInfo { - CFGBlock *continue_dest, *break_dest; - }; - std::vector loops; - std::vector returns; - - void pushLoop(CFGBlock *continue_dest, CFGBlock *break_dest) { - LoopInfo loop; - loop.continue_dest = continue_dest; - loop.break_dest = break_dest; - loops.push_back(loop); - } - - void popLoop() { - loops.pop_back(); - } - - void pushReturn(CFGBlock *return_dest) { - returns.push_back(return_dest); - } - - void popReturn() { - returns.pop_back(); - } - - void doReturn(AST_expr* value) { - assert(value); - CFGBlock *rtn_dest = getReturn(); - if (rtn_dest != NULL) { - push_back(makeAssign("#rtnval", value)); - - AST_Jump *j = makeJump(); - j->target = rtn_dest; - curblock->connectTo(rtn_dest); - push_back(j); - } else { - AST_Return *node = new AST_Return(); - node->value = value; - node->col_offset = value->col_offset; - node->lineno = value->lineno; - push_back(node); - } - curblock = NULL; - } - - CFGBlock* getContinue() { - assert(loops.size()); - return loops.back().continue_dest; - } - - CFGBlock* getBreak() { - assert(loops.size()); - return loops.back().break_dest; - } - - CFGBlock* getReturn() { - if (returns.size()) - return returns.back(); - return NULL; - } - - - - AST_expr* makeNum(int n) { - AST_Num* node = new AST_Num(); - node->col_offset = -1; - node->lineno = -1; - node->num_type = AST_Num::INT; - node->n_int = n; - return node; - } - - AST_Jump* makeJump() { - AST_Jump* rtn = new AST_Jump(); - return rtn; - } - - AST_Branch* makeBranch(AST_expr* test) { - AST_Branch* rtn = new AST_Branch(); - rtn->test = test; - rtn->col_offset = test->col_offset; - rtn->lineno = test->lineno; - return rtn; - } - - AST_expr* makeLoadAttribute(AST_expr* base, const std::string &name, bool clsonly) { - AST_expr* rtn; - if (clsonly) { - AST_ClsAttribute *attr = new AST_ClsAttribute(); - attr->value = base; - attr->attr = name; - rtn = attr; - } else { - AST_Attribute *attr = new AST_Attribute(); - attr->ctx_type = AST_TYPE::Load; - attr->value = base; - attr->attr = name; - rtn = attr; - } - rtn->col_offset = base->col_offset; - rtn->lineno = base->lineno; - return rtn; - } - - AST_Call* makeCall(AST_expr* func) { - AST_Call *call = new AST_Call(); - call->starargs = NULL; - call->kwargs = NULL; - call->func = func; - call->col_offset = func->col_offset; - call->lineno = func->lineno; - return call; - } - - AST_expr* makeName(const std::string &id, AST_TYPE::AST_TYPE ctx_type, int lineno=-1, int col_offset=-1) { - AST_Name *name = new AST_Name(); - name->id = id; - name->col_offset = col_offset; - name->lineno = lineno; - name->ctx_type = ctx_type; - return name; - } - - AST_stmt* makeAssign(AST_expr *target, AST_expr *val) { - AST_Assign *assign = new AST_Assign(); - assign->targets.push_back(target); - assign->value = val; - assign->col_offset = val->col_offset; - assign->lineno = val->lineno; - return assign; - } - - AST_stmt* makeAssign(const std::string &id, AST_expr *val) { - assert(val); - AST_expr *name = makeName(id, AST_TYPE::Store, val->lineno, 0); - return makeAssign(name, val); - } - - AST_stmt* makeExpr(AST_expr* expr) { - AST_Expr *stmt = new AST_Expr(); - stmt->value = expr; - stmt->lineno = expr->lineno; - stmt->col_offset = expr->col_offset; - return stmt; - } - - public: - CFGVisitor(AST_TYPE::AST_TYPE root_type, CFG* cfg) : root_type(root_type), cfg(cfg) { - curblock = cfg->addBlock(); - curblock->info = "entry"; - } - - ~CFGVisitor() { - assert(loops.size() == 0); - assert(returns.size() == 0); - } - - void push_back(AST_stmt* node) { - if (curblock) - curblock->push_back(node); - } - - virtual bool visit_assign(AST_Assign* node) { push_back(node); return true; } - virtual bool visit_classdef(AST_ClassDef* node) { push_back(node); return true; } - virtual bool visit_expr(AST_Expr* node) { push_back(node); return true; } - virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; } - virtual bool visit_global(AST_Global* node) { push_back(node); return true; } - virtual bool visit_import(AST_Import* node) { push_back(node); return true; } - virtual bool visit_pass(AST_Pass* node) { push_back(node); return true; } - virtual bool visit_print(AST_Print* node) { push_back(node); return true; } - - virtual bool visit_return(AST_Return* node) { - if (root_type != AST_TYPE::FunctionDef) { - fprintf(stderr, "SyntaxError: 'return' outside function\n"); - exit(1); - } - - AST_expr *value = node->value; - if (value == NULL) - value = makeName("None", AST_TYPE::Load); - doReturn(value); - return true; - } - - virtual bool visit_if(AST_If* node) { - if (!curblock) return true; - - AST_Branch *br = new AST_Branch(); - br->col_offset = node->col_offset; - br->lineno = node->lineno; - br->test = node->test; - push_back(br); - - CFGBlock *starting_block = curblock; - CFGBlock *exit = cfg->addDeferredBlock(); - exit->info = "ifexit"; - - CFGBlock *iftrue = cfg->addBlock(); - iftrue->info = "iftrue"; - br->iftrue = iftrue; - starting_block->connectTo(iftrue); - curblock = iftrue; - for (int i = 0; i < node->body.size(); i++) { - node->body[i]->accept(this); - } - if (curblock) { - AST_Jump *jtrue = new AST_Jump(); - push_back(jtrue); - jtrue->target = exit; - curblock->connectTo(exit); - } - - CFGBlock *iffalse = cfg->addBlock(); - br->iffalse = iffalse; - starting_block->connectTo(iffalse); - - iffalse->info = "iffalse"; - curblock = iffalse; - for (int i = 0; i < node->orelse.size(); i++) { - node->orelse[i]->accept(this); - } - if (curblock) { - AST_Jump *jfalse = new AST_Jump(); - push_back(jfalse); - jfalse->target = exit; - curblock->connectTo(exit); - } - - if (exit->predecessors.size() == 0) { - curblock = NULL; - } else { - cfg->placeBlock(exit); - curblock = exit; - } - - return true; - } - - virtual bool visit_break(AST_Break* node) { - if (!curblock) return true; - - if (loops.size() == 0) { - fprintf(stderr, "SyntaxError: 'break' outside loop\n"); - exit(1); - } - - AST_Jump *j = makeJump(); - push_back(j); - assert(loops.size()); - j->target = loops[loops.size()-1].break_dest; - curblock->connectTo(j->target, true); - - curblock = NULL; - return true; - } - - virtual bool visit_continue(AST_Continue* node) { - if (!curblock) return true; - - if (loops.size() == 0) { - // Note: error message is different than the 'break' case - fprintf(stderr, "SyntaxError: 'continue' not properly in loop\n"); - exit(1); - } - - AST_Jump *j = makeJump(); - push_back(j); - assert(loops.size()); - j->target = loops[loops.size()-1].continue_dest; - curblock->connectTo(j->target, true); - - // See visit_break for explanation: - curblock = NULL; - return true; - } - - virtual bool visit_while(AST_While* node) { - if (!curblock) return true; - - CFGBlock *test_block = cfg->addBlock(); - test_block->info = "while_test"; - - AST_Jump *j = makeJump(); - push_back(j); - j->target = test_block; - curblock->connectTo(test_block); - - curblock = test_block; - AST_Branch *br = makeBranch(node->test); - push_back(br); - - // We need a reference to this block early on so we can break to it, - // but we don't want it to be placed until after the orelse. - CFGBlock *end = cfg->addDeferredBlock(); - end->info = "while_exit"; - pushLoop(test_block, end); - - CFGBlock *body = cfg->addBlock(); - body->info = "while_body_start"; - br->iftrue = body; - test_block->connectTo(body); - curblock = body; - for (int i = 0; i < node->body.size(); i++) { - node->body[i]->accept(this); - } - if (curblock) { - AST_Jump *jbody = makeJump(); - push_back(jbody); - jbody->target = test_block; - curblock->connectTo(test_block, true); - } - popLoop(); - - CFGBlock *orelse = cfg->addBlock(); - orelse->info = "while_orelse_start"; - br->iffalse = orelse; - test_block->connectTo(orelse); - curblock = orelse; - for (int i = 0; i < node->orelse.size(); i++) { - node->orelse[i]->accept(this); - } - if (curblock) { - AST_Jump *jend = makeJump(); - push_back(jend); - jend->target = end; - curblock->connectTo(end); - } - curblock = end; - - cfg->placeBlock(end); - - return true; - } - - virtual bool visit_for(AST_For* node) { - if (!curblock) return true; - - // TODO this is so complicated because I tried doing loop inversion; - // is it really worth it? It got so bad because all the edges became - // critical edges and needed to be broken, otherwise it's not too different. - - AST_expr *iter_attr = makeLoadAttribute(node->iter, "__iter__", true); - AST_expr *iter_call = makeCall(iter_attr); - - char itername_buf[80]; - snprintf(itername_buf, 80, "#iter_%p", node); - AST_stmt *iter_assign = makeAssign(itername_buf, iter_call); - push_back(iter_assign); - - AST_expr *hasnext_attr = makeLoadAttribute(makeName(itername_buf, AST_TYPE::Load), "__hasnext__", true); - AST_expr *next_attr = makeLoadAttribute(makeName(itername_buf, AST_TYPE::Load), "next", true); -//#define SAVE_ATTRS -#ifdef SAVE_ATTRS - char hasnextname_buf[80]; - snprintf(hasnextname_buf, 80, "#hasnext_%p", node); - AST_stmt *hasnext_assign = makeAssign(hasnextname_buf, hasnext_attr); - push_back(hasnext_assign); - char nextname_buf[80]; - snprintf(nextname_buf, 80, "#next_%p", node); - push_back(makeAssign(nextname_buf, next_attr)); -#endif - - CFGBlock *test_block = cfg->addBlock(); - AST_Jump* jump_to_test = makeJump(); - jump_to_test->target = test_block; - push_back(jump_to_test); - curblock->connectTo(test_block); - curblock = test_block; - -#ifdef SAVE_ATTRS - AST_expr *test_call = makeCall(makeName(hasnextname_buf, AST_TYPE::Load)); -#else - AST_expr *test_call = makeCall(hasnext_attr); -#endif - AST_Branch *test_br = makeBranch(test_call); - push_back(test_br); - - CFGBlock *test_true = cfg->addBlock(); - CFGBlock *test_false = cfg->addBlock(); - test_br->iftrue = test_true; - test_br->iffalse = test_false; - test_block->connectTo(test_true); - test_block->connectTo(test_false); - - CFGBlock *loop_block = cfg->addBlock(); - CFGBlock *end_block = cfg->addDeferredBlock(); - CFGBlock *else_block = cfg->addDeferredBlock(); - - curblock = test_true; - - // TODO simplify the breaking of these crit edges? - AST_Jump *test_true_jump = makeJump(); - test_true_jump->target = loop_block; - push_back(test_true_jump); - test_true->connectTo(loop_block); - - curblock = test_false; - AST_Jump *test_false_jump = makeJump(); - test_false_jump->target = else_block; - push_back(test_false_jump); - test_false->connectTo(else_block); - - pushLoop(test_block, end_block); - - curblock = loop_block; -#ifdef SAVE_ATTRS - push_back(makeAssign(node->target, makeCall(makeName(nextname_buf, AST_TYPE::Load)))); -#else - push_back(makeAssign(node->target, makeCall(next_attr))); -#endif - - for (int i = 0; i < node->body.size(); i++) { - node->body[i]->accept(this); - } - popLoop(); - - if (curblock) { -#ifdef SAVE_ATTRS - AST_expr *end_call = makeCall(makeName(hasnextname_buf, AST_TYPE::Load)); -#else - AST_expr *end_call = makeCall(hasnext_attr); -#endif - AST_Branch *end_br = makeBranch(end_call); - push_back(end_br); - - CFGBlock *end_true = cfg->addBlock(); - CFGBlock *end_false = cfg->addBlock(); - end_br->iftrue = end_true; - end_br->iffalse = end_false; - curblock->connectTo(end_true); - curblock->connectTo(end_false); - - curblock = end_true; - AST_Jump *end_true_jump = makeJump(); - end_true_jump->target = loop_block; - push_back(end_true_jump); - end_true->connectTo(loop_block, true); - - curblock = end_false; - AST_Jump *end_false_jump = makeJump(); - end_false_jump->target = else_block; - push_back(end_false_jump); - end_false->connectTo(else_block); - } - - cfg->placeBlock(else_block); - curblock = else_block; - - for (int i = 0; i < node->orelse.size(); i++) { - node->orelse[i]->accept(this); - } - if (curblock) { - AST_Jump *else_jump = makeJump(); - push_back(else_jump); - else_jump->target = end_block; - curblock->connectTo(end_block); - } - - cfg->placeBlock(end_block); - curblock = end_block; - - return true; - } - - virtual bool visit_with(AST_With* node) { - char ctxmgrname_buf[80]; - snprintf(ctxmgrname_buf, 80, "#ctxmgr_%p", node); - char exitname_buf[80]; - snprintf(exitname_buf, 80, "#exit_%p", node); - - push_back(makeAssign(ctxmgrname_buf, node->context_expr)); - - AST_expr *enter = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__enter__", true); - AST_expr *exit = makeLoadAttribute(makeName(ctxmgrname_buf, AST_TYPE::Load), "__exit__", true); - push_back(makeAssign(exitname_buf, exit)); - enter = makeCall(enter); - - if (node->optional_vars) { - push_back(makeAssign(node->optional_vars, enter)); - } else { - push_back(makeExpr(enter)); - } - - CFGBlock *continue_dest = NULL, *break_dest = NULL; - CFGBlock *orig_continue_dest = NULL, *orig_break_dest = NULL; - if (loops.size()) { - continue_dest = cfg->addDeferredBlock(); - continue_dest->info = "with_continue"; - break_dest = cfg->addDeferredBlock(); - break_dest->info = "with_break"; - - orig_continue_dest = loops[loops.size() - 1].continue_dest; - orig_break_dest = loops[loops.size() - 1].break_dest; - - pushLoop(continue_dest, break_dest); - } - - CFGBlock *orig_return_dest = getReturn(); - CFGBlock *return_dest = cfg->addDeferredBlock(); - return_dest->info = "with_return"; - pushReturn(return_dest); - - for (int i = 0; i < node->body.size(); i++) { - node->body[i]->accept(this); - } - - AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - push_back(makeExpr(exit_call)); - - CFGBlock *orig_ending_block = curblock; - - if (continue_dest) { - if (continue_dest->predecessors.size() == 0) { - delete continue_dest; - } else { - curblock = continue_dest; - - AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - push_back(makeExpr(exit_call)); - - cfg->placeBlock(continue_dest); - AST_Jump* jcontinue = makeJump(); - jcontinue->target = orig_continue_dest; - push_back(jcontinue); - continue_dest->connectTo(orig_continue_dest, true); - } - - if (break_dest->predecessors.size() == 0) { - delete break_dest; - } else { - curblock = break_dest; - - AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - push_back(makeExpr(exit_call)); - - cfg->placeBlock(break_dest); - AST_Jump* jbreak = makeJump(); - jbreak->target = orig_break_dest; - push_back(jbreak); - break_dest->connectTo(orig_break_dest, true); - } - popLoop(); - curblock = orig_ending_block; - } - - popReturn(); - if (return_dest->predecessors.size() == 0) { - delete return_dest; - } else { - cfg->placeBlock(return_dest); - curblock = return_dest; - - AST_Call* exit_call = makeCall(makeName(exitname_buf, AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - exit_call->args.push_back(makeName("None", AST_TYPE::Load)); - push_back(makeExpr(exit_call)); - - doReturn(makeName("#rtnval", AST_TYPE::Load)); - curblock = orig_ending_block; - } - - return true; - } -}; - -void CFG::print() { - printf("CFG:\n"); - printf("%ld blocks\n", blocks.size()); - PrintVisitor *pv = new PrintVisitor(4); - for (int i = 0; i < blocks.size(); i++) { - printf("Block %d", i); - CFGBlock *b = blocks[i]; - if (b->info) - printf(" '%s'", b->info); - - printf("; Predecessors:"); - for (int j = 0; j < b->predecessors.size(); j++) { - printf(" %d", b->predecessors[j]->idx); - } - printf(" Successors:"); - for (int j = 0; j < b->successors.size(); j++) { - printf(" %d", b->successors[j]->idx); - } - printf("\n"); - - for (int j = 0; j < b->body.size(); j++) { - printf(" "); - b->body[j]->accept(pv); - printf("\n"); - } - } - delete pv; -} - -CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector body) { - CFG *rtn = new CFG(); - CFGVisitor visitor(root_type, rtn); - for (int i = 0; i < body.size(); i++) { - body[i]->accept(&visitor); - } - - // Put a fake "return" statement at the end of every function just to make sure they all have one; - // we already have to support multiple return statements in a function, but this way we can avoid - // having to support not having a return statement: - AST_Return *return_stmt = new AST_Return(); - return_stmt->value = NULL; - visitor.push_back(return_stmt); - - //// - // Check some properties expected by later stages: - - // Block 0 is hard-coded to be the entry block, and shouldn't have any - // predecessors: - assert(rtn->blocks[0]->predecessors.size() == 0); - - // We need to generate the CFG in a way that doesn't have any critical edges, - // since the ir generation requires that. - // We could do this with a separate critical-edge-breaking pass, but for now - // the cfg-computing code directly avoids making critical edges. - // Either way, double check to make sure that we don't have any: - for (int i = 0; i < rtn->blocks.size(); i++) { - if (rtn->blocks[i]->successors.size() >= 2) { - for (int j = 0; j < rtn->blocks[i]->successors.size(); j++) { - // It's ok to have zero predecessors if you are the entry block - ASSERT(rtn->blocks[i]->successors[j]->predecessors.size() < 2, "Critical edge from %d to %d!", i, rtn->blocks[i]->successors[j]->idx); - } - } - } - - // The cfg blocks should be generated in roughly program order. - // Specifically, this means every block should have one predecessor block that - // has a lower index (except for block 0). - // We use this during IR generation to ensure that at least one predecessor has always - // been evaluated before the current block; this property also ensures that there are no - // dead blocks. - for (int i = 1; i < rtn->blocks.size(); i++) { - bool good = false; - for (int j = 0; j < rtn->blocks[i]->predecessors.size(); j++) { - if (rtn->blocks[i]->predecessors[j]->idx < i) - good = true; - } - if (!good) { - printf("internal error: block %d doesn't have a previous predecessor\n", i); - abort(); - } - - // Later phases also rely on the fact that the first predecessor has a lower index; - // this can be worked around but it's easiest just to ensure this here. - assert(rtn->blocks[i]->predecessors[0]->idx < i); - } - - return rtn; -} - -} diff --git a/src/core/cfg.h b/src/core/cfg.h deleted file mode 100644 index e173f2c58..000000000 --- a/src/core/cfg.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_CFG_H -#define PYSTON_CORE_CFG_H - -/* - * This CFG is a relatively high-level CFG, closely corresponding to the input Python source. We break down control-flow constructs, - * but it doesn't do things like decompose IfExpressions or short-circuit conditional expressions. - * Those will have to get broken into low-level control flow, so this CFG doesn't exactly correspond to the llvm-level one we will eventually - * generate; this one is (at least for now) meant to be a slightly-lowered version of the input AST, for doing relatively high-level things such - * as type analysis, liveness, etc, and then using as the source representation for the next lowering pass (emitting llvm SSA) - */ - -#include - -#include "core/common.h" - -namespace pyston { - -class AST_stmt; - -namespace AST_TYPE { -enum AST_TYPE; -} - -class CFG; -class CFGBlock { - private: - CFG* cfg; - public: - std::vector body; - std::vector predecessors, successors; - int idx; // index in the CFG - const char* info; - - typedef std::vector::iterator iterator; - - CFGBlock(CFG *cfg, int idx) : cfg(cfg), idx(idx), info(NULL) { - } - - void connectTo(CFGBlock *successor, bool allow_backedge=false); - - void push_back(AST_stmt* node) { - body.push_back(node); - } -}; - -// Control Flow Graph -class CFG { - private: - public: - std::vector blocks; - - CFGBlock* addBlock() { - int idx = blocks.size(); - CFGBlock* block = new CFGBlock(this, idx); - blocks.push_back(block); - - return block; - } - - CFGBlock* addDeferredBlock() { - CFGBlock* block = new CFGBlock(this, -1); - return block; - } - - void placeBlock(CFGBlock *block) { - assert(block->idx == -1); - block->idx = blocks.size(); - blocks.push_back(block); - } - - void print(); -}; - -CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector body); - - -} - -#endif diff --git a/src/core/common.h b/src/core/common.h deleted file mode 100644 index 3c215da0e..000000000 --- a/src/core/common.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_COMMON_H -#define PYSTON_CORE_COMMON_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _STRINGIFY(N) #N -#define STRINGIFY(N) _STRINGIFY(N) - -// GCC and clang handle always_inline very differently; -// we mostly only care about it for the stdlib, so just remove the attributes -// if we're not in clang -#ifdef __clang__ -#define ALWAYSINLINE __attribute__((always_inline)) -#define NOINLINE __attribute__((noinline)) -#else -#define ALWAYSINLINE -#define NOINLINE -#endif - -// From http://stackoverflow.com/questions/3767869/adding-message-to-assert, modified to use fprintf -#define RELEASE_ASSERT(condition, fmt, ...) \ -do { \ - if (! (condition)) { \ - fprintf(stderr, __FILE__ ":" STRINGIFY(__LINE__) ": %s: Assertion `" #condition "' failed: " fmt "\n", __PRETTY_FUNCTION__, ##__VA_ARGS__); \ - abort(); \ - } \ -} while (false) -#ifndef NDEBUG -# define ASSERT RELEASE_ASSERT -#else -# define ASSERT(condition, fmt, ...) do { } while (false) -#endif - -#define UNIMPLEMENTED() RELEASE_ASSERT(0, "unimplemented") - -#define OFFSET(cls, attr) ((char*)&(((cls*)0x01)->attr) - (char*)0x1) - -//#ifndef NDEBUG -//#define VALGRIND -//#endif - -// Allow using std::pair as keys in hashtables: -namespace std { - template struct hash > { - size_t operator() (const pair p) const { - return hash()(p.first) ^ (hash()(p.second) << 1); - } - }; -} - -#endif - diff --git a/src/core/options.cpp b/src/core/options.cpp deleted file mode 100644 index 9c77f5044..000000000 --- a/src/core/options.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/options.h" - -namespace pyston { - -int GLOBAL_VERBOSITY = 1; - -int PYTHON_VERSION_MAJOR = DEFAULT_PYTHON_MAJOR_VERSION; -int PYTHON_VERSION_MINOR = DEFAULT_PYTHON_MINOR_VERSION; -int PYTHON_VERSION_MICRO = DEFAULT_PYTHON_MICRO_VERSION; - -int MAX_OPT_ITERATIONS = 1; - -bool FORCE_OPTIMIZE = false; -bool SHOW_DISASM = false; -bool BENCH = false; -bool PROFILE = false; -bool DUMPJIT = false; -bool TRAP = false; -bool USE_STRIPPED_STDLIB = false; -bool ENABLE_INTERPRETER = true; - -static bool _GLOBAL_ENABLE = 1; -bool ENABLE_ICS = 1 && _GLOBAL_ENABLE; -bool ENABLE_ICGENERICS = 1 && ENABLE_ICS; -bool ENABLE_ICGETITEMS = 1 && ENABLE_ICS; -bool ENABLE_ICSETITEMS = 1 && ENABLE_ICS; -bool ENABLE_ICCALLSITES = 1 && ENABLE_ICS; -bool ENABLE_ICSETATTRS = 1 && ENABLE_ICS; -bool ENABLE_ICGETATTRS = 1 && ENABLE_ICS; -bool ENABLE_ICGETGLOBALS = 1 && ENABLE_ICS; -bool ENABLE_ICBINEXPS = 1 && ENABLE_ICS; -bool ENABLE_ICNONZEROS = 1 && ENABLE_ICS; -bool ENABLE_SPECULATION = 1 && _GLOBAL_ENABLE; -bool ENABLE_OSR = 1 && _GLOBAL_ENABLE; -bool ENABLE_LLVMOPTS = 1 && _GLOBAL_ENABLE; -bool ENABLE_INLINING = 1 && _GLOBAL_ENABLE; -bool ENABLE_REOPT = 1 && _GLOBAL_ENABLE; -bool ENABLE_PYSTON_PASSES = 1 && _GLOBAL_ENABLE; - -} diff --git a/src/core/options.h b/src/core/options.h deleted file mode 100644 index 76fe3ba93..000000000 --- a/src/core/options.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_OPTIONS_H -#define PYSTON_CORE_OPTIONS_H - -namespace pyston { - -extern "C" { - -extern int GLOBAL_VERBOSITY; -#define VERBOSITY(x) GLOBAL_VERBOSITY -// Version number we're targeting: -extern int PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO; - -extern int MAX_OPT_ITERATIONS; - -extern bool SHOW_DISASM, FORCE_OPTIMIZE, BENCH, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB, ENABLE_INTERPRETER; - -extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICBINEXPS, ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENABLE_ICGETGLOBALS, ENABLE_SPECULATION, ENABLE_OSR, ENABLE_LLVMOPTS, ENABLE_INLINING, ENABLE_REOPT, ENABLE_PYSTON_PASSES; -} - -} - -#endif diff --git a/src/core/stats.cpp b/src/core/stats.cpp deleted file mode 100644 index 32a4dde8e..000000000 --- a/src/core/stats.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/stats.h" - -namespace pyston { - -std::vector* Stats::counts; -std::unordered_map* Stats::names; -StatCounter::StatCounter(const std::string &name) : id(Stats::getStatId(name)) { -} - -int Stats::getStatId(const std::string &name) { - // hacky but easy way of getting around static constructor ordering issues for now: - static std::unordered_map names; - Stats::names = &names; - static std::vector counts; - Stats::counts = &counts; - static std::unordered_map made; - - if (made.count(name)) - return made[name]; - - int rtn = names.size(); - names[rtn] = name; - made[name] = rtn; - counts.push_back(0); - return rtn; -} - -void Stats::dump() { - printf("Stats:\n"); - - std::vector > pairs; - for (std::unordered_map::iterator it = names->begin(), end = names->end(); it != end; ++it) { - pairs.push_back(make_pair(it->second, it->first)); - } - - std::sort(pairs.begin(), pairs.end()); - - for (int i = 0; i < pairs.size(); i++) { - printf("%s: %ld\n", pairs[i].first.c_str(), (*counts)[pairs[i].second]); - } -} - -} diff --git a/src/core/stats.h b/src/core/stats.h deleted file mode 100644 index 3115646f9..000000000 --- a/src/core/stats.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_STATS_H -#define PYSTON_CORE_STATS_H - -#include -#include -#include -#include - -#include "core/options.h" - -namespace pyston { - -struct Stats { - private: - static std::vector *counts; - static std::unordered_map *names; - - public: - static int getStatId(const std::string &name); - - static void log(int id, int count=1) { - (*counts)[id] += count; - } - - static void dump(); -}; - -struct StatCounter { - private: - int id; - public: - StatCounter(const std::string &name); - - void log(int count=1) { - Stats::log(id, count); - } -}; - -} - -#endif diff --git a/src/core/types.h b/src/core/types.h deleted file mode 100644 index f6651e5cc..000000000 --- a/src/core/types.h +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_TYPES_H -#define PYSTON_CORE_TYPES_H - -// TODO while having all these defs in a single header file is an improvement -// over having them spread randomly in different files, this should probably be split again -// but in a way that makes more sense. - -#include "core/common.h" -#include "core/stats.h" - -namespace llvm { -class Function; -class Type; -class Value; -} - -namespace pyston { - -class GCVisitor { - public: - virtual void visit(void* p) = 0; - virtual void visitRange(void** start, void** end) = 0; - virtual void visitPotential(void* p) = 0; - virtual void visitPotentialRange(void** start, void** end) = 0; -}; - -typedef int kindid_t; -class AllocationKind; -extern "C" kindid_t registerKind(const AllocationKind*); -class AllocationKind { - public: -#ifndef NDEBUG - static const int64_t COOKIE = 0x1234abcd0c00c1e; - const int64_t _cookie = COOKIE; -#endif - - typedef void (*GCHandler)(GCVisitor*, void*); - GCHandler gc_handler; - - typedef void (*FinalizationFunc)(void*); - FinalizationFunc finalizer; - - const kindid_t kind_id; - - public: - AllocationKind(GCHandler gc_handler, FinalizationFunc finalizer) __attribute__((visibility("default"))) : - gc_handler(gc_handler), finalizer(finalizer), kind_id(registerKind(this)) { - } -}; -extern "C" const AllocationKind untracked_kind, conservative_kind; - -class ObjectFlavor; -extern "C" const ObjectFlavor user_flavor; -class ObjectFlavor : public AllocationKind { - public: - bool isUserDefined() const { - return this == &user_flavor; - } - - ObjectFlavor(GCHandler gc_handler, FinalizationFunc finalizer) __attribute__((visibility("default"))) : - AllocationKind(gc_handler, finalizer) { - } -}; - - - -namespace EffortLevel { -enum EffortLevel { - INTERPRETED = 0, - MINIMAL, - MODERATE, - MAXIMAL, -}; -} - -template class ValuedCompilerType; -typedef ValuedCompilerType ConcreteCompilerType; - -class CompilerVariable; -template class ValuedCompilerVariable; -typedef ValuedCompilerVariable ConcreteCompilerVariable; - -class Box; -class BoxedClass; -class BoxedModule; -class BoxedFunction; - -class ICGetattr; -class ICSlotInfo; - -class CFG; -class AST; -class AST_FunctionDef; -class AST_arguments; -class AST_expr; -class AST_stmt; - -class PhiAnalysis; -class LivenessAnalysis; -class ScopingAnalysis; - -class CLFunction; -class OSREntryDescriptor; - -class ICInvalidator { - private: - int64_t cur_version; - std::unordered_set dependents; - public: - ICInvalidator() : cur_version(0) {} - - void addDependent(ICSlotInfo* icentry); - int64_t version(); - void invalidateAll(); -}; - -// Codegen types: - -struct FunctionSignature { - ConcreteCompilerType *rtn_type; - std::vector arg_types; - bool is_vararg; - - FunctionSignature(ConcreteCompilerType *rtn_type, bool is_vararg) : rtn_type(rtn_type), is_vararg(is_vararg) { - } - - FunctionSignature(ConcreteCompilerType *rtn_type, ConcreteCompilerType *arg1, ConcreteCompilerType *arg2, bool is_vararg) : rtn_type(rtn_type), is_vararg(is_vararg) { - arg_types.push_back(arg1); - arg_types.push_back(arg2); - } - - FunctionSignature(ConcreteCompilerType *rtn_type, std::vector &arg_types, bool is_vararg) : rtn_type(rtn_type), arg_types(arg_types), is_vararg(is_vararg) { - } -}; - -struct CompiledFunction { - private: - public: - CLFunction *clfunc; - llvm::Function *func; // the llvm IR object - FunctionSignature *sig; - const OSREntryDescriptor *entry_descriptor; - bool is_interpreted; - - union { - Box* (*call)(Box*, Box*, Box*, Box**); - void* code; - }; - llvm::Value *llvm_code; // the llvm callable. - - EffortLevel::EffortLevel effort; - - int64_t times_called; - ICInvalidator dependent_callsites; - - CompiledFunction(llvm::Function *func, FunctionSignature *sig, bool is_interpreted, void* code, llvm::Value *llvm_code, EffortLevel::EffortLevel effort, const OSREntryDescriptor* entry_descriptor) : - clfunc(NULL), func(func), sig(sig), entry_descriptor(entry_descriptor), is_interpreted(is_interpreted), code(code), llvm_code(llvm_code), effort(effort), times_called(0) { - } -}; - -class BoxedModule; -class SourceInfo { - public: - BoxedModule *parent_module; - ScopingAnalysis *scoping; - AST *ast; - CFG *cfg; - LivenessAnalysis *liveness; - PhiAnalysis *phis; - - const std::string getName(); - AST_arguments* getArgsAST(); - const std::vector& getArgNames(); - const std::vector& getBody(); - - SourceInfo(BoxedModule* m, ScopingAnalysis *scoping) : parent_module(m), scoping(scoping), - ast(NULL), cfg(NULL), liveness(NULL), phis(NULL) {} -}; -typedef std::vector FunctionList; -struct CLFunction { - SourceInfo *source; - FunctionList versions; // any compiled versions along with their type parameters; in order from most preferred to least - std::unordered_map osr_versions; - - CLFunction(SourceInfo *source) : source(source) { - } - - void addVersion(CompiledFunction *compiled) { - assert(compiled); - assert((source == NULL) == (compiled->func == NULL)); - assert(compiled->sig); - assert(compiled->clfunc == NULL); - assert(compiled->is_interpreted == (compiled->code == NULL)); - assert(compiled->is_interpreted == (compiled->llvm_code == NULL)); - compiled->clfunc = this; - if (compiled->entry_descriptor == NULL) - versions.push_back(compiled); - else - osr_versions[compiled->entry_descriptor] = compiled; - } -}; - -extern "C" CLFunction* createRTFunction(); -extern "C" CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg); -void addRTFunction(CLFunction *cf, void* f, ConcreteCompilerType* rtn_type, int nargs, bool is_vararg); -void addRTFunction(CLFunction *cf, void* f, ConcreteCompilerType* rtn_type, const std::vector &arg_types, bool is_vararg); -CLFunction* unboxRTFunction(Box*); -//extern "C" CLFunction* boxRTFunctionVariadic(const char* name, int nargs_min, int nargs_max, void* f); -extern "C" CompiledFunction* resolveCLFunc(CLFunction *f, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); -extern "C" Box* callCompiledFunc(CompiledFunction *cf, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args); - -std::string getOpName(int op_type); -std::string getOpSymbol(int op_type); -std::string getReverseOpName(int op_type); - -typedef bool i1; -typedef int64_t i64; - -extern "C" void* rt_alloc(size_t); -extern "C" void rt_free(void*); - -extern "C" const std::string* getNameOfClass(BoxedClass* cls); - -class Rewriter; -class RewriterVar; - -struct GCObjectHeader { - kindid_t kind_id; - uint16_t kind_data; // this part of the header is free for the kind to set as it wishes. - uint8_t gc_flags; - - constexpr GCObjectHeader(const AllocationKind *kind) : kind_id(kind->kind_id), kind_data(0), gc_flags(0) {} -}; -static_assert(sizeof(GCObjectHeader) <= sizeof(void*), ""); - -class GCObject { - public: - GCObjectHeader gc_header; - - constexpr GCObject(const AllocationKind *kind) : gc_header(kind) { - } - - void* operator new(size_t size) __attribute__((visibility("default"))) { - return rt_alloc(size); - } - void operator delete(void* ptr) __attribute__((visibility("default"))) { - rt_free(ptr); - } -}; - -extern "C" const AllocationKind hc_kind; -class HiddenClass : public GCObject { - private: - HiddenClass() : GCObject(&hc_kind) {} - HiddenClass(const HiddenClass* parent) : GCObject(&hc_kind), attr_offsets(parent->attr_offsets) {} - public: - static HiddenClass* getRoot(); - std::unordered_map attr_offsets; - std::unordered_map children; - - HiddenClass* getOrMakeChild(const std::string &attr); - - int getOffset(const std::string& attr) { - std::unordered_map::iterator it = attr_offsets.find(attr); - if (it == attr_offsets.end()) - return -1; - return it->second; - } -}; - -extern bool TRACK_ALLOCATIONS; -class Box : public GCObject { - public: - BoxedClass *cls; - - constexpr Box(const ObjectFlavor *flavor, BoxedClass *c) __attribute__((visibility("default"))) : GCObject(flavor), cls(c) { - //if (TRACK_ALLOCATIONS) { - //int id = Stats::getStatId("allocated_" + *getNameOfClass(c)); - //Stats::log(id); - //} - } - -}; - - -class SetattrRewriteArgs; -class SetattrRewriteArgs2; -class GetattrRewriteArgs; -class GetattrRewriteArgs2; -// I expect that most things will end up being represented by HCBox's rather than boxes, -// but I'm not putting these into Box so that things that don't have any python-level instance -// attributes (ex: integers) don't need to allocate the extra space. -class HCBox : public Box { - public: - struct AttrList : GCObject { - Box* attrs[0]; - }; - - HiddenClass *hcls; - // Python-level attributes: - AttrList *attr_list; - - HCBox(const ObjectFlavor *flavor, BoxedClass *cls); - - void setattr(const std::string &attr, Box* val, SetattrRewriteArgs* rewrite_args, SetattrRewriteArgs2 *rewrite_args2); - void giveAttr(const std::string &attr, Box* val); - Box* getattr(const std::string &attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2); - Box* peekattr(const std::string &attr) { - int offset = hcls->getOffset(attr); - if (offset == -1) return NULL; - return attr_list->attrs[offset]; - } -}; - -class BoxedClass : public HCBox { - public: - // This first typedef is right, but clang miscompiles it (how??), so use the second one: - //typedef void (*Dtor)(Box*); - typedef void* Dtor; - - // whether or not instances of this class are subclasses of HCBox, - // ie they have python-level instance attributes: - const bool hasattrs; - - // compiler-level (cf python-level) destructor, that does things like decrementing - // refcounts of any attributes - const Dtor dtor; - - // Whether this class object is constant or not. - // Does not necessarily imply that the instances of this class are constant, - // though for now (is_constant && !hasattrs) does imply that the instances are constant. - bool is_constant; - - // If the user sets __getattribute__ or __getattr__, we will have to invalidate - // all getattr IC entries that relied on the fact that those functions didn't exist. - // Doing this via invalidation means that instance attr lookups don't have - // to guard on anything about the class. - ICInvalidator dependent_icgetattrs; - - BoxedClass(bool hasattrs, Dtor dtor); - void freeze() { - assert(!is_constant); - is_constant = true; - } -}; - -// TODO these shouldn't be here -void setupRuntime(); -void teardownRuntime(); -extern "C" BoxedModule* createModule(const std::string *name, const std::string *fn); - -std::string getPythonFuncAt(void* ip, void* sp); - -} - -#endif diff --git a/src/core/util.cpp b/src/core/util.cpp deleted file mode 100644 index 7cf1e0251..000000000 --- a/src/core/util.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormattedStream.h" - -#include "core/common.h" -#include "core/options.h" - -#include "core/util.h" - -namespace pyston { - -int Timer::level = 0; -Timer::Timer(const char* desc, int min_usec) : min_usec(min_usec), ended(true) { - restart(desc); -} - -void Timer::restart(const char* newdesc, int min_usec) { - assert(ended); - - desc = newdesc; - this->min_usec = min_usec; - gettimeofday(&start_time, NULL); - Timer::level++; - ended = false; -} - -long Timer::end() { - if (!ended) { - timeval end; - gettimeofday(&end, NULL); - long us = 1000000L * (end.tv_sec - start_time.tv_sec) + (end.tv_usec - start_time.tv_usec); - - Timer::level--; - if (VERBOSITY("time") >= 1) { - if (us > min_usec) { - for (int i = 0; i < Timer::level; i++) { - putchar(' '); - } - printf("\033[32m"); - if (us < 1000) { - printf("%ldus %s\n", us, desc); - } else if (us < 1000000) { - printf("%.1fms %s\n", us / 1000.0, desc); - } else { - printf("%.2fs %s\n", us / 1000000.0, desc); - } - printf("\033[0m"); - fflush(stdout); - } - } - ended = true; - return us; - } - return -1; -} - -Timer::~Timer() { - end(); -} - -bool startswith(const std::string &s, const std::string &pattern) { - if (s.size() == 0) - return pattern.size() == 0; - return s.compare(0, pattern.size(), pattern) == 0; -} - -void removeDirectoryIfExists(const std::string& path) { - llvm::error_code code; - - llvm::sys::fs::file_status status; - code = llvm::sys::fs::status(path, status); - if (!llvm::sys::fs::exists(status)) - return; - - assert(llvm::sys::fs::is_directory(status)); - - llvm::sys::fs::directory_iterator it(path, code), end; - assert(!code); - - while (it != end) { - code = it->status(status); - assert(!code); - - if (llvm::sys::fs::is_directory(status)) { - removeDirectoryIfExists(it->path()); - } else { - llvm::errs() << "Removing file " << it->path() << '\n'; - code = llvm::sys::fs::remove(it->path(), false); - assert(!code); - } - - it = it.increment(code); - assert(!code); - } - - llvm::errs() << "Removing directory " << path << '\n'; - code = llvm::sys::fs::remove(path, false); - assert(!code); -} - -} diff --git a/src/core/util.h b/src/core/util.h deleted file mode 100644 index 7ffa75595..000000000 --- a/src/core/util.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_CORE_UTIL_H -#define PYSTON_CORE_UTIL_H - -#include - -#include -#include - -namespace pyston { - -class Timer { - private: - static int level; - timeval start_time; - const char* desc; - int min_usec; - bool ended; - public: - Timer(const char* desc, int min_usec=-1); - ~Timer(); - - void restart(const char* newdesc, int min_usec=-1); - long end(); - long split(const char* newdesc, int min_usec=-1) { - long rtn = end(); - restart(newdesc, min_usec); - return rtn; - } -}; - -bool startswith(const std::string &s, const std::string &pattern); - -void removeDirectoryIfExists(const std::string& path); - -template -void compareKeyset(T1 *lhs, T2 *rhs) { - std::vector lv, rv; - for (typename T1::iterator it = lhs->begin(); it != lhs->end(); it++) { - lv.push_back(it->first); - } - for (typename T2::iterator it = rhs->begin(); it != rhs->end(); it++) { - rv.push_back(it->first); - } - - std::sort(lv.begin(), lv.end()); - std::sort(rv.begin(), rv.end()); - - std::vector lextra(lv.size()); - std::vector::iterator diffend = std::set_difference(lv.begin(), lv.end(), rv.begin(), rv.end(), lextra.begin()); - lextra.resize(diffend - lextra.begin()); - - bool good = true; - if (lextra.size()) { - printf("Only in lhs:\n"); - for (int i = 0; i < lextra.size(); i++) { - printf("%s\n", lextra[i].c_str()); - } - good = false; - } - - std::vector rextra(rv.size()); - diffend = std::set_difference(rv.begin(), rv.end(), lv.begin(), lv.end(), rextra.begin()); - rextra.resize(diffend - rextra.begin()); - - if (rextra.size()) { - printf("Only in rhs:\n"); - for (int i = 0; i < rextra.size(); i++) { - printf("%s\n", rextra[i].c_str()); - } - good = false; - } - assert(good); -} - -} - -#endif diff --git a/src/gc/collector.cpp b/src/gc/collector.cpp deleted file mode 100644 index ec55afec2..000000000 --- a/src/gc/collector.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#define UNW_LOCAL_ONLY -#include - -#include "core/common.h" -#include "core/types.h" - -#include "codegen/codegen.h" - -#include "gc/collector.h" -#include "gc/heap.h" -#include "gc/root_finder.h" - -namespace pyston { -namespace gc { - -//unsigned numAllocs = 0; -unsigned bytesAllocatedSinceCollection = 0; - -static TraceStack roots; -void registerStaticRootObj(void* obj) { - assert(global_heap.getAllocationFromInteriorPointer(obj)); - roots.push(obj); -} - -bool TraceStackGCVisitor::isValid(void* p) { - return global_heap.getAllocationFromInteriorPointer(p); -} - -inline void TraceStackGCVisitor::_visit(void* p) { - assert(isValid(p)); - stack->push(p); -} - -void TraceStackGCVisitor::visit(void* p) { - _visit(p); -} - -void TraceStackGCVisitor::visitRange(void** start, void** end) { - while (start < end) { - _visit(*start); - start++; - } -} - -void TraceStackGCVisitor::visitPotential(void* p) { - void* a = global_heap.getAllocationFromInteriorPointer(p); - if (a) { - visit(a); - } -} - -void TraceStackGCVisitor::visitPotentialRange(void** start, void** end) { - while (start < end) { - visitPotential(*start); - start++; - } -} - -#define MAX_KINDS 1024 -#define KIND_OFFSET 0x111 -static kindid_t num_kinds = 0; -static AllocationKind::GCHandler handlers[MAX_KINDS]; - -extern "C" kindid_t registerKind(const AllocationKind *kind) { - assert(kind == &untracked_kind || kind->gc_handler); - assert(num_kinds < MAX_KINDS); - assert(handlers[num_kinds] == NULL); - handlers[num_kinds] = kind->gc_handler; - return KIND_OFFSET + num_kinds++; -} - -static void markPhase() { - TraceStack stack(roots); - collectStackRoots(&stack); - - TraceStackGCVisitor visitor(&stack); - - //if (VERBOSITY()) printf("Found %d roots\n", stack.size()); - while (void* p = stack.pop()) { - assert(((intptr_t)p) % 8 == 0); - GCObjectHeader* header = headerFromObject(p); - //printf("%p\n", p); - - if (isMarked(header)) { - //printf("Already marked, skipping\n"); - continue; - } - - //printf("Marking + scanning %p\n", p); - - setMark(header); - - ASSERT(KIND_OFFSET <= header->kind_id && header->kind_id < KIND_OFFSET + num_kinds, "%p %d", header, header->kind_id); - - if (header->kind_id == untracked_kind.kind_id) - continue; - - //ASSERT(kind->_cookie == AllocationKind::COOKIE, "%lx %lx", kind->_cookie, AllocationKind::COOKIE); - //AllocationKind::GCHandler gcf = kind->gc_handler; - AllocationKind::GCHandler gcf = handlers[header->kind_id - KIND_OFFSET]; - - assert(gcf); - //if (!gcf) { - //std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)kind, true); - //ASSERT(gcf, "%p %s", kind, name.c_str()); - //} - - gcf(&visitor, p); - - } -} - -static void sweepPhase() { - global_heap.freeUnmarked(); -} - -static int ncollections = 0; -void runCollection() { - static StatCounter sc("gc_collections"); - sc.log(); - - if (VERBOSITY("gc") >= 2) printf("Collection #%d\n", ++ncollections); - - //if (ncollections == 754) { - //raise(SIGTRAP); - //} - - markPhase(); - sweepPhase(); -} - -} // namespace gc -} // namespace pyston diff --git a/src/gc/collector.h b/src/gc/collector.h deleted file mode 100644 index 56d853696..000000000 --- a/src/gc/collector.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_GC_COLLECTOR_H -#define PYSTON_GC_COLLECTOR_H - -#include - -#include "core/types.h" - -namespace pyston { -namespace gc { - -#define MARK_BIT 0x1 - -inline GCObjectHeader* headerFromObject(void* obj) { - return static_cast(obj); -} - -inline void setMark(GCObjectHeader *header) { - header->gc_flags |= MARK_BIT; -} - -inline void clearMark(GCObjectHeader *header) { - header->gc_flags &= ~MARK_BIT; -} - -inline bool isMarked(GCObjectHeader *header) { - return (header->gc_flags & MARK_BIT) != 0; -} - -#undef MARK_BIT - -class TraceStack { - private: - std::vector v; - - public: - void push(void* p) { - v.push_back(p); - } - - int size() { - return v.size(); - } - - void* pop() { - if (v.size()) { - void* r = v.back(); - v.pop_back(); - return r; - } - return NULL; - } -}; - -class TraceStackGCVisitor : public GCVisitor { - private: - bool isValid(void* p); - - void _visit(void* p); - public: - TraceStack *stack; - constexpr TraceStackGCVisitor(TraceStack *stack) : stack(stack) {} - - void visit(void* p) override; - void visitRange(void** start, void** end) override; - void visitPotential(void* p) override; - void visitPotentialRange(void** start, void** end) override; -}; - -// Call it a "root obj" because this function takes the pointer to the object, not a pointer -// to a storage location where we might store different objects. -// ie this only works for constant roots, and not out-of-gc-knowledge storage locations -// (that should be registerStaticRootPtr) -void registerStaticRootObj(void* root_obj); -void runCollection(); - -} -} - -#endif diff --git a/src/gc/gc_alloc.h b/src/gc/gc_alloc.h deleted file mode 100644 index 0542a0e56..000000000 --- a/src/gc/gc_alloc.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_GC_GCALLOC_H -#define PYSTON_GC_GCALLOC_H - -#include - -#include "gc/heap.h" -#include "gc/collector.h" - -namespace pyston { -namespace gc { - -inline void* gc_alloc(size_t bytes) __attribute__((visibility("default"))); -inline void* gc_alloc(size_t bytes) { - //if ((++numAllocs) >= ALLOCS_PER_COLLECTION) { - //numAllocs = 0; - //runCollection(); - //} - - void* r = global_heap.alloc(bytes); - -#ifndef NDEBUG - // I think I have a suspicion: the gc will see the constant and treat it as a - // root. So instead, shift to hide the pointer - //if ((((intptr_t)r) >> 4) == (0x127001424L)) { - //if ((((intptr_t)r) >> 4) == (0x127000718L)) { - //raise(SIGTRAP); - //} - - //if (VERBOSITY()) printf("Allocated: %p\n", r); -#endif - - return r; -} - -inline void* gc_realloc(void* ptr, size_t bytes) __attribute__((visibility("default"))); -inline void* gc_realloc(void* ptr, size_t bytes) { - return global_heap.realloc(ptr, bytes); -} - -inline void gc_free(void* ptr) __attribute__((visibility("default"))); -inline void gc_free(void* ptr) { - global_heap.free(ptr); -} - -} -} - -#endif diff --git a/src/gc/heap.cpp b/src/gc/heap.cpp deleted file mode 100644 index 9b0f58b76..000000000 --- a/src/gc/heap.cpp +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include "valgrind.h" - -#include "gc/gc_alloc.h" - -#include "core/common.h" - -namespace pyston { -namespace gc { - -//extern unsigned numAllocs; -//#define ALLOCS_PER_COLLECTION 1000 -extern unsigned bytesAllocatedSinceCollection; -#define ALLOCBYTES_PER_COLLECTION 2000000 - -void _collectIfNeeded(size_t bytes) { - if (bytesAllocatedSinceCollection >= ALLOCBYTES_PER_COLLECTION) { - bytesAllocatedSinceCollection = 0; - runCollection(); - } - bytesAllocatedSinceCollection += bytes; -} - - -Heap global_heap; - -#define PAGE_SIZE 4096 -class Arena { - private: - void* start; - void* cur; - - public: - constexpr Arena(void* start) : start(start), cur(start) { - } - - void* doMmap(size_t size) { - assert(size % PAGE_SIZE == 0); - //printf("mmap %ld\n", size); - - void* mrtn = mmap(cur, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - assert((uintptr_t)mrtn != -1 && "failed to allocate memory from OS"); - ASSERT(mrtn == cur, "%p %p\n", mrtn, cur); - cur = (uint8_t*)cur + size; - return mrtn; - } - - bool contains(void* addr) { - return start <= addr && addr < cur; - } -}; - -Arena small_arena((void*)0x1270000000L); -Arena large_arena((void*)0x2270000000L); - -struct LargeObj { - LargeObj *next, **prev; - size_t obj_size; - char data[0]; - - int mmap_size() { - size_t total_size = obj_size + sizeof(LargeObj); - total_size = (total_size + PAGE_SIZE - 1) & ~(PAGE_SIZE-1); - return total_size; - } - - int capacity() { - return mmap_size() - sizeof(LargeObj); - } - - static LargeObj* fromPointer(void* ptr) { - char* rtn = (char*)ptr + ((char*)NULL - ((LargeObj*)(NULL))->data); - assert((uintptr_t)rtn % PAGE_SIZE == 0); - return reinterpret_cast(rtn); - } -}; - -void* Heap::allocLarge(size_t size) { - _collectIfNeeded(size); - - size_t total_size = size + sizeof(LargeObj); - total_size = (total_size + PAGE_SIZE - 1) & ~(PAGE_SIZE-1); - LargeObj* rtn = (LargeObj*)large_arena.doMmap(total_size); - rtn->obj_size = size; - - rtn->next = large_head; - if (rtn->next) - rtn->next->prev = &rtn->next; - rtn->prev = &large_head; - large_head = rtn; - - return &rtn->data; -} - -static Block* alloc_block(uint64_t size, Block** prev) { - // TODO use mmap - - Block* rtn = (Block*)small_arena.doMmap(sizeof(Block)); - assert(rtn); - rtn->size = size; - rtn->prev = prev; - rtn->next = NULL; - -#ifdef VALGRIND - VALGRIND_CREATE_MEMPOOL(rtn, 0, true); -#endif - - // Don't think I need to do this: - memset(rtn->isfree, 0, sizeof(Block::isfree)); - - int num_objects = rtn->numObjects(); - int num_lost = rtn->minObjIndex(); - int atoms_per_object = rtn->atomsPerObj(); - for (int i = num_lost * atoms_per_object; i < num_objects * atoms_per_object; i += atoms_per_object) { - int idx = i / 64; - int bit = i % 64; - rtn->isfree[idx] ^= (1L << bit); - //printf("%d %d\n", idx, bit); - } - - //printf("%d %d %d\n", num_objects, num_lost, atoms_per_object); - //for (int i =0; i < BITFIELD_ELTS; i++) { - //printf("%d: %lx\n", i, rtn->isfree[i]); - //} - return rtn; -} - -void* Heap::allocSmall(size_t rounded_size, Block** prev, Block** full_head) { - _collectIfNeeded(rounded_size); - - Block *cur = *prev; - assert(!cur || prev == cur->prev); - int scanned = 0; - - //printf("alloc(%ld)\n", rounded_size); - - //Block **full_prev = full_head; - while (true) { - //printf("cur = %p, prev = %p\n", cur, prev); - if (cur == NULL) { - Block *next = alloc_block(rounded_size, &cur->next); - //printf("allocated new block %p\n", next); - *prev = next; - next->prev = prev; - prev = &cur->next; - - next->next = *full_head; - *full_head = NULL; - prev = full_head; - - cur = next; - } - - int i = 0; - uint64_t mask = 0; - for (; i < BITFIELD_ELTS; i++) { - mask = cur->isfree[i]; - if (mask != 0L) { - break; - } - } - - if (i == BITFIELD_ELTS) { - scanned++; - //printf("moving on\n"); - - Block *t = *prev = cur->next; - cur->next = NULL; - if (t) t->prev = prev; - - cur->prev = full_head; - cur->next = *full_head; - *full_head = cur; - - cur = t; - - scanned++; - continue; - } - - //printf("scanned %d\n", scanned); - int first = __builtin_ctzll(mask); - assert(first < 64); - //printf("mask: %lx, first: %d\n", mask, first); - cur->isfree[i] ^= (1L << first); - - int idx = first + i * 64; - - //printf("Using index %d\n", idx); - - void* rtn = &cur->atoms[idx]; - -#ifndef NDEBUG - Block *b = Block::forPointer(rtn); - assert(b == cur); - int offset = (char*)rtn - (char*)b; - assert(offset % rounded_size == 0); -#endif - -#ifdef VALGRIND - VALGRIND_MEMPOOL_ALLOC(cur, rtn, rounded_size); -#endif - - return rtn; - } -} - -void _freeFrom(void* ptr, Block* b) { - assert(b == Block::forPointer(ptr)); - - size_t size = b->size; - int offset = (char*)ptr - (char*)b; - assert(offset % size == 0); - int atom_idx = offset / ATOM_SIZE; - - int bitmap_idx = atom_idx / 64; - int bitmap_bit = atom_idx % 64; - uint64_t mask = 1L << bitmap_bit; - assert((b->isfree[bitmap_idx] & mask) == 0); - b->isfree[bitmap_idx] ^= mask; - -#ifdef VALGRIND - VALGRIND_MEMPOOL_FREE(b, ptr); -#endif -} - -static void _freeLargeObj(LargeObj *lobj) { - *lobj->prev = lobj->next; - if (lobj->next) - lobj->next->prev = lobj->prev; - - int r = munmap(lobj, lobj->mmap_size()); - assert(r == 0); -} - -void Heap::free(void* ptr) { - if (large_arena.contains(ptr)) { - LargeObj *lobj = LargeObj::fromPointer(ptr); - _freeLargeObj(lobj); - return; - } - - assert(small_arena.contains(ptr)); - Block *b = Block::forPointer(ptr); - _freeFrom(ptr, b); -} - -void* Heap::realloc(void* ptr, size_t bytes) { - if (large_arena.contains(ptr)) { - LargeObj *lobj = LargeObj::fromPointer(ptr); - - int capacity = lobj->capacity(); - if (capacity >= bytes && capacity < bytes * 2) - return ptr; - - void* rtn = alloc(bytes); - memcpy(rtn, ptr, std::min(bytes, lobj->obj_size)); - - _freeLargeObj(lobj); - return rtn; - } - - assert(small_arena.contains(ptr)); - Block *b = Block::forPointer(ptr); - - size_t size = b->size; - - if (size >= bytes && size < bytes * 2) - return ptr; - - void* rtn = alloc(bytes); - - memcpy(rtn, ptr, std::min(bytes, size)); - - _freeFrom(ptr, b); - return rtn; -} - -void* Heap::getAllocationFromInteriorPointer(void* ptr) { - if (large_arena.contains(ptr)) { - LargeObj *cur = large_head; - while (cur) { - if (ptr >= cur && ptr < &cur->data[cur->obj_size]) - return &cur->data[0]; - cur = cur->next; - } - return NULL; - } - - if (!small_arena.contains(ptr)) - return NULL; - - Block *b = Block::forPointer(ptr); - size_t size = b->size; - int offset = (char*)ptr - (char*)b; - int obj_idx = offset / size; - - if (obj_idx < b->minObjIndex() || obj_idx >= b->numObjects()) - return NULL; - - int atom_idx = obj_idx * (size / ATOM_SIZE); - - int bitmap_idx = atom_idx / 64; - int bitmap_bit = atom_idx % 64; - uint64_t mask = 1L << bitmap_bit; - if (b->isfree[bitmap_idx] & mask) - return NULL; - - return &b->atoms[atom_idx]; -} - -static long freeChain(Block* head) { - long bytes_freed = 0; - while (head) { - int num_objects = head->numObjects(); - int first_obj = head->minObjIndex(); - int atoms_per_obj = head->atomsPerObj(); - - for (int obj_idx = first_obj; obj_idx < num_objects; obj_idx++) { - int atom_idx = obj_idx * atoms_per_obj; - int bitmap_idx = atom_idx / 64; - int bitmap_bit = atom_idx % 64; - uint64_t mask = 1L << bitmap_bit; - - if (head->isfree[bitmap_idx] & mask) - continue; - - void *p = &head->atoms[atom_idx]; - GCObjectHeader* header = headerFromObject(p); - - if (isMarked(header)) { - clearMark(header); - } else { - if (VERBOSITY() >= 2) printf("Freeing %p\n", p); - //assert(p != (void*)0x127000d960); // the main module - bytes_freed += head->size; - head->isfree[bitmap_idx] |= mask; - } - } - - head = head->next; - } - return bytes_freed; -} - -void Heap::freeUnmarked() { - long bytes_freed = 0; - for (int bidx = 0; bidx < NUM_BUCKETS; bidx++) { - bytes_freed += freeChain(heads[bidx]); - bytes_freed += freeChain(full_heads[bidx]); - } - - LargeObj *cur = large_head; - while (cur) { - void *p = cur->data; - GCObjectHeader* header = headerFromObject(p); - if (isMarked(header)) { - clearMark(header); - } else { - if (VERBOSITY() >= 2) printf("Freeing %p\n", p); - bytes_freed += cur->mmap_size(); - - *cur->prev = cur->next; - if (cur->next) cur->next->prev = cur->prev; - - LargeObj *to_free = cur; - cur = cur->next; - _freeLargeObj(to_free); - continue; - } - - cur = cur->next; - } - - if (VERBOSITY("gc") >= 2) if (bytes_freed) printf("Freed %ld bytes\n", bytes_freed); -} - -} -} diff --git a/src/gc/heap.h b/src/gc/heap.h deleted file mode 100644 index 4b4560409..000000000 --- a/src/gc/heap.h +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_GC_HEAP_H -#define PYSTON_GC_HEAP_H - -#include - -#include "core/common.h" - -namespace pyston { -namespace gc { - -#define BLOCK_SIZE 4096 -#define ATOM_SIZE 16 -static_assert(BLOCK_SIZE % ATOM_SIZE == 0, ""); -#define ATOMS_PER_BLOCK (BLOCK_SIZE / ATOM_SIZE) -static_assert(ATOMS_PER_BLOCK % 64 == 0, ""); -#define BITFIELD_SIZE (ATOMS_PER_BLOCK / 8) -#define BITFIELD_ELTS (BITFIELD_SIZE / 8) - -#define BLOCK_HEADER_SIZE (BITFIELD_SIZE + 2 * sizeof(void*) + sizeof(uint64_t)) -#define BLOCK_HEADER_ATOMS ((BLOCK_HEADER_SIZE + ATOM_SIZE - 1) / ATOM_SIZE) - -struct Atoms { - char _data[ATOM_SIZE]; -}; - -struct Block { - union { - struct { - Block *next, **prev; - uint64_t size; - uint64_t isfree[BITFIELD_ELTS]; - }; - Atoms atoms[ATOMS_PER_BLOCK]; - }; - - inline int minObjIndex() { - return (BLOCK_HEADER_SIZE + size - 1) / size; - } - - inline int numObjects() { - return BLOCK_SIZE / size; - } - - inline int atomsPerObj() { - return size / ATOM_SIZE; - } - - static Block* forPointer(void* ptr) { - return (Block*)((uintptr_t)ptr & ~(BLOCK_SIZE-1)); - } -}; -static_assert(sizeof(Block) == BLOCK_SIZE, "bad size"); - -constexpr const size_t sizes[] = { - 16, 32, 48, 64, - 80, 96, 112, 128, - 160, 192, 224, 256, - 320, 384, 448, 512, - 640, 768, 896, 1024, - 1280, 1536, 1792, 2048, - //2560, 3072, 3584, // 4096, -}; -#define NUM_BUCKETS (sizeof(sizes) / sizeof(sizes[0])) - -class LargeObj; -class Heap { - private: - Block* heads[NUM_BUCKETS]; - Block* full_heads[NUM_BUCKETS]; - LargeObj *large_head = NULL; - - void* allocSmall(size_t rounded_size, Block **head, Block **full_head); - void* allocLarge(size_t bytes); - - public: - void* realloc(void* ptr, size_t bytes); - - void* alloc(size_t bytes) { - //assert(bytes >= 16); - if (bytes == 16) - return allocSmall(16, &heads[0], &full_heads[0]); - if (bytes <= 32) - return allocSmall(32, &heads[1], &full_heads[1]); - - if (bytes > sizes[NUM_BUCKETS-1]) { - return allocLarge(bytes); - } - - for (int i = 2; i < NUM_BUCKETS; i++) { - if (sizes[i] >= bytes) { - return allocSmall(sizes[i], &heads[i], &full_heads[i]); - } - } - - //unreachable - abort(); - } - - void free(void* ptr); - - void* getAllocationFromInteriorPointer(void* ptr); - void freeUnmarked(); -}; - -extern Heap global_heap; - -} // namespace gc -} // namespace pyston - -#endif diff --git a/src/gc/root_finder.cpp b/src/gc/root_finder.cpp deleted file mode 100644 index 5d3dd562c..000000000 --- a/src/gc/root_finder.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define UNW_LOCAL_ONLY -#include - -#include -#include -#include -#include -#include - -#include "core/common.h" - -#include "codegen/codegen.h" -#include "codegen/llvm_interpreter.h" - -#include "gc/collector.h" -#include "gc/heap.h" -#include "gc/root_finder.h" - -extern "C" void __libc_start_main(); - -namespace pyston { -namespace gc { - -void collectRoots(void* start, void* end, TraceStack* stack) { - assert(start <= end); - - void** cur = (void**)start; - while (cur < end) { - void* p = global_heap.getAllocationFromInteriorPointer(*cur); - if (p) - stack->push(p); - cur++; - } -} - -void collectStackRoots(TraceStack *stack) { - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t ip, sp, bp; - - // force callee-save registers onto the stack: - // Actually, I feel like this is pretty brittle: - // collectStackRoots itself is allowed to save the callee-save registers - // on its own stack. - jmp_buf registers __attribute__((aligned(sizeof(void*)))); -#ifdef VALGRIND - memset(®isters, 0, sizeof(registers)); - memset(&cursor, 0, sizeof(cursor)); - memset(&uc, 0, sizeof(uc)); - memset(&ip, 0, sizeof(ip)); - memset(&sp, 0, sizeof(sp)); - memset(&bp, 0, sizeof(bp)); -#endif - setjmp(registers); - - assert(sizeof(registers) % 8 == 0); - //void* stack_bottom = __builtin_frame_address(0); - collectRoots(®isters, ®isters + 1, stack); - - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - - TraceStackGCVisitor visitor(stack); - - int code; - while (true) { - int code = unw_step(&cursor); - assert(code > 0 && "something broke unwinding!"); - - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - unw_get_reg(&cursor, UNW_TDEP_BP, &bp); - - void* cur_sp = (void*)sp; - void* cur_bp = (void*)bp; - - //std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)ip, true); - //if (VERBOSITY()) printf("ip = %lx (%s), stack = [%p, %p)\n", (long) ip, name.c_str(), cur_sp, cur_bp); - - unw_proc_info_t pip; - unw_get_proc_info(&cursor, &pip); - - if (pip.start_ip == (uintptr_t)&__libc_start_main) { - break; - } - - if (pip.start_ip == (intptr_t)interpretFunction) { - // TODO Do we still need to crawl the interpreter itself? - gatherInterpreterRootsForFrame(&visitor, cur_bp); - } - - collectRoots(cur_sp, (char*)cur_bp, stack); - } -} - -} -} diff --git a/src/gc/root_finder.h b/src/gc/root_finder.h deleted file mode 100644 index 452b7dc70..000000000 --- a/src/gc/root_finder.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_GC_ROOTFINDER_H -#define PYSTON_GC_ROOTFINDER_H - -namespace pyston { -namespace gc { - -class TraceStack; -void collectStackRoots(TraceStack*); - -} -} - -#endif diff --git a/src/jit.cpp b/src/jit.cpp deleted file mode 100644 index a44b873c1..000000000 --- a/src/jit.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include -#include - -#include "llvm/Support/ManagedStatic.h" -//#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "core/ast.h" -#include "core/util.h" - -#include "codegen/entry.h" -#include "codegen/llvm_interpreter.h" -#include "codegen/parser.h" - - -#ifndef GITREV -#error -#endif - -using namespace pyston; - -int main(int argc, char** argv) { - Timer _t("for jit startup"); - //llvm::sys::PrintStackTraceOnErrorSignal(); - //llvm::PrettyStackTraceProgram X(argc, argv); - llvm::llvm_shutdown_obj Y; - - int code; - bool caching = true; - bool force_repl = false; - bool repl = true; - bool stats = false; - while ((code = getopt(argc, argv, "+Oqcdibpjtrsvn")) != -1) { - if (code == 'O') - FORCE_OPTIMIZE = true; - else if (code == 't') - TRAP = true; - else if (code == 'q') - GLOBAL_VERBOSITY = 0; - else if (code == 'v') - GLOBAL_VERBOSITY++; - //else if (code == 'c') // now always enabled - //caching = true; - else if (code == 'd') - SHOW_DISASM = true; - else if (code == 'i') - force_repl = true; - else if (code == 'b') { - BENCH = true; - } else if (code == 'n') { - ENABLE_INTERPRETER = false; - } else if (code == 'p') { - PROFILE = true; - } else if (code == 'j') { - DUMPJIT = true; - } else if (code == 's') { - stats = true; - } else if (code == 'r') { - USE_STRIPPED_STDLIB = true; - } else if (code == '?') - abort(); - } - - const char* fn = NULL; - if (optind != argc-1 && optind != argc) { - fprintf(stderr, "Error: python-level arguments not supported yet (first given was %s)\n", argv[optind+1]); - exit(1); - } - if (optind != argc) { - fn = argv[optind]; - if (!force_repl) - repl = false; - } - - // end of argument parsing - - { - Timer _t("for initCodegen"); - initCodegen(); - } - - BoxedModule* main = createMainModule(fn); - - _t.split("to run"); - if (fn != NULL) { - int num_iterations = 1; - if (BENCH) - num_iterations = 1000; - - for (int i = 0; i < num_iterations; i++) { - AST_Module *m; - if (caching) - m = caching_parse(fn); - else - m = parse(fn); - - if (VERBOSITY() >= 1) { - fprintf(stderr, "Parsed code; ast:\n"); - print_ast(m); - fprintf(stderr, "==============\n"); - } - - CompiledFunction* compiled = compileModule(m, main); - if (VERBOSITY() >= 1) - fprintf(stderr, "compiled module.main to machine code; running:\n"); - if (compiled->is_interpreted) - interpretFunction(compiled->func, 0, NULL, NULL, NULL, NULL); - else - ((void (*)())compiled->code)(); - if (VERBOSITY() >= 1) - fprintf(stderr, "finished running\n"); - } - } - - if (repl && BENCH) { - timeval start, end; - gettimeofday(&start, NULL); - const int MAX_RUNS = 1000; - const int MAX_TIME = 30; - int run = 0; - while (true) { - run++; - - AST_Module *m = new AST_Module(); - CompiledFunction* compiled = compileModule(m, main); - if (compiled->is_interpreted) - interpretFunction(compiled->func, 0, NULL, NULL, NULL, NULL); - else - ((void (*)())compiled->code)(); - - if (run >= MAX_RUNS) { - printf("Quitting after %d iterations\n", run); - break; - } - gettimeofday(&end, NULL); - if (end.tv_sec - start.tv_sec > MAX_TIME) { - printf("Quitting after %d seconds (%d iterations)\n", MAX_TIME, run); - break; - } - } - gettimeofday(&end, NULL); - long ms = 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000; - printf("%ldms (%.2fms per)\n", ms, 1.0 * ms / run); - - repl = force_repl; - } - - if (repl) { - printf("Pyston v0.1, rev " STRINGIFY(GITREV) "\n"); - } - while (repl) { - printf(">> "); - - char* line = NULL; - size_t size; - int read; - if ((read = getline(&line, &size, stdin)) == -1) { - repl = false; - } else { - timeval start, end; - gettimeofday(&start, NULL); - - char buf[] = "pystontmp_XXXXXX"; - char *tmpdir = mkdtemp(buf); - assert(tmpdir); - std::string tmp = std::string(tmpdir) + "/in.py"; - if (VERBOSITY() >= 1) { - printf("writing %d bytes to %s\n", read, tmp.c_str()); - } - - FILE* f = fopen(tmp.c_str(), "w"); - fwrite(line, 1, read, f); - fclose(f); - - AST_Module* m = parse(tmp.c_str()); - removeDirectoryIfExists(tmpdir); - - if (m->body.size() > 0 && m->body[0]->type == AST_TYPE::Expr) { - AST_Expr *e = static_cast(m->body[0]); - AST_Print *p = new AST_Print(); - p->dest = NULL; - p->nl = true; - p->values.push_back(e->value); - m->body[0] = p; - } - - CompiledFunction* compiled = compileModule(m, main); - if (compiled->is_interpreted) - interpretFunction(compiled->func, 0, NULL, NULL, NULL, NULL); - else - ((void (*)())compiled->code)(); - - if (VERBOSITY() >= 1) { - gettimeofday(&end, NULL); - long ms = 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000; - printf("%ldms\n", ms); - } - } - } - _t.split("joinRuntime"); - - int rtncode = joinRuntime(); - _t.split("finishing up"); - - if (VERBOSITY() >= 1 || stats) - Stats::dump(); - - // I don't know why this is required... - fflush(stdout); - return rtncode; -} diff --git a/src/runtime/bool.cpp b/src/runtime/bool.cpp deleted file mode 100644 index e37c8cc74..000000000 --- a/src/runtime/bool.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/common.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -#include "gc/collector.h" - -namespace pyston { - -Box *True, *False; - -extern "C" Box* boolInvert(BoxedBool* v) { - return boxInt(~v->b); -} - -extern "C" Box* boolPos(BoxedBool* v) { - return boxInt(v->b ? 1 : 0); -} - -extern "C" Box* boolNeg(BoxedBool* v) { - return boxInt(v->b ? -1 : 0); -} - -extern "C" Box* boolNonzero(BoxedBool* v) { - return v; -} - -extern "C" Box* boolRepr(BoxedBool* v) { - if (v->b) - return boxStrConstant("True"); - return boxStrConstant("False"); -} - -extern "C" Box* boolNew1(Box* cls) { - assert(cls == bool_cls); - return False; -} - -extern "C" Box* boolNew2(Box* cls, Box* val) { - assert(cls == bool_cls); - - bool b = nonzero(val); - return boxBool(b); -} - -void setupBool() { - bool_cls->giveAttr("__name__", boxStrConstant("bool")); - - bool_cls->giveAttr("__invert__", new BoxedFunction(boxRTFunction((void*)boolInvert, NULL, 1, false))); - bool_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)boolPos, NULL, 1, false))); - bool_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)boolNeg, NULL, 1, false))); - bool_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)boolNonzero, NULL, 1, false))); - bool_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)boolRepr, NULL, 1, false))); - bool_cls->setattr("__str__", bool_cls->peekattr("__repr__"), NULL, NULL); - - CLFunction *__new__ = boxRTFunction((void*)boolNew1, NULL, 1, false); - addRTFunction(__new__, (void*)boolNew2, NULL, 2, false); - bool_cls->giveAttr("__new__", new BoxedFunction(__new__)); - - - bool_cls->freeze(); - - True = new BoxedBool(true); - False = new BoxedBool(false); - - gc::registerStaticRootObj(True); - gc::registerStaticRootObj(False); -} - -void teardownBool() { -} - -} - diff --git a/src/runtime/builtin_modules/builtins.cpp b/src/runtime/builtin_modules/builtins.cpp deleted file mode 100644 index dfc6b4b75..000000000 --- a/src/runtime/builtin_modules/builtins.cpp +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/ast.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -#include "runtime/inline/xrange.h" - -#include "gc/collector.h" - -namespace pyston { - -extern "C" Box* trap() { - raise(SIGTRAP); - - return None; -} - -extern "C" Box* abs_(Box* x) { - if (x->cls == int_cls) { - i64 n = static_cast(x)->n; - return boxInt(n >= 0 ? n : -n); - } else if (x->cls == float_cls) { - double d = static_cast(x)->d; - return boxFloat(d >= 0 ? d : -d); - } else { - RELEASE_ASSERT(0, "%s", getTypeName(x)->c_str()); - } -} - -extern "C" Box* min_(Box* o0, Box* o1) { - Box *comp_result = compareInternal(o0, o1, AST_TYPE::Gt, NULL); - bool b = nonzero(comp_result); - if (b) { - return o1; - } - return o0; -} - -extern "C" Box* max_(Box* o0, Box* o1) { - Box *comp_result = compareInternal(o0, o1, AST_TYPE::Lt, NULL); - bool b = nonzero(comp_result); - if (b) { - return o1; - } - return o0; -} - -extern "C" Box* open2(Box* arg1, Box* arg2) { - if (arg1->cls != str_cls) { - fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg1)->c_str()); - raiseExc(); - } - if (arg2->cls != str_cls) { - fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg2)->c_str()); - raiseExc(); - } - - const std::string &fn = static_cast(arg1)->s; - const std::string &mode = static_cast(arg2)->s; - - FILE* f = fopen(fn.c_str(), mode.c_str()); - RELEASE_ASSERT(f, ""); - - return new BoxedFile(f); -} - -extern "C" Box* open1(Box* arg) { - Box* mode = boxStrConstant("r"); - Box *rtn = open2(arg, mode); - return rtn; -} - -extern "C" Box* chr(Box* arg) { - if (arg->cls != int_cls) { - fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg)->c_str()); - raiseExc(); - } - i64 n = static_cast(arg)->n; - RELEASE_ASSERT(n >= 0 && n < 256, ""); - - return boxString(std::string(1, (char)n)); -} - -Box* range1(Box* end) { - RELEASE_ASSERT(end->cls == int_cls, "%s", getTypeName(end)->c_str()); - - BoxedList *rtn = new BoxedList(); - i64 iend = static_cast(end)->n; - for (i64 i = 0; i < iend; i++) { - Box *bi = boxInt(i); - listAppendInternal(rtn, bi); - } - return rtn; -} - -Box* range2(Box* start, Box* end) { - RELEASE_ASSERT(start->cls == int_cls, "%s", getTypeName(start)->c_str()); - RELEASE_ASSERT(end->cls == int_cls, "%s", getTypeName(end)->c_str()); - - BoxedList *rtn = new BoxedList(); - i64 istart = static_cast(start)->n; - i64 iend = static_cast(end)->n; - - for (i64 i = istart; i < iend; i++) { - Box *bi = boxInt(i); - listAppendInternal(rtn, bi); - } - return rtn; -} - -Box* range3(Box* start, Box* end, Box* step) { - RELEASE_ASSERT(start->cls == int_cls, "%s", getTypeName(start)->c_str()); - RELEASE_ASSERT(end->cls == int_cls, "%s", getTypeName(end)->c_str()); - RELEASE_ASSERT(step->cls == int_cls, "%s", getTypeName(step)->c_str()); - - BoxedList *rtn = new BoxedList(); - i64 istart = static_cast(start)->n; - i64 iend = static_cast(end)->n; - i64 istep = static_cast(step)->n; - RELEASE_ASSERT(istep != 0, "step can't be 0"); - - if (istep > 0) { - for (i64 i = istart; i < iend; i += istep) { - Box *bi = boxInt(i); - listAppendInternal(rtn, bi); - } - } else { - for (i64 i = istart; i > iend; i += istep) { - Box *bi = boxInt(i); - listAppendInternal(rtn, bi); - } - } - return rtn; -} - -Box* notimplementedRepr(Box* self) { - assert(self == NotImplemented); - return boxStrConstant("NotImplemented"); -} - -Box* sorted(Box* obj) { - RELEASE_ASSERT(obj->cls == list_cls, ""); - - BoxedList *lobj = static_cast(obj); - BoxedList *rtn = new BoxedList(); - - int size = lobj->size; - rtn->elts = new (size) BoxedList::ElementArray(); - rtn->size = size; - rtn->capacity = size; - for (int i = 0; i < size; i++) { - Box* t = rtn->elts->elts[i] = lobj->elts->elts[i]; - } - - std::sort(rtn->elts->elts, rtn->elts->elts + size, PyLt()); - - return rtn; -} - -Box* isinstance(Box* obj, Box *cls) { - assert(cls->cls == type_cls); - BoxedClass *ccls = static_cast(cls); - - // TODO need to check if it's a subclass, or if subclasshook exists - return boxBool(obj->cls == cls); -} - -Box* getattr2(Box* obj, Box* _str) { - if (_str->cls != str_cls) { - fprintf(stderr, "TypeError: getattr(): attribute name must be string\n"); - raiseExc(); - } - - BoxedString* str = static_cast(_str); - Box* rtn = getattr_internal(obj, str->s.c_str(), true, true, NULL, NULL); - - if (!rtn) { - fprintf(stderr, "AttributeError: '%s' object has no attribute '%s'\n", getTypeName(obj)->c_str(), str->s.c_str()); - raiseExc(); - } - - return rtn; -} - -Box* getattr3(Box* obj, Box* _str, Box* default_value) { - if (_str->cls != str_cls) { - fprintf(stderr, "TypeError: getattr(): attribute name must be string\n"); - raiseExc(); - } - - BoxedString* str = static_cast(_str); - Box* rtn = getattr_internal(obj, str->s.c_str(), true, true, NULL, NULL); - - if (!rtn) { - return default_value; - } - - return rtn; -} - -extern "C" const ObjectFlavor notimplemented_flavor(&boxGCHandler, NULL); -BoxedClass *notimplemented_cls; -BoxedModule* builtins_module; - -void setupBuiltins() { - std::string name("__builtin__"); - std::string fn("__builtin__"); - builtins_module = new BoxedModule(&name, &fn); - - builtins_module->setattr("None", None, NULL, NULL); - - notimplemented_cls = new BoxedClass(false, NULL); - notimplemented_cls->giveAttr("__name__", boxStrConstant("NotImplementedType")); - notimplemented_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)notimplementedRepr, NULL, 1, false))); - notimplemented_cls->freeze(); - NotImplemented = new Box(¬implemented_flavor, notimplemented_cls); - gc::registerStaticRootObj(NotImplemented); - - builtins_module->giveAttr("NotImplemented", NotImplemented); - builtins_module->giveAttr("NotImplementedType", notimplemented_cls); - - repr_obj = new BoxedFunction(boxRTFunction((void*)repr, NULL, 1, false)); - builtins_module->giveAttr("repr", repr_obj); - len_obj = new BoxedFunction(boxRTFunction((void*)len, NULL, 1, false)); - builtins_module->giveAttr("len", len_obj); - hash_obj = new BoxedFunction(boxRTFunction((void*)hash, NULL, 1, false)); - builtins_module->giveAttr("hash", hash_obj); - abs_obj = new BoxedFunction(boxRTFunction((void*)abs_, NULL, 1, false)); - builtins_module->giveAttr("abs", abs_obj); - min_obj = new BoxedFunction(boxRTFunction((void*)min_, NULL, 2, false)); - builtins_module->giveAttr("min", min_obj); - max_obj = new BoxedFunction(boxRTFunction((void*)max_, NULL, 2, false)); - builtins_module->giveAttr("max", max_obj); - chr_obj = new BoxedFunction(boxRTFunction((void*)chr, NULL, 1, false)); - builtins_module->giveAttr("chr", chr_obj); - trap_obj = new BoxedFunction(boxRTFunction((void*)trap, NULL, 0, false)); - builtins_module->giveAttr("trap", trap_obj); - - CLFunction* getattr_func = boxRTFunction((void*)getattr2, NULL, 2, false); - addRTFunction(getattr_func, (void*)getattr3, NULL, 3, false); - builtins_module->giveAttr("getattr", new BoxedFunction(getattr_func)); - - Box* isinstance_obj = new BoxedFunction(boxRTFunction((void*)isinstance, NULL, 2, false)); - builtins_module->giveAttr("isinstance", isinstance_obj); - - builtins_module->giveAttr("sorted", new BoxedFunction(boxRTFunction((void*)sorted, NULL, 1, false))); - - builtins_module->setattr("True", True, NULL, NULL); - builtins_module->setattr("False", False, NULL, NULL); - - CLFunction *range_clf = boxRTFunction((void*)range1, NULL, 1, false); - addRTFunction(range_clf, (void*)range2, NULL, 2, false); - addRTFunction(range_clf, (void*)range3, NULL, 3, false); - range_obj = new BoxedFunction(range_clf); - builtins_module->giveAttr("range", range_obj); - - setupXrange(); - builtins_module->giveAttr("xrange", xrange_cls); - - CLFunction *open = boxRTFunction((void*)open1, NULL, 1, false); - addRTFunction(open, (void*)open2, NULL, 2, false); - open_obj = new BoxedFunction(open); - builtins_module->giveAttr("open", open_obj); - - - builtins_module->setattr("str", str_cls, NULL, NULL); - builtins_module->setattr("int", int_cls, NULL, NULL); - builtins_module->setattr("float", float_cls, NULL, NULL); - builtins_module->setattr("list", list_cls, NULL, NULL); - builtins_module->setattr("slice", slice_cls, NULL, NULL); - builtins_module->setattr("type", type_cls, NULL, NULL); - builtins_module->setattr("file", file_cls, NULL, NULL); - builtins_module->setattr("bool", bool_cls, NULL, NULL); - builtins_module->setattr("dict", dict_cls, NULL, NULL); - builtins_module->setattr("tuple", tuple_cls, NULL, NULL); - builtins_module->setattr("instancemethod", instancemethod_cls, NULL, NULL); -} - -} diff --git a/src/runtime/builtin_modules/math.cpp b/src/runtime/builtin_modules/math.cpp deleted file mode 100644 index 19a0e89f4..000000000 --- a/src/runtime/builtin_modules/math.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define _USE_MATH_DEFINES -#include - -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/types.h" -#include "runtime/util.h" -#include "runtime/inline/boxing.h" - -namespace pyston { - -BoxedModule* math_module; - -static double _extractFloat(Box* b) { - if (b->cls != int_cls && b->cls != float_cls) { - fprintf(stderr, "TypeError: a float is required\n"); - raiseExc(); - } - - if (b->cls == int_cls) - return static_cast(b)->n; - else - return static_cast(b)->d; -} - -Box* mathSqrt(Box* b) { - double d = _extractFloat(b); - if (d < 0) { - fprintf(stderr, "ValueError: math domain error\n"); - raiseExc(); - } - - double r = sqrt(d); - - return boxFloat(r); -} - -Box* mathTan(Box* b) { - double d = _extractFloat(b); - return boxFloat(tan(d)); -} - -void setupMath() { - std::string name("math"); - std::string fn("__builtin__"); - math_module = new BoxedModule(&name, &fn); - - math_module->giveAttr("pi", boxFloat(M_PI)); - - math_module->giveAttr("sqrt", new BoxedFunction(boxRTFunction((void*)mathSqrt, NULL, 1, false))); - math_module->giveAttr("tan", new BoxedFunction(boxRTFunction((void*)mathTan, NULL, 1, false))); -} - -} diff --git a/src/runtime/builtin_modules/time.cpp b/src/runtime/builtin_modules/time.cpp deleted file mode 100644 index d71810cae..000000000 --- a/src/runtime/builtin_modules/time.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/types.h" - -namespace pyston { - -BoxedModule* time_module; - -Box* timeTime() { - struct timeval now; - gettimeofday(&now, NULL); - double t = now.tv_sec + .000001 * now.tv_usec; - return boxFloat(t); -} - -void setupTime() { - std::string name("time"); - std::string fn("__builtin__"); - time_module = new BoxedModule(&name, &fn); - - time_module->giveAttr("time", new BoxedFunction(boxRTFunction((void*)timeTime, NULL, 0, false))); -} - -} - diff --git a/src/runtime/dict.cpp b/src/runtime/dict.cpp deleted file mode 100644 index 38357add0..000000000 --- a/src/runtime/dict.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/common.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -Box* dictRepr(BoxedDict* self) { - std::vector chars; - chars.push_back('{'); - bool first = true; - for (BoxedDict::PyDict::iterator it = self->d.begin(), end = self->d.end(); it != end; ++it) { - if (!first) { - chars.push_back(','); - chars.push_back(' '); - } - first = false; - - BoxedString *k = repr(it->first); - BoxedString *v = repr(it->second); - chars.insert(chars.end(), k->s.begin(), k->s.end()); - chars.push_back(':'); - chars.push_back(' '); - chars.insert(chars.end(), v->s.begin(), v->s.end()); - } - chars.push_back('}'); - return boxString(std::string(chars.begin(), chars.end())); -} - -Box* dictItems(BoxedDict* self) { - BoxedList* rtn = new BoxedList(); - - for (BoxedDict::PyDict::const_iterator it = self->d.begin(), end = self->d.end(); it != end; ++it) { - std::vector elts; - elts.push_back(it->first); - elts.push_back(it->second); - BoxedTuple *t = new BoxedTuple(elts); - listAppendInternal(rtn, t); - } - - return rtn; -} - -Box* dictValues(BoxedDict* self) { - BoxedList* rtn = new BoxedList(); - for (BoxedDict::PyDict::const_iterator it = self->d.begin(), end = self->d.end(); it != end; ++it) { - listAppendInternal(rtn, it->second); - } - return rtn; -} - -Box* dictKeys(BoxedDict* self) { - BoxedList* rtn = new BoxedList(); - for (BoxedDict::PyDict::const_iterator it = self->d.begin(), end = self->d.end(); it != end; ++it) { - listAppendInternal(rtn, it->first); - } - return rtn; -} - -Box* dictGetitem(BoxedDict* self, Box* k) { - Box* &pos = self->d[k]; - - if (pos == NULL) { - BoxedString *s = repr(k); - fprintf(stderr, "KeyError: %s\n", s->s.c_str()); - raiseExc(); - } - - return pos; -} - -Box* dictSetitem(BoxedDict* self, Box* k, Box* v) { - //printf("Starting setitem\n"); - Box* &pos = self->d[k]; - //printf("Got the pos\n"); - - if (pos != NULL) { - pos = v; - } else { - pos = v; - } - - return None; -} - -void dict_dtor(BoxedDict* self) { - self->d.clear(); - - // Not sure how to express this without the typedef: - typedef BoxedDict::PyDict T; - (&self->d)->~T(); -} - -void setupDict() { - dict_cls->giveAttr("__name__", boxStrConstant("dict")); - //dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, NULL, 1, false))); - //dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem, NULL, 2, false))); - //dict_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, NULL, 1, false))); - //dict_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)dictInit, NULL, 1, false))); - dict_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)dictRepr, NULL, 1, false))); - dict_cls->setattr("__str__", dict_cls->peekattr("__repr__"), NULL, NULL); - - dict_cls->giveAttr("items", new BoxedFunction(boxRTFunction((void*)dictItems, NULL, 1, false))); - dict_cls->setattr("iteritems", dict_cls->peekattr("items"), NULL, NULL); - - dict_cls->giveAttr("values", new BoxedFunction(boxRTFunction((void*)dictValues, NULL, 1, false))); - dict_cls->setattr("itervalues", dict_cls->peekattr("values"), NULL, NULL); - - dict_cls->giveAttr("keys", new BoxedFunction(boxRTFunction((void*)dictKeys, NULL, 1, false))); - dict_cls->setattr("iterkeys", dict_cls->peekattr("keys"), NULL, NULL); - - dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem, NULL, 2, false))); - dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NULL, 3, false))); - - dict_cls->freeze(); -} - -void teardownDict() { -} - -} - diff --git a/src/runtime/file.cpp b/src/runtime/file.cpp deleted file mode 100644 index 41bb8800a..000000000 --- a/src/runtime/file.cpp +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/common.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -Box* fileRepr(BoxedFile* self) { - assert(self->cls == file_cls); - RELEASE_ASSERT(0, ""); -} - -static Box* _fileRead(BoxedFile* self, i64 size) { - if (self->closed) { - fprintf(stderr, "IOError: file not open for reading\n"); - raiseExc(); - } - - std::ostringstream os(""); - - if (size < 0) - size = 1L << 60; - - i64 read = 0; - while (read < size) { - const int BUF_SIZE = 1024; - char buf[BUF_SIZE]; - size_t more_read = fread(buf, 1, std::min((i64)BUF_SIZE, size - read), self->f); - if (more_read == 0) { - ASSERT(!ferror(self->f), "%d", ferror(self->f)); - break; - } - - read += more_read; - // this is probably inefficient: - os << std::string(buf, more_read); - } - return boxString(os.str()); -} - -Box* fileRead1(BoxedFile* self) { - assert(self->cls == file_cls); - return _fileRead(self, -1); -} - -Box* fileRead2(BoxedFile* self, Box* size) { - assert(self->cls == file_cls); - if (size->cls != int_cls) { - fprintf(stderr, "TypeError: an integer is required\n"); - raiseExc(); - } - return _fileRead(self, static_cast(size)->n); -} - -Box* fileWrite(BoxedFile* self, Box* val) { - assert(self->cls == file_cls); - - if (self->closed) { - fprintf(stderr, "IOError: file is closed\n"); - raiseExc(); - } - - - if (val->cls == str_cls) { - const std::string &s = static_cast(val)->s; - - size_t size = s.size(); - size_t written = 0; - while (written < size) { - //const int BUF_SIZE = 1024; - //char buf[BUF_SIZE]; - //int to_write = std::min(BUF_SIZE, size - written); - //memcpy(buf, s.c_str() + written, to_write); - //size_t new_written = fwrite(buf, 1, to_write, self->f); - - size_t new_written = fwrite(s.c_str() + written, 1, size - written, self->f); - - if (!new_written) { - int error = ferror(self->f); - fprintf(stderr, "IOError %d\n", error); - raiseExc(); - } - - written += new_written; - } - - return None; - } else { - fprintf(stderr, "str expected\n"); - raiseExc(); - } -} - -Box* fileClose(BoxedFile* self) { - assert(self->cls == file_cls); - if (self->closed) { - fprintf(stderr, "IOError: file is closed\n"); - raiseExc(); - } - - fclose(self->f); - self->closed = true; - - return None; -} - -Box* fileEnter(BoxedFile* self) { - assert(self->cls == file_cls); - return self; -} - -Box* fileExit(BoxedFile* self, Box* exc_type, Box* exc_val, Box** args) { - Box* exc_tb = args[0]; - assert(self->cls == file_cls); - assert(exc_type == None); - assert(exc_val == None); - assert(exc_tb == None); - - return fileClose(self); -} - -void file_dtor(BoxedFile* t) { -} - -Box* fileNew2(BoxedClass *cls, Box* s) { - assert(cls == file_cls); - return open1(s); -} - -Box* fileNew3(BoxedClass *cls, Box* s, Box* m) { - assert(cls == file_cls); - return open2(s, m); -} - -void setupFile() { - file_cls->giveAttr("__name__", boxStrConstant("file")); - - CLFunction *read = boxRTFunction((void*)fileRead1, NULL, 1, false); - addRTFunction(read, (void*)fileRead2, NULL, 2, false); - file_cls->giveAttr("read", new BoxedFunction(read)); - - file_cls->giveAttr("write", new BoxedFunction(boxRTFunction((void*)fileWrite, NULL, 2, false))); - file_cls->giveAttr("close", new BoxedFunction(boxRTFunction((void*)fileClose, NULL, 1, false))); - - file_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)fileRepr, NULL, 1, false))); - file_cls->setattr("__str__", file_cls->peekattr("__repr__"), NULL, NULL); - - file_cls->giveAttr("__enter__", new BoxedFunction(boxRTFunction((void*)fileEnter, NULL, 1, false))); - file_cls->giveAttr("__exit__", new BoxedFunction(boxRTFunction((void*)fileExit, NULL, 4, false))); - - CLFunction *__new__ = boxRTFunction((void*)fileNew2, NULL, 2, false); - addRTFunction(__new__, (void*)fileNew3, NULL, 3, false); - file_cls->giveAttr("__new__", new BoxedFunction(__new__)); - - file_cls->freeze(); -} - -void teardownFile() { -} - -} diff --git a/src/runtime/float.cpp b/src/runtime/float.cpp deleted file mode 100644 index eaf371b04..000000000 --- a/src/runtime/float.cpp +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -#include "runtime/inline/boxing.h" - -#include "codegen/compvars.h" - -namespace pyston { - -extern "C" double mod_float_float(double lhs, double rhs) { - if (rhs == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - double r = fmod(lhs, rhs); - // Have to be careful here with signed zeroes: - if (std::signbit(r) != std::signbit(rhs)) { - if (r == 0) - r *= -1; - else - r += rhs; - } - return r; -} - -extern "C" double pow_float_float(double lhs, double rhs) { - return pow(lhs, rhs); -} - -extern "C" double div_float_float(double lhs, double rhs) { - if (rhs == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - return lhs / rhs; -} - -extern "C" Box* floatAddFloat(BoxedFloat* lhs, BoxedFloat *rhs) { - assert(lhs->cls == float_cls); - assert(rhs->cls == float_cls); - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d + rhs_float->d); -} - -extern "C" Box* floatAdd(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - //printf("floatAdd %p %p\n", lhs, rhs); - if (rhs->cls == int_cls) { - BoxedInt* rhs_int = static_cast(rhs); - return boxFloat(lhs->d + rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d + rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatDiv(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - if (rhs_int->n == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - return boxFloat(lhs->d / rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - if (rhs_float->d == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - return boxFloat(lhs->d / rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatRDiv(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (lhs->d == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxFloat(rhs_int->n / lhs->d); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(rhs_float->d / lhs->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatEq(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d == rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d == rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatFloorDiv(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls != float_cls) { - return NotImplemented; - } - BoxedFloat *rhs_float = static_cast(rhs); - if (rhs_float->d == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - return boxFloat(floor(lhs->d / rhs_float->d)); -} - -extern "C" Box* floatNe(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d != rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d != rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatLt(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d < rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d < rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatLe(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d <= rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d <= rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatGt(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d > rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d > rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatGe(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxBool(lhs->d >= rhs_float->d); - } else if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->d >= rhs_int->n); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatModFloat(BoxedFloat* lhs, Box *rhs) { - assert(rhs->cls == float_cls); - BoxedFloat *rhs_float = static_cast(rhs); - double drhs = rhs_float->d; - - if (drhs == 0) { - fprintf(stderr, "float div by zero\n"); - raiseExc(); - } - - return boxFloat(mod_float_float(lhs->d, drhs)); -} - -extern "C" Box* floatMod(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - double drhs; - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - drhs = rhs_int->n; - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - drhs = rhs_float->d; - } else { - return NotImplemented; - } - - if (drhs == 0) { - fprintf(stderr, "float div by zero\n"); - raiseExc(); - } - - return boxFloat(mod_float_float(lhs->d, drhs)); -} - -extern "C" Box* floatRModFloat(BoxedFloat* lhs, Box *rhs) { - assert(rhs->cls == float_cls); - BoxedFloat *rhs_float = static_cast(rhs); - double drhs = rhs_float->d; - - if (lhs->d == 0) { - fprintf(stderr, "float div by zero\n"); - raiseExc(); - } - - return boxFloat(mod_float_float(drhs, lhs->d)); -} - -extern "C" Box* floatRMod(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - double drhs; - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - drhs = rhs_int->n; - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - drhs = rhs_float->d; - } else { - return NotImplemented; - } - - if (lhs->d == 0) { - fprintf(stderr, "float div by zero\n"); - raiseExc(); - } - - return boxFloat(mod_float_float(drhs, lhs->d)); -} - -extern "C" Box* floatPow(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == int_cls) { - BoxedInt* rhs_int = static_cast(rhs); - return boxFloat(pow(lhs->d, rhs_int->n)); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(pow(lhs->d, rhs_float->d)); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatMulFloat(BoxedFloat* lhs, BoxedFloat *rhs) { - assert(lhs->cls == float_cls); - assert(rhs->cls == float_cls); - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d * rhs_float->d); -} - -extern "C" Box* floatMul(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxFloat(lhs->d * rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d * rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatSubFloat(BoxedFloat* lhs, BoxedFloat *rhs) { - assert(lhs->cls == float_cls); - assert(rhs->cls == float_cls); - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d - rhs_float->d); -} - -extern "C" Box* floatSub(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == int_cls) { - BoxedInt* rhs_int = static_cast(rhs); - return boxFloat(lhs->d - rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->d - rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* floatRSub(BoxedFloat* lhs, Box *rhs) { - assert(lhs->cls == float_cls); - if (rhs->cls == int_cls) { - BoxedInt* rhs_int = static_cast(rhs); - return boxFloat(rhs_int->n - lhs->d); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(rhs_float->d - lhs->d); - } else { - return NotImplemented; - } -} - -Box* floatNeg(BoxedFloat *self) { - assert(self->cls == float_cls); - return boxFloat(-self->d); -} - -Box* floatNonzero(BoxedFloat *self) { - assert(self->cls == float_cls); - return boxBool(self->d != 0.0); -} - -std::string floatFmt(double x, int precision, char code) { - char fmt[5] = "%.*g"; - fmt[3] = code; - - if (isnan(x)) { - return "nan"; - } - if (isinf(x)) { - if (x > 0) - return "inf"; - return "-inf"; - } - - char buf[40]; - int n = snprintf(buf, 40, fmt, precision, x); - - int dot = -1; - int exp = -1; - int first = -1; - for (int i = 0; i < n; i++) { - char c = buf[i]; - if (c == '.') { - dot = i; - } else if (c == 'e') { - exp = i; - } else if (first == -1 && c >= '0' && c <= '9') { - first = i; - } - } - - if (dot == -1 && exp == -1) { - if (n == precision) { - memmove(buf + first + 2, buf + first + 1, (n - first - 1)); - buf[first + 1] = '.'; - exp = n + 1; - int exp_digs = snprintf(buf + n + 1, 5, "e%+.02d", (n-first-1)); - n += exp_digs + 1; - dot = 1; - } else { - buf[n] = '.'; - buf[n+1] = '0'; - n += 2; - - return std::string(buf, n); - } - } - - if (exp != -1 && dot == -1) { - return std::string(buf, n); - } - - assert(dot != -1); - - int start, end; - if (exp) { - start = exp - 1; - end = dot; - } else { - start = n - 1; - end = dot + 2; - } - for (int i = start; i >= end; i--) { - if (buf[i] == '0') { - memmove(buf + i, buf + i + 1, n - i - 1); - n--; - } else if (buf[i] == '.') { - memmove(buf + i, buf + i + 1, n - i - 1); - n--; - break; - } else { - break; - } - } - return std::string(buf, n); -} - -Box* floatNew1(BoxedClass *cls) { - assert(cls == float_cls); - // TODO intern this? - return boxFloat(0.0); -} - -Box* floatNew2(BoxedClass *cls, Box* a) { - assert(cls == float_cls); - - if (a->cls == float_cls) { - return a; - } else if (a->cls == str_cls) { - const std::string &s = static_cast(a)->s; - if (s == "nan") - return boxFloat(NAN); - if (s == "-nan") - return boxFloat(-NAN); - if (s == "inf") - return boxFloat(INFINITY); - if (s == "-inf") - return boxFloat(-INFINITY); - - RELEASE_ASSERT(0, "%s", s.c_str()); - } - RELEASE_ASSERT(0, "%s", getTypeName(a)->c_str()); -} - -Box* floatStr(BoxedFloat *self) { - assert(self->cls == float_cls); - return boxString(floatFmt(self->d, 12, 'g')); -} - -Box* floatRepr(BoxedFloat *self) { - assert(self->cls == float_cls); - return boxString(floatFmt(self->d, 16, 'g')); -} - -extern "C" void printFloat(double d) { - std::string s = floatFmt(d, 12, 'g'); - printf("%s", s.c_str()); -} - -static void _addFunc(const char* name, void* float_func, void* boxed_func) { - std::vector v_ff, v_fu; - v_ff.push_back(BOXED_FLOAT); v_ff.push_back(BOXED_FLOAT); - v_fu.push_back(BOXED_FLOAT); v_fu.push_back(NULL); - - CLFunction *cl = createRTFunction(); - addRTFunction(cl, float_func, BOXED_FLOAT, v_ff, false); - addRTFunction(cl, boxed_func, NULL, v_fu, false); - float_cls->giveAttr(name, new BoxedFunction(cl)); -} - -void setupFloat() { - float_cls->giveAttr("__name__", boxStrConstant("float")); - - _addFunc("__add__", (void*)floatAddFloat, (void*)floatAdd); - //float_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)floatAdd, NULL, 2, false))); - float_cls->setattr("__radd__", float_cls->peekattr("__add__"), NULL, NULL); - float_cls->giveAttr("__div__", new BoxedFunction(boxRTFunction((void*)floatDiv, NULL, 2, false))); - float_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)floatRDiv, NULL, 2, false))); - float_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)floatEq, NULL, 2, false))); - float_cls->giveAttr("__floordiv__", new BoxedFunction(boxRTFunction((void*)floatFloorDiv, NULL, 2, false))); - float_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)floatGe, NULL, 2, false))); - float_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)floatGt, NULL, 2, false))); - float_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)floatLe, NULL, 2, false))); - float_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)floatLt, NULL, 2, false))); - _addFunc("__mod__", (void*)floatModFloat, (void*)floatMod); - _addFunc("__rmod__", (void*)floatRModFloat, (void*)floatRMod); - _addFunc("__mul__", (void*)floatMulFloat, (void*)floatMul); - float_cls->setattr("__rmul__", float_cls->peekattr("__mul__"), NULL, NULL); - float_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)floatNe, NULL, 2, false))); - float_cls->giveAttr("__pow__", new BoxedFunction(boxRTFunction((void*)floatPow, NULL, 2, false))); - //float_cls->giveAttr("__sub__", new BoxedFunction(boxRTFunction((void*)floatSub, NULL, 2, false))); - _addFunc("__sub__", (void*)floatSubFloat, (void*)floatSub); - float_cls->giveAttr("__rsub__", new BoxedFunction(boxRTFunction((void*)floatRSub, NULL, 2, false))); - - CLFunction *__new__ = boxRTFunction((void*)floatNew1, NULL, 1, false); - addRTFunction(__new__, (void*)floatNew2, NULL, 2, false); - float_cls->giveAttr("__new__", new BoxedFunction(__new__)); - - float_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)floatNeg, NULL, 1, false))); - float_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)floatNonzero, NULL, 1, false))); - float_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)floatStr, NULL, 1, false))); - float_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)floatRepr, NULL, 1, false))); - float_cls->freeze(); -} - -void teardownFloat() { -} - -} diff --git a/src/runtime/float.h b/src/runtime/float.h deleted file mode 100644 index 2c6d43bc0..000000000 --- a/src/runtime/float.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_FLOAT_H -#define PYSTON_RUNTIME_FLOAT_H - -extern "C" double mod_float_float(double lhs, double rhs); -extern "C" double div_float_float(double lhs, double rhs); -extern "C" double pow_float_float(double lhs, double rhs); - -#endif diff --git a/src/runtime/gc_runtime.h b/src/runtime/gc_runtime.h deleted file mode 100644 index ee84b75c8..000000000 --- a/src/runtime/gc_runtime.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_GCRUNTIME_H -#define PYSTON_RUNTIME_GCRUNTIME_H - -#include "core/common.h" -#include "core/options.h" -#include "core/types.h" - -namespace pyston { - -class Box; - -void gc_teardown(); -extern "C" void* rt_alloc(size_t size); -extern "C" void* rt_realloc(void* ptr, size_t new_size); -extern "C" void rt_free(void* ptr); -} - -#endif diff --git a/src/runtime/importing.cpp b/src/runtime/importing.cpp deleted file mode 100644 index 656e2f442..000000000 --- a/src/runtime/importing.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/types.h" - -#include "runtime/types.h" - -#include "Python.h" - -namespace pyston { - -static BoxedModule* test_module = NULL; - -extern "C" const ObjectFlavor capifunc_flavor(&boxGCHandler, NULL); -BoxedClass *capifunc_cls; -class BoxedCApiFunction : public Box { - private: - const char* name; - PyCFunction func; - - public: - BoxedCApiFunction(const char* name, PyCFunction func) : Box(&capifunc_flavor, capifunc_cls), name(name), func(func) { - } - - static BoxedString* __repr__(BoxedCApiFunction* self) { - assert(self->cls == capifunc_cls); - return boxStrConstant(self->name); - } - - static Box* __call__(BoxedCApiFunction* self, BoxedList* varargs) { - assert(self->cls == capifunc_cls); - assert(varargs->cls == list_cls); - - Box* rtn = (Box*)self->func(test_module, varargs); - assert(rtn); - return rtn; - } -}; - -extern "C" void* Py_InitModule4(const char *arg0, PyMethodDef *arg1, const char *arg2, PyObject *arg3, int arg4) { - std::string name("test"); - std::string fn("../test/test_extension/test.so"); - test_module = new BoxedModule(&name, &fn); - - while (arg1->ml_name) { - if (VERBOSITY()) printf("Loading method %s\n", arg1->ml_name); - assert(arg1->ml_flags == METH_VARARGS); - - //test_module->giveAttr(arg1->ml_name, boxInt(1)); - test_module->giveAttr(arg1->ml_name, new BoxedCApiFunction(arg1->ml_name, arg1->ml_meth)); - - arg1++; - } - return test_module; -} - -extern "C" void* Py_BuildValue(const char* arg0) { - assert(*arg0 == '\0'); - return None; -} - -extern "C" bool PyArg_ParseTuple(void* tuple, const char* fmt, ...) { - if (strcmp("", fmt) == 0) - return true; - - assert(strcmp("O", fmt) == 0); - - BoxedList *varargs = (BoxedList*)tuple; - assert(varargs->size == 1); - - va_list ap; - va_start(ap, fmt); - - Box** arg0 = va_arg(ap, Box**); - *arg0 = varargs->elts->elts[0]; - - va_end(ap); - - return true; -} - -BoxedModule* getTestModule() { - if (test_module) - return test_module; - - void* handle = dlopen("../test/test_extension/test.so", RTLD_NOW); - if (!handle) { - fprintf(stderr, "%s\n", dlerror()); - exit(1); - } - assert(handle); - - void (*init)() = (void (*)())dlsym(handle, "inittest"); - - char *error; - if ((error = dlerror()) != NULL) { - fprintf(stderr, "%s\n", error); - exit(1); - } - - //dlclose(handle); - - assert(init); - (*init)(); - assert(test_module); - return test_module; -} - -void setupCAPI() { - capifunc_cls = new BoxedClass(false, NULL); - capifunc_cls->giveAttr("__name__", boxStrConstant("capifunc")); - - capifunc_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, NULL, 1, false))); - capifunc_cls->setattr("__str__", capifunc_cls->peekattr("__repr__"), NULL, NULL); - - capifunc_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__call__, NULL, 1, true))); - - capifunc_cls->freeze(); -} - -void teardownCAPI() { -} - -} diff --git a/src/runtime/importing.h b/src/runtime/importing.h deleted file mode 100644 index 46c4ae645..000000000 --- a/src/runtime/importing.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_IMPORTING_H -#define PYSTON_RUNTIME_IMPORTING_H - -namespace pyston { - -class BoxedModule; -BoxedModule* getTestModule(); - -} - -#endif diff --git a/src/runtime/inline/boxing.cpp b/src/runtime/inline/boxing.cpp deleted file mode 100644 index 4989cb7f8..000000000 --- a/src/runtime/inline/boxing.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -#include "runtime/gc_runtime.h" -#include "runtime/int.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -#include "runtime/inline/boxing.h" - -namespace pyston { - -extern "C" Box* createDict() { - return new BoxedDict(); -} - -extern "C" Box* createList() { - return new BoxedList(); -} - -extern "C" BoxedString* boxStrConstant(const char* chars) { - return new BoxedString(chars); -} - -extern "C" Box* boxStringPtr(const std::string *s) { - return new BoxedString(*s); -} - -Box* boxString(const std::string &s) { - return new BoxedString(s); -} - -extern "C" double unboxFloat(Box *b) { - ASSERT(b->cls == float_cls, "%s", getTypeName(b)->c_str()); - BoxedFloat *f = (BoxedFloat*)b; - return f->d; -} - -i64 unboxInt(Box *b) { - ASSERT(b->cls == int_cls, "%s", getTypeName(b)->c_str()); - return ((BoxedInt*)b)->n; -} - -Box* boxInt(int64_t n) { - if (0 <= n && n < NUM_INTERNED_INTS) { - return interned_ints[n]; - } - return new BoxedInt(n); -} - -//BoxedInt::BoxedInt(int64_t n) : Box(int_cls), n(n) {} - -} diff --git a/src/runtime/inline/boxing.h b/src/runtime/inline/boxing.h deleted file mode 100644 index b224324eb..000000000 --- a/src/runtime/inline/boxing.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_INLINE_BOXING_H -#define PYSTON_RUNTIME_INLINE_BOXING_H - -#include "runtime/gc_runtime.h" -#include "runtime/int.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -namespace pyston { - -extern "C" inline Box* boxFloat(double d) __attribute__((visibility("default"))); -extern "C" inline Box* boxFloat(double d) { - return new BoxedFloat(d); -} - -extern "C" inline Box* boxBool(bool b) __attribute__((visibility("default"))); -extern "C" inline Box* boxBool(bool b) { - Box* rtn = b ? True : False; - return rtn; -} - -extern "C" inline bool unboxBool(Box* b) __attribute__((visibility("default"))); -extern "C" inline bool unboxBool(Box* b) { - assert(b->cls == bool_cls); - - // I think this is worse statically than looking up the class attribute - // (since we have to load the value of True), but: - // - the jit knows True is constant once the program starts - // - this function will get inlined as well as boxBool - // So in the presence of optimizations, I think this should do better: - return b == True; - //return static_cast(b)->b; -} - -} - -#endif diff --git a/src/runtime/inline/gc_runtime.cpp b/src/runtime/inline/gc_runtime.cpp deleted file mode 100644 index b4528b9c2..000000000 --- a/src/runtime/inline/gc_runtime.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/common.h" -#include "core/options.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -#include "gc/gc_alloc.h" - -#define USE_CUSTOM_ALLOC - -namespace pyston { - -//#define DEBUG_GC -#ifdef DEBUG_GC -typedef std::unordered_set AliveSet; -static AliveSet* getAlive() { - static AliveSet* alive = new AliveSet(); - return alive; -} -#endif - -void* rt_alloc(size_t size) { -#ifdef USE_CUSTOM_ALLOC - void* ptr = gc::gc_alloc(size); -#else - void* ptr = malloc(size); -#endif - -#ifndef NDEBUG - //nallocs++; -#endif -#ifdef DEBUG_GC - getAlive()->insert(ptr); -#endif - return ptr; -} - -void* rt_realloc(void* ptr, size_t new_size) { -#ifdef USE_CUSTOM_ALLOC - void* rtn = gc::gc_realloc(ptr, new_size); -#else - void* rtn = realloc(ptr, new_size); -#endif - -#ifdef DEBUG_GC - getAlive()->erase(ptr); - getAlive()->insert(rtn); -#endif - return rtn; -} - -void rt_free(void* ptr) { -#ifndef NDEBUG - //nallocs--; -#endif -#ifdef DEBUG_GC - getAlive()->erase(ptr); -#endif - -#ifdef USE_CUSTOM_ALLOC - gc::gc_free(ptr); -#else - free(ptr); -#endif - - //assert(nallocs >= 0); -} - -void gc_teardown() { - /* - if (nallocs != 0) { - printf("Error: %d alloc's not freed\n", nallocs); -#ifdef DEBUG_GC - AliveSet *alive = getAlive(); - assert(nallocs == alive->size()); - for (AliveSet::iterator it = alive->begin(), end = alive->end(); it != end; ++it) { - printf("%p\n", *it); - } -#endif - // This will scan through the heap and alert us about things that - // aren't marked (which should be all alive objects): - gc::global_heap.freeUnmarked(); - - abort(); - } - */ -} - -} diff --git a/src/runtime/inline/link_forcer.cpp b/src/runtime/inline/link_forcer.cpp deleted file mode 100644 index 6884eb996..000000000 --- a/src/runtime/inline/link_forcer.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This file is for forcing the inclusion of function declarations into the stdlib. -// This is so that the types of the functions are available to the compiler. - -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/int.h" -#include "runtime/float.h" -#include "runtime/list.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -#include "runtime/inline/boxing.h" - -#include "gc/heap.h" - -namespace pyston { - -static void forceLink(void* x) { - printf("%p\n", x); -} - -namespace _force { - -#define FORCE(name) forceLink((void*)name) -void force() { - FORCE(my_assert); - - FORCE(boxInt); - FORCE(unboxInt); - FORCE(boxFloat); - FORCE(unboxFloat); - FORCE(boxStringPtr); - FORCE(boxCLFunction); - FORCE(unboxCLFunction); - FORCE(boxInstanceMethod); - FORCE(boxBool); - FORCE(unboxBool); - FORCE(createTuple); - FORCE(createDict); - FORCE(createList); - FORCE(createSlice); - FORCE(createClass); - - FORCE(getattr); - FORCE(setattr); - FORCE(print); - FORCE(nonzero); - FORCE(binop); - FORCE(compare); - FORCE(unboxedLen); - FORCE(getitem); - FORCE(getclsattr); - FORCE(getGlobal); - FORCE(setitem); - FORCE(unaryop); - FORCE(import); - - FORCE(checkUnpackingLength); - FORCE(raiseAttributeError); - FORCE(raiseAttributeErrorStr); - FORCE(raiseNotIterableError); - FORCE(assertNameDefined); - - FORCE(printFloat); - FORCE(listAppendInternal); - - FORCE(dump); - - FORCE(runtimeCall); - FORCE(callattr); - - FORCE(div_i64_i64); - FORCE(mod_i64_i64); - FORCE(pow_i64_i64); - - FORCE(div_float_float); - FORCE(mod_float_float); - FORCE(pow_float_float); - - FORCE(boxFloat); - - FORCE(createModule); - - FORCE(gc::sizes); - - //FORCE(listIter); -} - -} - -} diff --git a/src/runtime/inline/list.cpp b/src/runtime/inline/list.cpp deleted file mode 100644 index 0b938b6eb..000000000 --- a/src/runtime/inline/list.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "runtime/list.h" -#include "runtime/gc_runtime.h" - -namespace pyston { - -BoxedListIterator::BoxedListIterator(BoxedList* l) : Box(&list_iterator_flavor, list_iterator_cls), l(l), pos(0) { -} - -Box* listIter(Box* s) { - assert(s->cls == list_cls); - BoxedList* self = static_cast(s); - return new BoxedListIterator(self); -} - -Box* listiterHasnext(Box* s) { - assert(s->cls == list_iterator_cls); - BoxedListIterator* self = static_cast(s); - - return boxBool(self->pos < self->l->size); -} - -i1 listiterHasnextUnboxed(Box* s) { - assert(s->cls == list_iterator_cls); - BoxedListIterator* self = static_cast(s); - - return self->pos < self->l->size; -} - -Box* listiterNext(Box* s) { - assert(s->cls == list_iterator_cls); - BoxedListIterator* self = static_cast(s); - - assert(self->pos >= 0 && self->pos < self->l->size); - Box* rtn = self->l->elts->elts[self->pos]; - self->pos++; - return rtn; -} - -// TODO the inliner doesn't want to inline these; is there any point to having them in the inline section? -void BoxedList::ensure(int space) { - if (size + space > capacity) { - if (capacity == 0) { - const int INITIAL_CAPACITY = 8; - int initial = std::max(INITIAL_CAPACITY, space); - elts = new (initial) BoxedList::ElementArray(); - capacity = initial; - } else { - int new_capacity = std::max(capacity * 2, size + space); - elts = (BoxedList::ElementArray*)rt_realloc(elts, new_capacity * sizeof(Box*) + sizeof(BoxedList::ElementArray)); - capacity = new_capacity; - } - } - assert(capacity >= size + space); -} - -// TODO the inliner doesn't want to inline these; is there any point to having them in the inline section? -extern "C" void listAppendInternal(Box* s, Box* v) { - assert(s->cls == list_cls); - BoxedList* self = static_cast(s); - - assert(self->size <= self->capacity); - self->ensure(1); - - assert(self->size < self->capacity); - self->elts->elts[self->size] = v; - self->size++; -} - -// TODO the inliner doesn't want to inline these; is there any point to having them in the inline section? -extern "C" Box* listAppend(Box* s, Box* v) { - assert(s->cls == list_cls); - BoxedList* self = static_cast(s); - - listAppendInternal(self, v); - - return None; -} - -} diff --git a/src/runtime/inline/xrange.cpp b/src/runtime/inline/xrange.cpp deleted file mode 100644 index 10b17d052..000000000 --- a/src/runtime/inline/xrange.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/types.h" - -#include "runtime/types.h" -#include "runtime/objmodel.h" -#include "runtime/gc_runtime.h" - -#include "codegen/compvars.h" - -namespace pyston { - -extern "C" const ObjectFlavor xrange_flavor(&boxGCHandler, NULL); - -extern "C" const ObjectFlavor xrange_iterator_flavor; -BoxedClass *xrange_cls, *xrange_iterator_cls; - -class BoxedXrangeIterator; -class BoxedXrange : public Box { - private: - const int64_t start, stop, step; - - public: - BoxedXrange(i64 start, i64 stop, i64 step) : Box(&xrange_flavor, xrange_cls), start(start), stop(stop), step(step) {} - - friend class BoxedXrangeIterator; -}; - -class BoxedXrangeIterator : public Box { - private: - BoxedXrange * const xrange; - int64_t cur; - - public: - BoxedXrangeIterator(BoxedXrange *xrange) : Box(&xrange_iterator_flavor, xrange_iterator_cls), xrange(xrange), cur(xrange->start) { - } - - static void xrangeIteratorDtor(Box *s) __attribute__((visibility("default"))) { - assert(s->cls == xrange_iterator_cls); - BoxedXrangeIterator *self = static_cast(s); - } - - static Box* xrangeIteratorHasnext(Box *s) __attribute__((visibility("default"))) { - assert(s->cls == xrange_iterator_cls); - BoxedXrangeIterator *self = static_cast(s); - assert(self->xrange->step > 0); - return boxBool(self->cur < self->xrange->stop); - } - - static bool xrangeIteratorHasnextUnboxed(Box *s) __attribute__((visibility("default"))) { - assert(s->cls == xrange_iterator_cls); - BoxedXrangeIterator *self = static_cast(s); - assert(self->xrange->step > 0); - return self->cur < self->xrange->stop; - } - - static Box* xrangeIteratorNext(Box *s) __attribute__((visibility("default"))) { - assert(s->cls == xrange_iterator_cls); - BoxedXrangeIterator *self = static_cast(s); - - i64 rtn = self->cur; - self->cur += self->xrange->step; - return boxInt(rtn); - } - - static i64 xrangeIteratorNextUnboxed(Box *s) __attribute__((visibility("default"))) { - assert(s->cls == xrange_iterator_cls); - BoxedXrangeIterator *self = static_cast(s); - - i64 rtn = self->cur; - self->cur += self->xrange->step; - return rtn; - } - - static void xrangeIteratorGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - - BoxedXrangeIterator *it = (BoxedXrangeIterator*)p; - v->visit(it->xrange); - } -}; -extern "C" const ObjectFlavor xrange_iterator_flavor(&BoxedXrangeIterator::xrangeIteratorGCHandler, NULL); - -Box* xrange1(Box* cls, Box* stop) { - assert(cls == xrange_cls); - RELEASE_ASSERT(stop->cls == int_cls, "%s", getTypeName(stop)->c_str()); - - i64 istop = static_cast(stop)->n; - return new BoxedXrange(0, istop, 1); -} - -Box* xrange2(Box* cls, Box* start, Box* stop) { - assert(cls == xrange_cls); - RELEASE_ASSERT(start->cls == int_cls, "%s", getTypeName(start)->c_str()); - RELEASE_ASSERT(stop->cls == int_cls, "%s", getTypeName(stop)->c_str()); - - i64 istart = static_cast(start)->n; - i64 istop = static_cast(stop)->n; - return new BoxedXrange(istart, istop, 1); -} - -Box* xrange3(Box* cls, Box* start, Box* stop, Box** args) { - Box* step = args[0]; - - assert(cls == xrange_cls); - RELEASE_ASSERT(start->cls == int_cls, "%s", getTypeName(start)->c_str()); - RELEASE_ASSERT(stop->cls == int_cls, "%s", getTypeName(stop)->c_str()); - RELEASE_ASSERT(step->cls == int_cls, "%s", getTypeName(step)->c_str()); - - i64 istart = static_cast(start)->n; - i64 istop = static_cast(stop)->n; - i64 istep = static_cast(step)->n; - RELEASE_ASSERT(istep != 0, "step can't be 0"); - return new BoxedXrange(istart, istop, istep); -} - -Box* xrangeIter(Box* self) { - assert(self->cls == xrange_cls); - - Box* rtn = new BoxedXrangeIterator(static_cast(self)); - return rtn; -} - -void setupXrange() { - xrange_cls = new BoxedClass(false, NULL); - xrange_cls->giveAttr("__name__", boxStrConstant("xrange")); - xrange_iterator_cls = new BoxedClass(false, (BoxedClass::Dtor)BoxedXrangeIterator::xrangeIteratorDtor); - xrange_iterator_cls->giveAttr("__name__", boxStrConstant("rangeiterator")); - - CLFunction *xrange_clf = boxRTFunction((void*)xrange1, NULL, 2, false); - addRTFunction(xrange_clf, (void*)xrange2, NULL, 3, false); - addRTFunction(xrange_clf, (void*)xrange3, NULL, 4, false); - xrange_cls->giveAttr("__new__", new BoxedFunction(xrange_clf)); - xrange_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)xrangeIter, typeFromClass(xrange_iterator_cls), 1, false))); - - CLFunction *hasnext = boxRTFunction((void*)BoxedXrangeIterator::xrangeIteratorHasnextUnboxed, BOOL, 1, false); - addRTFunction(hasnext, (void*)BoxedXrangeIterator::xrangeIteratorHasnext, BOXED_BOOL, 1, false); - xrange_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); - - CLFunction *next = boxRTFunction((void*)BoxedXrangeIterator::xrangeIteratorNextUnboxed, INT, 1, false); - addRTFunction(next, (void*)BoxedXrangeIterator::xrangeIteratorNext, BOXED_INT, 1, false); - xrange_iterator_cls->giveAttr("next", new BoxedFunction(next)); - - // TODO this is pretty hacky, but stuff the iterator cls into xrange to make sure it gets decref'd at the end - xrange_cls->giveAttr("__iterator_cls__", xrange_iterator_cls); - - xrange_cls->freeze(); - xrange_iterator_cls->freeze(); -} - -} diff --git a/src/runtime/inline/xrange.h b/src/runtime/inline/xrange.h deleted file mode 100644 index 8902435ef..000000000 --- a/src/runtime/inline/xrange.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_INLINE_XRANGE_H -#define PYSTON_RUNTIME_INLINE_XRANGE_H - -namespace pyston { - -void setupXrange(); - -} - -#endif diff --git a/src/runtime/int.cpp b/src/runtime/int.cpp deleted file mode 100644 index ff3566610..000000000 --- a/src/runtime/int.cpp +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/common.h" -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/int.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -#include "runtime/inline/boxing.h" - -#include "gc/collector.h" - -#include "codegen/compvars.h" - -namespace pyston { - -BoxedInt* interned_ints[NUM_INTERNED_INTS]; - -// Could add this to the others, but the inliner should be smart enough -// that this isn't needed: -extern "C" i64 add_i64_i64(i64 lhs, i64 rhs) { - return lhs + rhs; -} - -extern "C" i64 sub_i64_i64(i64 lhs, i64 rhs) { - return lhs - rhs; -} - -extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) { - if (rhs == 0) { - fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n"); - raiseExc(); - } - if (lhs < 0 && rhs > 0) - return (lhs - rhs + 1) / rhs; - if (lhs > 0 && rhs < 0) - return (lhs - rhs - 1) / rhs; - return lhs / rhs; -} - -extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) { - if (rhs == 0) { - fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n"); - raiseExc(); - } - if (lhs < 0 && rhs > 0) - return ((lhs + 1) % rhs) + (rhs - 1); - if (lhs > 0 && rhs < 0) - return ((lhs - 1) % rhs) + (rhs + 1); - return lhs % rhs; -} - -extern "C" i64 pow_i64_i64(i64 lhs, i64 rhs) { - // TODO overflow very possible - i64 rtn = 1, curpow = lhs; - RELEASE_ASSERT(rhs >= 0, ""); - while (rhs) { - if (rhs & 1) - rtn *= curpow; - curpow *= curpow; - rhs >>= 1; - } - return rtn; -} - -extern "C" i64 mul_i64_i64(i64 lhs, i64 rhs) { - return lhs * rhs; -} - -extern "C" i1 eq_i64_i64(i64 lhs, i64 rhs) { - return lhs == rhs; -} - -extern "C" i1 ne_i64_i64(i64 lhs, i64 rhs) { - return lhs != rhs; -} - -extern "C" i1 lt_i64_i64(i64 lhs, i64 rhs) { - return lhs < rhs; -} - -extern "C" i1 le_i64_i64(i64 lhs, i64 rhs) { - return lhs <= rhs; -} - -extern "C" i1 gt_i64_i64(i64 lhs, i64 rhs) { - return lhs > rhs; -} - -extern "C" i1 ge_i64_i64(i64 lhs, i64 rhs) { - return lhs >= rhs; -} - - -extern "C" Box* intAddInt(BoxedInt* lhs, BoxedInt *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == int_cls); - return boxInt(lhs->n + rhs->n); -} - -extern "C" Box* intAddFloat(BoxedInt* lhs, BoxedFloat *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == float_cls); - return boxFloat(lhs->n + rhs->d); -} - -extern "C" Box* intAdd(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n + rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->n + rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* intAnd(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n & rhs_int->n); -} - -extern "C" Box* intDivInt(BoxedInt* lhs, BoxedInt *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == int_cls); - return boxInt(div_i64_i64(lhs->n, rhs->n)); -} - -extern "C" Box* intDivFloat(BoxedInt* lhs, BoxedFloat *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == float_cls); - - if (rhs->d == 0) { - fprintf(stderr, "float divide by zero\n"); - raiseExc(); - } - return boxFloat(lhs->n / rhs->d); -} - -extern "C" Box* intDiv(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls == int_cls) { - return intDivInt(lhs, static_cast(rhs)); - } else if (rhs->cls == float_cls) { - return intDivFloat(lhs, static_cast(rhs)); - } else { - return NotImplemented; - } -} - -extern "C" Box* intEq(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n == rhs_int->n); -} - -extern "C" Box* intNe(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n != rhs_int->n); -} - -extern "C" Box* intLt(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n < rhs_int->n); -} - -extern "C" Box* intLe(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n <= rhs_int->n); -} - -extern "C" Box* intGt(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n > rhs_int->n); -} - -extern "C" Box* intGe(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxBool(lhs->n >= rhs_int->n); -} - -extern "C" Box* intLShift(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n << rhs_int->n); -} - -extern "C" Box* intMod(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - - return boxInt(mod_i64_i64(lhs->n, rhs_int->n)); -} - -extern "C" Box* intMulInt(BoxedInt* lhs, BoxedInt *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == int_cls); - return boxInt(lhs->n * rhs->n); -} - -extern "C" Box* intMulFloat(BoxedInt* lhs, BoxedFloat *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == float_cls); - return boxFloat(lhs->n * rhs->d); -} - -extern "C" Box* intMul(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n * rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->n * rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* intPow(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(pow_i64_i64(lhs->n, rhs_int->n)); -} - -extern "C" Box* intRShift(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls != int_cls) { - return NotImplemented; - } - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n >> rhs_int->n); -} - -extern "C" Box* intSubInt(BoxedInt* lhs, BoxedInt *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == int_cls); - return boxInt(lhs->n - rhs->n); -} - -extern "C" Box* intSubFloat(BoxedInt* lhs, BoxedFloat *rhs) { - assert(lhs->cls == int_cls); - assert(rhs->cls == float_cls); - return boxFloat(lhs->n - rhs->d); -} - -extern "C" Box* intSub(BoxedInt* lhs, Box *rhs) { - assert(lhs->cls == int_cls); - if (rhs->cls == int_cls) { - BoxedInt *rhs_int = static_cast(rhs); - return boxInt(lhs->n - rhs_int->n); - } else if (rhs->cls == float_cls) { - BoxedFloat *rhs_float = static_cast(rhs); - return boxFloat(lhs->n - rhs_float->d); - } else { - return NotImplemented; - } -} - -extern "C" Box* intInvert(BoxedInt* v) { - assert(v->cls == int_cls); - return boxInt(~v->n); -} - -extern "C" Box* intPos(BoxedInt* v) { - assert(v->cls == int_cls); - return v; -} - -extern "C" Box* intNeg(BoxedInt* v) { - assert(v->cls == int_cls); - return boxInt(-v->n); -} - -extern "C" Box* intNonzero(BoxedInt* v) { - assert(v->cls == int_cls); - return boxBool(v->n != 0); -} - -extern "C" BoxedString* intRepr(BoxedInt* v) { - assert(v->cls == int_cls); - char buf[80]; - int len = snprintf(buf, 80, "%ld", v->n); - return new BoxedString(std::string(buf, len)); -} - -extern "C" Box* intHash(BoxedInt* self) { - assert(self->cls == int_cls); - return self; -} - -extern "C" Box* intNew1(Box* cls) { - assert(cls == int_cls); - return new BoxedInt(0); -} - -extern "C" Box* intNew2(Box* cls, Box* val) { - assert(cls == int_cls); - - if (val->cls == int_cls) { - return val; - } else if (val->cls == str_cls) { - BoxedString *s = static_cast(val); - - std::istringstream ss(s->s); - int64_t n; - ss >> n; - return boxInt(n); - } else if (val->cls == float_cls) { - double d = static_cast(val)->d; - - return boxInt(d); - } else { - fprintf(stderr, "int() argument must be a string or a number, not '%s'\n", getTypeName(val)->c_str()); - raiseExc(); - } -} - -extern "C" Box* intInit1(BoxedInt* self) { - assert(self->cls == int_cls); - - return None; -} - -extern "C" Box* intInit2(BoxedInt* self, Box* val) { - assert(self->cls == int_cls); - - return None; -} - -static void _addFunc(const char* name, void* int_func, void* float_func, void* boxed_func) { - std::vector v_ii, v_if, v_iu; - assert(BOXED_INT); - v_ii.push_back(BOXED_INT); v_ii.push_back(BOXED_INT); - v_if.push_back(BOXED_INT); v_if.push_back(BOXED_FLOAT); - v_iu.push_back(BOXED_INT); v_iu.push_back(NULL); - - CLFunction *cl = createRTFunction(); - addRTFunction(cl, int_func, NULL, v_ii, false); - addRTFunction(cl, float_func, NULL, v_if, false); - addRTFunction(cl, boxed_func, NULL, v_iu, false); - int_cls->giveAttr(name, new BoxedFunction(cl)); -} - -void setupInt() { - int_cls->giveAttr("__name__", boxStrConstant("int")); - - //int_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)intAdd, NULL, 2, false))); - _addFunc("__add__", (void*)intAddInt, (void*)intAddFloat, (void*)intAdd); - int_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)intAnd, NULL, 2, false))); - _addFunc("__div__", (void*)intDivInt, (void*)intDivFloat, (void*)intDiv); - //int_cls->giveAttr("__div__", new BoxedFunction(boxRTFunction((void*)intDiv, NULL, 2, false))); - int_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)intEq, NULL, 2, false))); - int_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)intNe, NULL, 2, false))); - int_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)intLt, NULL, 2, false))); - int_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)intLe, NULL, 2, false))); - int_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)intGt, NULL, 2, false))); - int_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)intGe, NULL, 2, false))); - int_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)intLShift, NULL, 2, false))); - int_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)intMod, NULL, 2, false))); - _addFunc("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul); - //int_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)intMul, NULL, 2, false))); - int_cls->giveAttr("__pow__", new BoxedFunction(boxRTFunction((void*)intPow, NULL, 2, false))); - int_cls->giveAttr("__rshift__", new BoxedFunction(boxRTFunction((void*)intRShift, NULL, 2, false))); - _addFunc("__sub__", (void*)intSubInt, (void*)intSubFloat, (void*)intSub); - //int_cls->giveAttr("__sub__", new BoxedFunction(boxRTFunction((void*)intSub, NULL, 2, false))); - - int_cls->giveAttr("__invert__", new BoxedFunction(boxRTFunction((void*)intInvert, NULL, 1, false))); - int_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)intPos, NULL, 1, false))); - int_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)intNeg, NULL, 1, false))); - int_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)intNonzero, NULL, 1, false))); - int_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)intRepr, NULL, 1, false))); - int_cls->setattr("__str__", int_cls->peekattr("__repr__"), NULL, NULL); - int_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)intHash, NULL, 1, false))); - - CLFunction *__new__ = boxRTFunction((void*)intNew1, NULL, 1, false); - addRTFunction(__new__, (void*)intNew2, NULL, 2, false); - int_cls->giveAttr("__new__", new BoxedFunction(__new__)); - - CLFunction *__init__ = boxRTFunction((void*)intInit1, NULL, 1, false); - addRTFunction(__init__, (void*)intInit2, NULL, 2, false); - int_cls->giveAttr("__init__", new BoxedFunction(__init__)); - - int_cls->freeze(); - - for (int i = 0; i < NUM_INTERNED_INTS; i++) { - interned_ints[i] = new BoxedInt(i); - gc::registerStaticRootObj(interned_ints[i]); - } -} - -void teardownInt() { -} - -} diff --git a/src/runtime/int.h b/src/runtime/int.h deleted file mode 100644 index 2ac2c05a1..000000000 --- a/src/runtime/int.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_INT_H -#define PYSTON_RUNTIME_INT_H - -#include "core/common.h" - -#include "runtime/types.h" - -namespace pyston { - -extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; -extern "C" i64 div_i64_i64(i64 lhs, i64 rhs); -extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; -extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs); - -extern "C" i64 add_i64_i64(i64 lhs, i64 rhs) ALWAYSINLINE; -extern "C" i64 add_i64_i64(i64 lhs, i64 rhs); -extern "C" i64 sub_i64_i64(i64 lhs, i64 rhs); -extern "C" i64 pow_i64_i64(i64 lhs, i64 rhs); -extern "C" i64 mul_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 eq_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 ne_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 lt_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 le_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 gt_i64_i64(i64 lhs, i64 rhs); -extern "C" i1 ge_i64_i64(i64 lhs, i64 rhs); -extern "C" Box* intAdd(BoxedInt* lhs, Box *rhs); -extern "C" Box* intAnd(BoxedInt* lhs, Box *rhs); -extern "C" Box* intDiv(BoxedInt* lhs, Box *rhs); -extern "C" Box* intEq(BoxedInt* lhs, Box *rhs); -extern "C" Box* intNe(BoxedInt* lhs, Box *rhs); -extern "C" Box* intLt(BoxedInt* lhs, Box *rhs); -extern "C" Box* intLe(BoxedInt* lhs, Box *rhs); -extern "C" Box* intGt(BoxedInt* lhs, Box *rhs); -extern "C" Box* intGe(BoxedInt* lhs, Box *rhs); -extern "C" Box* intLShift(BoxedInt* lhs, Box *rhs); -extern "C" Box* intMod(BoxedInt* lhs, Box *rhs); -extern "C" Box* intMul(BoxedInt* lhs, Box *rhs); -extern "C" Box* intRShift(BoxedInt* lhs, Box *rhs); -extern "C" Box* intSub(BoxedInt* lhs, Box *rhs); -extern "C" Box* intInvert(BoxedInt* v); -extern "C" Box* intPos(BoxedInt* v); -extern "C" Box* intNeg(BoxedInt* v); -extern "C" Box* intNonzero(BoxedInt* v); -extern "C" BoxedString* intRepr(BoxedInt* v); -extern "C" Box* intHash(BoxedInt* self); -extern "C" Box* intNew1(Box* cls); -extern "C" Box* intNew2(Box* cls, Box* val); -extern "C" Box* intInit1(BoxedInt* self); -extern "C" Box* intInit2(BoxedInt* self, Box* val); - -#define NUM_INTERNED_INTS 100 -extern BoxedInt* interned_ints[NUM_INTERNED_INTS]; - -} - -#endif diff --git a/src/runtime/list.cpp b/src/runtime/list.cpp deleted file mode 100644 index 783be6a69..000000000 --- a/src/runtime/list.cpp +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "core/common.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/list.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -#include "codegen/compvars.h" - -#include "gc/collector.h" - -namespace pyston { - -extern "C" Box* listRepr(BoxedList* self) { - // TODO highly inefficient with all the string copying - std::ostringstream os; - os << '['; - for (int i = 0; i < self->size; i++) { - if (i > 0) - os << ", "; - - BoxedString *s = repr(self->elts->elts[i]); - os << s->s; - } - os << ']'; - return new BoxedString(os.str()); -} - -extern "C" Box* listNonzero(BoxedList* self) { - return boxBool(self->size != 0); -} - -extern "C" Box* listPop1(BoxedList* self) { - if (self->size == 0) { - fprintf(stderr, "IndexError: pop from empty list\n"); - raiseExc(); - } - - self->size--; - Box* rtn = self->elts->elts[self->size]; - return rtn; -} - -extern "C" Box* listPop2(BoxedList* self, Box* idx) { - if (idx->cls != int_cls) { - fprintf(stderr, "TypeError: an integer is required\n"); - raiseExc(); - } - - int64_t n = static_cast(idx)->n; - if (n < 0) - n = self->size + n; - - if (n < 0 || n >= self->size) { - if (self->size == 0) - fprintf(stderr, "IndexError: pop from empty list\n"); - else - fprintf(stderr, "IndexError: pop index out of range\n"); - raiseExc(); - } - - Box* rtn = self->elts->elts[n]; - memmove(self->elts->elts + n, self->elts->elts + n + 1, (self->size - n - 1) * sizeof(Box*)); - self->size--; - - return rtn; -} - -extern "C" Box* listLen(BoxedList* self) { - return new BoxedInt(self->size); -} - -Box* _listSlice(BoxedList *self, i64 start, i64 stop, i64 step) { - //printf("%ld %ld %ld\n", start, stop, step); - assert(step != 0); - if (step > 0) { - assert(0 <= start); - assert(stop <= self->size); - } else { - assert(start < self->size); - assert(-1 <= stop); - } - - BoxedList *rtn = new BoxedList(); - - int cur = start; - while ((step > 0 && cur < stop) || (step < 0 && cur > stop)) { - listAppendInternal(rtn, self->elts->elts[cur]); - cur += step; - } - return rtn; -} - -extern "C" Box* listGetitem(BoxedList* self, Box* slice) { - if (slice->cls == int_cls) { - BoxedInt* islice = static_cast(slice); - int64_t n = islice->n; - if (n < 0) - n = self->size + n; - - if (n < 0 || n >= self->size) { - fprintf(stderr, "IndexError: list index out of range\n"); - raiseExc(); - } - Box* rtn = self->elts->elts[n]; - return rtn; - } else if (slice->cls == slice_cls) { - BoxedSlice *sslice = static_cast(slice); - - i64 start, stop, step; - parseSlice(sslice, self->size, &start, &stop, &step); - return _listSlice(self, start, stop, step); - } else { - fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str()); - raiseExc(); - } -} - -extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) { - if (slice->cls == int_cls) { - BoxedInt* islice = static_cast(slice); - int64_t n = islice->n; - if (n < 0) - n = self->size + n; - - if (n < 0 || n >= self->size) { - fprintf(stderr, "IndexError: list index out of range\n"); - raiseExc(); - } - - Box* prev = self->elts->elts[n]; - self->elts->elts[n] = v; - - return None; - } else if (slice->cls == slice_cls) { - BoxedSlice *sslice = static_cast(slice); - - i64 start, stop, step; - parseSlice(sslice, self->size, &start, &stop, &step); - RELEASE_ASSERT(step == 1, "step sizes must be 1 for now"); - - assert(0 <= start && start < self->size); - ASSERT(0 <= stop && stop <= self->size, "%ld %ld", self->size, stop); - assert(start <= stop); - - ASSERT(v->cls == list_cls, "unsupported %s", getTypeName(v)->c_str()); - BoxedList *lv = static_cast(v); - - int delts = lv->size - (stop - start); - int remaining_elts = self->size - stop; - self->ensure(delts); - - memmove(self->elts->elts + start + lv->size, self->elts->elts + stop, remaining_elts * sizeof(Box*)); - for (int i = 0; i < lv->size; i++) { - Box* r = lv->elts->elts[i]; - self->elts->elts[start + i] = r; - } - - self->size += delts; - - return None; - } else { - fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str()); - raiseExc(); - } -} - -extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) { - if (idx->cls != int_cls) { - fprintf(stderr, "TypeError: an integer is required\n"); - raiseExc(); - } - - int64_t n = static_cast(idx)->n; - if (n < 0) - n = self->size + n; - - if (n >= self->size) { - listAppendInternal(self, v); - } else { - if (n < 0) - n = 0; - assert(0 <= n && n < self->size); - - self->ensure(1); - memmove(self->elts->elts + n + 1, self->elts->elts + n, (self->size - n) * sizeof(Box*)); - - self->size++; - self->elts->elts[n] = v; - } - - return None; -} - -Box* listMul(BoxedList* self, Box* rhs) { - if (rhs->cls != int_cls) { - fprintf(stderr, "TypeError: can't multiply sequence by non-int of type '%s'\n", getTypeName(rhs)->c_str()); - raiseExc(); - } - - int n = static_cast(rhs)->n; - int s = self->size; - - BoxedList* rtn = new BoxedList(); - for (int i = 0; i < n; i++) { - for (int j = 0; j < s; j++) { - listAppendInternal(rtn, self->elts->elts[j]); - } - } - return rtn; -} - -BoxedClass *list_iterator_cls = NULL; -extern "C" void listIteratorGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - BoxedListIterator *it = (BoxedListIterator*)p; - v->visit(it->l); -} - -extern "C" const ObjectFlavor list_iterator_flavor(&listIteratorGCHandler, NULL); - -void listiterDtor(BoxedListIterator *self) { -} - -extern "C" Box* listNew1(Box* cls) { - assert(cls == list_cls); - return new BoxedList(); -} - -extern "C" Box* listNew2(Box* cls, Box* rhs) { - assert(cls == list_cls); - - RELEASE_ASSERT(rhs->cls == list_cls, "unsupported for now"); - BoxedList *lrhs = static_cast(rhs); - int size = lrhs->size; - - BoxedList *rtn = new BoxedList(); - rtn->elts = new (size) BoxedList::ElementArray(); - memcpy(rtn->elts->elts, lrhs->elts->elts, size * sizeof(Box*)); - rtn->size = size; - rtn->capacity = size; - return rtn; -} - -void list_dtor(BoxedList* self) { - if (self->capacity) - rt_free(self->elts); -} - -void setupList() { - list_iterator_cls = new BoxedClass(false, (BoxedClass::Dtor)listiterDtor); - - list_cls->giveAttr("__name__", boxStrConstant("list")); - - list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, NULL, 1, false))); - list_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)listGetitem, NULL, 2, false))); - list_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)listIter, typeFromClass(list_iterator_cls), 1, false))); - - list_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)listRepr, NULL, 1, false))); - list_cls->setattr("__str__", list_cls->peekattr("__repr__"), NULL, NULL); - list_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)listNonzero, NULL, 1, false))); - - CLFunction *pop = boxRTFunction((void*)listPop1, NULL, 1, false); - addRTFunction(pop, (void*)listPop2, NULL, 2, false); - list_cls->giveAttr("pop", new BoxedFunction(pop)); - - list_cls->giveAttr("append", new BoxedFunction(boxRTFunction((void*)listAppend, NULL, 2, false))); - list_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)listSetitem, NULL, 3, false))); - list_cls->giveAttr("insert", new BoxedFunction(boxRTFunction((void*)listInsert, NULL, 3, false))); - list_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)listMul, NULL, 2, false))); - - CLFunction *new_ = boxRTFunction((void*)listNew1, NULL, 1, false); - addRTFunction(new_, (void*)listNew2, NULL, 2, false); - list_cls->giveAttr("__new__", new BoxedFunction(new_)); - - list_cls->freeze(); - - - gc::registerStaticRootObj(list_iterator_cls); - list_iterator_cls->giveAttr("__name__", boxStrConstant("listiterator")); - - CLFunction *hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1, false); - addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL, 1, false); - list_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext)); - list_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)listiterNext, UNKNOWN, 1, false))); - - list_iterator_cls->freeze(); -} - -void teardownList() { - // TODO do clearattrs? - //decref(list_iterator_cls); -} - -} diff --git a/src/runtime/list.h b/src/runtime/list.h deleted file mode 100644 index f643c513e..000000000 --- a/src/runtime/list.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_LIST_H -#define PYSTON_RUNTIME_LIST_H - -#include "core/types.h" - -#include "runtime/types.h" - -namespace pyston { - -extern BoxedClass *list_iterator_cls; -struct BoxedListIterator : public Box { - BoxedList *l; - int pos; - BoxedListIterator(BoxedList* l); -}; - -extern "C" const ObjectFlavor list_iterator_flavor; -Box* listIter(Box* self); -Box* listiterHasnext(Box *self); -i1 listiterHasnextUnboxed(Box *self); -Box* listiterNext(Box *self); -extern "C" Box* listAppend(Box* self, Box* v); - -} - -#endif diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp deleted file mode 100644 index b6c902de5..000000000 --- a/src/runtime/objmodel.cpp +++ /dev/null @@ -1,2138 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include "core/ast.h" -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "asm_writing/icinfo.h" -#include "asm_writing/rewriter.h" -#include "asm_writing/rewriter2.h" - -#include "runtime/gc_runtime.h" -#include "runtime/importing.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -#define BOX_NREFS_OFFSET ((char*)&(((HCBox*)0x01)->nrefs) - (char*)0x1) -#define BOX_CLS_OFFSET ((char*)&(((HCBox*)0x01)->cls) - (char*)0x1) -#define BOX_HCLS_OFFSET ((char*)&(((HCBox*)0x01)->hcls) - (char*)0x1) -#define BOX_ATTRS_OFFSET ((char*)&(((HCBox*)0x01)->attr_list) - (char*)0x1) -#define ATTRLIST_ATTRS_OFFSET ((char*)&(((HCBox::AttrList*)0x01)->attrs) - (char*)0x1) -#define ATTRLIST_KIND_OFFSET ((char*)&(((HCBox::AttrList*)0x01)->gc_header.kind_id) - (char*)0x1) -#define INSTANCEMETHOD_FUNC_OFFSET ((char*)&(((BoxedInstanceMethod*)0x01)->func) - (char*)0x1) -#define INSTANCEMETHOD_OBJ_OFFSET ((char*)&(((BoxedInstanceMethod*)0x01)->obj) - (char*)0x1) -#define BOOL_B_OFFSET ((char*)&(((BoxedBool*)0x01)->b) - (char*)0x1) -#define INT_N_OFFSET ((char*)&(((BoxedInt*)0x01)->n) - (char*)0x1) - -namespace pyston { - -struct GetattrRewriteArgs { - Rewriter *rewriter; - RewriterVar obj; - bool out_success; - RewriterVar out_rtn; - - bool obj_hcls_guarded; - int preferred_dest_reg; - - GetattrRewriteArgs(Rewriter *rewriter, const RewriterVar &obj) : - rewriter(rewriter), obj(obj), out_success(false), obj_hcls_guarded(false), preferred_dest_reg(-1) { - } -}; - -struct GetattrRewriteArgs2 { - Rewriter2 *rewriter; - RewriterVarUsage2 obj; - Location destination; - bool more_guards_after; - - bool out_success; - RewriterVarUsage2 out_rtn; - - bool obj_hcls_guarded; - - GetattrRewriteArgs2(Rewriter2 *rewriter, RewriterVarUsage2 &&obj, Location destination, bool more_guards_after) : - rewriter(rewriter), obj(std::move(obj)), destination(destination), more_guards_after(more_guards_after), out_success(false), out_rtn(RewriterVarUsage2::empty()), obj_hcls_guarded(false) { - } -}; - -struct SetattrRewriteArgs { - Rewriter *rewriter; - RewriterVar obj, attrval; - bool out_success; - - SetattrRewriteArgs(Rewriter *rewriter, const RewriterVar &obj, const RewriterVar &attrval) : - rewriter(rewriter), obj(obj), attrval(attrval), out_success(false) { - } -}; - -struct SetattrRewriteArgs2 { - Rewriter2 *rewriter; - RewriterVarUsage2 obj, attrval; - bool more_guards_after; - - bool out_success; - - SetattrRewriteArgs2(Rewriter2 *rewriter, RewriterVarUsage2 &&obj, RewriterVarUsage2 &&attrval, bool more_guards_after) : - rewriter(rewriter), obj(std::move(obj)), attrval(std::move(attrval)), more_guards_after(more_guards_after), out_success(false) { - } -}; - -struct LenRewriteArgs { - Rewriter *rewriter; - RewriterVar obj; - bool out_success; - RewriterVar out_rtn; - - int preferred_dest_reg; - - LenRewriteArgs(Rewriter *rewriter, const RewriterVar &obj) : - rewriter(rewriter), obj(obj), out_success(false), preferred_dest_reg(-1) { - } -}; - -struct CallRewriteArgs { - Rewriter *rewriter; - RewriterVar obj; - RewriterVar arg1, arg2, arg3, args; - bool out_success; - RewriterVar out_rtn; - bool func_guarded; - bool args_guarded; - - int preferred_dest_reg; - - CallRewriteArgs(Rewriter *rewriter, const RewriterVar &obj) : - rewriter(rewriter), obj(obj), out_success(false), func_guarded(false), args_guarded(false), preferred_dest_reg(-1) { - } -}; - -struct CompareRewriteArgs { - Rewriter *rewriter; - RewriterVar lhs, rhs; - bool out_success; - RewriterVar out_rtn; - - CompareRewriteArgs(Rewriter *rewriter, const RewriterVar &lhs, - const RewriterVar &rhs) : rewriter(rewriter), lhs(lhs), rhs(rhs), out_success(false) { - } -}; - -Box* runtimeCallInternal(Box* obj, CallRewriteArgs *rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box* *args); -static Box* (*runtimeCallInternal0)(Box*, CallRewriteArgs*, int64_t) = (Box* (*)(Box*, CallRewriteArgs*, int64_t))runtimeCallInternal; -static Box* (*runtimeCallInternal1)(Box*, CallRewriteArgs*, int64_t, Box*) = (Box* (*)(Box*, CallRewriteArgs*, int64_t, Box*))runtimeCallInternal; -static Box* (*runtimeCallInternal2)(Box*, CallRewriteArgs*, int64_t, Box*, Box*) = (Box* (*)(Box*, CallRewriteArgs*, int64_t, Box*, Box*))runtimeCallInternal; -static Box* (*runtimeCallInternal3)(Box*, CallRewriteArgs*, int64_t, Box*, Box*, Box*) = (Box* (*)(Box*, CallRewriteArgs*, int64_t, Box*, Box*, Box*))runtimeCallInternal; - -Box* typeCallInternal(CallRewriteArgs *rewrite_args, int64_t nargs, Box* obj, Box* arg1, Box* arg2, Box** args); -static Box* (*typeCallInternal1)(CallRewriteArgs *rewrite_args, int64_t nargs, Box*) = (Box* (*)(CallRewriteArgs*, int64_t, Box*))typeCallInternal; -static Box* (*typeCallInternal2)(CallRewriteArgs *rewrite_args, int64_t nargs, Box*, Box*) = (Box* (*)(CallRewriteArgs*, int64_t, Box*, Box*))typeCallInternal; -static Box* (*typeCallInternal3)(CallRewriteArgs *rewrite_args, int64_t nargs, Box*, Box*, Box*) = (Box* (*)(CallRewriteArgs*, int64_t, Box*, Box*, Box*))typeCallInternal; - -enum LookupScope { - CLASS_ONLY = 1, - INST_ONLY = 2, - CLASS_OR_INST = 3, -}; -bool checkClass(LookupScope scope) { - return (scope & CLASS_ONLY) != 0; -} -bool checkInst(LookupScope scope) { - return (scope & INST_ONLY) != 0; -} -extern "C" Box* callattrInternal(Box* obj, const std::string *attr, LookupScope, CallRewriteArgs *rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box **args); -static Box* (*callattrInternal0)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t) = (Box* (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t))callattrInternal; -static Box* (*callattrInternal1)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*) = (Box* (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*))callattrInternal; -static Box* (*callattrInternal2)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*) = (Box* (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*))callattrInternal; -static Box* (*callattrInternal3)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*, Box*) = (Box* (*)(Box*, const std::string*, LookupScope, CallRewriteArgs*, int64_t, Box*, Box*, Box*))callattrInternal; - -size_t PyHasher::operator() (Box* b) const { - if (b->cls == str_cls) { - std::hash H; - return H(static_cast(b)->s); - } - - BoxedInt *i = hash(b); - assert(sizeof(size_t) == sizeof(i->n)); - size_t rtn = i->n; - return rtn; -} - -bool PyEq::operator() (Box* lhs, Box* rhs) const { - if (lhs->cls == rhs->cls) { - if (lhs->cls == str_cls) { - return static_cast(lhs)->s == static_cast(rhs)->s; - } - } - - // TODO fix this - Box* cmp = compareInternal(lhs, rhs, AST_TYPE::Eq, NULL); - assert(cmp->cls == bool_cls); - BoxedBool* b = static_cast(cmp); - bool rtn = b->b; - return rtn; -} - -bool PyLt::operator() (Box* lhs, Box* rhs) const { - // TODO fix this - Box* cmp = compareInternal(lhs, rhs, AST_TYPE::Lt, NULL); - assert(cmp->cls == bool_cls); - BoxedBool* b = static_cast(cmp); - bool rtn = b->b; - return rtn; -} - -extern "C" void my_assert(bool b) { - assert(b); -} - -extern "C" void assertNameDefined(bool b, const char* name) { - if (!b) { - fprintf(stderr, "UnboundLocalError: local variable '%s' referenced before assignment\n", name); - raiseExc(); - } -} - -extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) { - fprintf(stderr, "AttributeError: '%s' object has no attribute '%s'\n", typeName, attr); - raiseExc(); -} - -extern "C" void raiseAttributeError(Box* obj, const char* attr) { - if (obj->cls == type_cls) { - fprintf(stderr, "AttributeError: type object '%s' has no attribute '%s'\n", getNameOfClass(static_cast(obj))->c_str(), attr); - } else { - raiseAttributeErrorStr(getTypeName(obj)->c_str(), attr); - } - raiseExc(); -} - -extern "C" void raiseNotIterableError(const char* typeName) { - fprintf(stderr, "TypeError: '%s' object is not iterable\n", typeName); - raiseExc(); -} - -extern "C" void checkUnpackingLength(i64 expected, i64 given) { - if (given == expected) - return; - - if (given > expected) - fprintf(stderr, "ValueError: too many values to unpack\n"); - else { - if (given == 1) - fprintf(stderr, "ValueError: need more than %ld value to unpack\n", given); - else - fprintf(stderr, "ValueError: need more than %ld values to unpack\n", given); - } - raiseExc(); -} - -BoxedClass::BoxedClass(bool hasattrs, BoxedClass::Dtor dtor): HCBox(&type_flavor, type_cls), hasattrs(hasattrs), dtor(dtor), is_constant(false) { -} - -extern "C" const std::string* getNameOfClass(BoxedClass* cls) { - Box* b = cls->peekattr("__name__"); - assert(b); - ASSERT(b->cls == str_cls, "%p", b->cls); - BoxedString* sb = static_cast(b); - return &sb->s; -} - -extern "C" const std::string* getTypeName(Box* o) { - return getNameOfClass(o->cls); -} - -HiddenClass* HiddenClass::getOrMakeChild(const std::string& attr) { - std::unordered_map::iterator it = children.find(attr); - if (it != children.end()) - return it->second; - - static StatCounter num_hclses("num_hidden_classes"); - num_hclses.log(); - - HiddenClass* rtn = new HiddenClass(this); - this->children[attr] = rtn; - rtn->attr_offsets[attr] = attr_offsets.size(); - return rtn; -} - -HiddenClass* HiddenClass::getRoot() { - static HiddenClass* root = new HiddenClass(); - return root; -} - -HCBox::HCBox(const ObjectFlavor *flavor, BoxedClass *cls) : Box(flavor, cls), hcls(HiddenClass::getRoot()), attr_list(NULL) { - assert(!cls || flavor->isUserDefined() == isUserDefined(cls)); - - // first part of this check is to handle if we're building "type" itself, since when - // it's constructed its type (which should be "type") is NULL. - assert((cls == NULL && type_cls == NULL) || cls->hasattrs); -} - - -Box* HCBox::getattr(const std::string &attr, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2) { - if (rewrite_args) { - rewrite_args->out_success = true; - - if (!rewrite_args->obj_hcls_guarded) - rewrite_args->obj.addAttrGuard(BOX_HCLS_OFFSET, (intptr_t)this->hcls); - } - - if (rewrite_args2) { - rewrite_args2->out_success = true; - - if (!rewrite_args2->obj_hcls_guarded) - rewrite_args2->obj.addAttrGuard(BOX_HCLS_OFFSET, (intptr_t)this->hcls); - } - - int offset = hcls->getOffset(attr); - if (offset == -1) - return NULL; - - if (rewrite_args) { - // TODO using the output register as the temporary makes register allocation easier - // since we don't need to clobber a register, but does it make the code slower? - //int temp_reg = -2; - //if (rewrite_args->preferred_dest_reg == -2) - //temp_reg = -3; - int temp_reg = rewrite_args->preferred_dest_reg; - - RewriterVar attrs = rewrite_args->obj.getAttr(BOX_ATTRS_OFFSET, temp_reg); - rewrite_args->out_rtn = attrs.getAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->preferred_dest_reg); - - rewrite_args->rewriter->addDependenceOn(cls->dependent_icgetattrs); - } - - if (rewrite_args2) { - if (!rewrite_args2->more_guards_after) - rewrite_args2->rewriter->setDoneGuarding(); - - RewriterVarUsage2 attrs = rewrite_args2->obj.getAttr(BOX_ATTRS_OFFSET, RewriterVarUsage2::Kill); - rewrite_args2->out_rtn = attrs.getAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, RewriterVarUsage2::Kill, rewrite_args2->destination); - } - - Box* rtn = attr_list->attrs[offset]; - return rtn; -} - -void HCBox::giveAttr(const std::string& attr, Box* val) { - assert(this->peekattr(attr) == NULL); - this->setattr(attr, val, NULL, NULL); -} - -void HCBox::setattr(const std::string& attr, Box* val, SetattrRewriteArgs *rewrite_args, SetattrRewriteArgs2 *rewrite_args2) { - RELEASE_ASSERT(attr != "None" || this == builtins_module, "can't assign to None"); - - bool isgetattr = (attr == "__getattr__" || attr == "__getattribute__"); - if (isgetattr && this->cls == type_cls) { - // Will have to embed the clear in the IC, so just disable the patching for now: - rewrite_args = NULL; - rewrite_args2 = NULL; - - // TODO should put this clearing behavior somewhere else, since there are probably more - // cases in which we want to do it. - BoxedClass *self = static_cast(this); - self->dependent_icgetattrs.invalidateAll(); - } - - HiddenClass *hcls = this->hcls; - int numattrs = hcls->attr_offsets.size(); - - int offset = hcls->getOffset(attr); - - if (rewrite_args) { - rewrite_args->obj.addAttrGuard(BOX_HCLS_OFFSET, (intptr_t)hcls); - rewrite_args->rewriter->addDecision(offset == -1 ? 1 : 0); - } - - if (rewrite_args2) { - rewrite_args2->obj.addAttrGuard(BOX_HCLS_OFFSET, (intptr_t)hcls); - - if (!rewrite_args2->more_guards_after) - rewrite_args2->rewriter->setDoneGuarding(); - //rewrite_args2->rewriter->addDecision(offset == -1 ? 1 : 0); - } - - if (offset >= 0) { - assert(offset < numattrs); - Box* prev = this->attr_list->attrs[offset]; - this->attr_list->attrs[offset] = val; - - if (rewrite_args) { - RewriterVar r_hattrs = rewrite_args->obj.getAttr(BOX_ATTRS_OFFSET, 1); - - r_hattrs.setAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval); - rewrite_args->out_success = true; - } - - if (rewrite_args2) { - - RewriterVarUsage2 r_hattrs = rewrite_args2->obj.getAttr(BOX_ATTRS_OFFSET, RewriterVarUsage2::Kill, Location::any()); - - r_hattrs.setAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, std::move(rewrite_args2->attrval)); - r_hattrs.setDoneUsing(); - - rewrite_args2->out_success = true; - } - - return; - } - - assert(offset == -1); - HiddenClass *new_hcls = hcls->getOrMakeChild(attr); - - // TODO need to make sure we don't need to rearrange the attributes - assert(new_hcls->attr_offsets[attr] == numattrs); -#ifndef NDEBUG - for (std::unordered_map::iterator it = hcls->attr_offsets.begin(), end = hcls->attr_offsets.end(); - it != end; ++it) { - assert(new_hcls->attr_offsets[it->first] == it->second); - } -#endif - - if (rewrite_args) { - rewrite_args->obj.push(); - rewrite_args->attrval.push(); - } - - - - RewriterVar r_new_array; - RewriterVarUsage2 r_new_array2(RewriterVarUsage2::empty()); - int new_size = sizeof(HCBox::AttrList) + sizeof(Box*) * (numattrs + 1); - if (numattrs == 0) { - this->attr_list = (HCBox::AttrList*)rt_alloc(new_size); - this->attr_list->gc_header.kind_id = untracked_kind.kind_id; - if (rewrite_args) { - rewrite_args->rewriter->loadConst(0, new_size); - r_new_array = rewrite_args->rewriter->call((void*)rt_alloc); - RewriterVar r_flavor = rewrite_args->rewriter->loadConst(0, (intptr_t)untracked_kind.kind_id); - r_new_array.setAttr(ATTRLIST_KIND_OFFSET, r_flavor); - } - if (rewrite_args2) { - RewriterVarUsage2 r_newsize = rewrite_args2->rewriter->loadConst(new_size, Location::forArg(0)); - r_new_array2 = rewrite_args2->rewriter->call(false, (void*)rt_alloc, std::move(r_newsize)); - RewriterVarUsage2 r_flavor = rewrite_args2->rewriter->loadConst((int64_t)untracked_kind.kind_id); - r_new_array2.setAttr(ATTRLIST_KIND_OFFSET, std::move(r_flavor)); - } - } else { - this->attr_list = (HCBox::AttrList*)rt_realloc(this->attr_list, new_size); - if (rewrite_args) { - rewrite_args->obj.getAttr(BOX_ATTRS_OFFSET, 0); - rewrite_args->rewriter->loadConst(1, new_size); - r_new_array = rewrite_args->rewriter->call((void*)rt_realloc); - } - if (rewrite_args2) { - RewriterVarUsage2 r_oldarray = rewrite_args2->obj.getAttr(BOX_ATTRS_OFFSET, RewriterVarUsage2::NoKill, Location::forArg(0)); - RewriterVarUsage2 r_newsize = rewrite_args2->rewriter->loadConst(new_size, Location::forArg(1)); - r_new_array2 = rewrite_args2->rewriter->call(false, (void*)rt_realloc, std::move(r_oldarray), std::move(r_newsize)); - } - } - // Don't set the new hcls until after we do the allocation for the new attr_list; - // that allocation can cause a collection, and we want the collector to always - // see a consistent state between the hcls and the attr_list - this->hcls = new_hcls; - - if (rewrite_args) { - RewriterVar attrval = rewrite_args->rewriter->pop(0); - RewriterVar obj = rewrite_args->rewriter->pop(2); - obj.setAttr(BOX_ATTRS_OFFSET, r_new_array); - r_new_array.setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, attrval); - RewriterVar hcls = rewrite_args->rewriter->loadConst(1, (intptr_t)new_hcls); - obj.setAttr(BOX_HCLS_OFFSET, hcls); - rewrite_args->out_success = true; - } - if (rewrite_args2) { - r_new_array2.setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, std::move(rewrite_args2->attrval)); - rewrite_args2->obj.setAttr(BOX_ATTRS_OFFSET, std::move(r_new_array2)); - - RewriterVarUsage2 r_hcls = rewrite_args2->rewriter->loadConst((intptr_t)new_hcls); - rewrite_args2->obj.setAttr(BOX_HCLS_OFFSET, std::move(r_hcls)); - rewrite_args2->obj.setDoneUsing(); - - rewrite_args2->out_success = true; - } - this->attr_list->attrs[numattrs] = val; -} - -static Box* _handleClsAttr(Box* obj, Box* attr) { - if (attr->cls == function_cls) { - Box* rtn = boxInstanceMethod(obj, attr); - return rtn; - } - return attr; -} - -Box* getclsattr_internal(Box* obj, const char* attr, GetattrRewriteArgs *rewrite_args, GetattrRewriteArgs2 *rewrite_args2) { - Box* val; - - if (rewrite_args) { - //rewrite_args->rewriter->nop(); - //rewrite_args->rewriter->trap(); - RewriterVar cls = rewrite_args->obj.getAttr(BOX_CLS_OFFSET, 4); - - //rewrite_args->obj.push(); - GetattrRewriteArgs sub_rewrite_args(rewrite_args->rewriter, cls); - sub_rewrite_args.preferred_dest_reg = 1; - val = getattr_internal(obj->cls, attr, false, false, &sub_rewrite_args, NULL); - //rewrite_args->obj = rewrite_args->rewriter->pop(0); - - if (!sub_rewrite_args.out_success) { - rewrite_args = NULL; - } else { - if (val) - rewrite_args->out_rtn = sub_rewrite_args.out_rtn; - } - } else if (rewrite_args2) { - RewriterVarUsage2 cls = rewrite_args2->obj.getAttr(BOX_CLS_OFFSET, RewriterVarUsage2::NoKill); - - GetattrRewriteArgs2 sub_rewrite_args(rewrite_args2->rewriter, std::move(cls), Location::forArg(1), rewrite_args2->more_guards_after); - val = getattr_internal(obj->cls, attr, false, false, NULL, &sub_rewrite_args); - - if (!sub_rewrite_args.out_success) { - sub_rewrite_args.obj.setDoneUsing(); - rewrite_args2 = NULL; - } else { - if (val) { - rewrite_args2->out_rtn = std::move(sub_rewrite_args.out_rtn); - } else { - sub_rewrite_args.obj.setDoneUsing(); - } - } - } else { - val = getattr_internal(obj->cls, attr, false, false, NULL, NULL); - } - - if (val == NULL) { - if (rewrite_args) rewrite_args->out_success = true; - if (rewrite_args2) rewrite_args2->out_success = true; - return val; - } - - if (rewrite_args) { - //rewrite_args->rewriter->trap(); - rewrite_args->obj = rewrite_args->obj.move(0); - RewriterVar val = rewrite_args->out_rtn.move(1); - - // TODO could speculate that the attr type is the same, ie guard on the attr type - // and then either always create the IM or never - RewriterVar rrtn = rewrite_args->rewriter->call((void*)_handleClsAttr); - rewrite_args->out_rtn = rrtn; - rewrite_args->out_success = true; - } - - if (rewrite_args2) { - // Ok this is a lie, _handleClsAttr can call back into python because it does GC collection. - // I guess it should disable GC or something... - RewriterVarUsage2 rrtn = rewrite_args2->rewriter->call(false, (void*)_handleClsAttr, std::move(rewrite_args2->obj), std::move(rewrite_args2->out_rtn)); - rewrite_args2->out_rtn = std::move(rrtn); - rewrite_args2->out_success = true; - } - - return _handleClsAttr(obj, val); -} - -extern "C" Box* getclsattr(Box* obj, const char* attr) { - static StatCounter slowpath_getclsattr("slowpath_getclsattr"); - slowpath_getclsattr.log(); - - Box* gotten; - -#if 0 - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, 1, "getclsattr")); - - if (rewriter.get()) { - //rewriter->trap(); - GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - gotten = getclsattr_internal(obj, attr, &rewrite_args, NULL); - - if (rewrite_args.out_success && gotten) { - rewrite_args.out_rtn.move(-1); - rewriter->commit(); - } -#else - std::unique_ptr rewriter(Rewriter2::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getclsattr")); - - if (rewriter.get()) { - //rewriter->trap(); - GetattrRewriteArgs2 rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination(), false); - gotten = getclsattr_internal(obj, attr, NULL, &rewrite_args); - - if (rewrite_args.out_success && gotten) { - rewriter->commitReturning(std::move(rewrite_args.out_rtn)); - } -#endif - } else { - gotten = getclsattr_internal(obj, attr, NULL, NULL); - } - RELEASE_ASSERT(gotten, "%s:%s", getTypeName(obj)->c_str(), attr); - - return gotten; -} - -static Box* (*runtimeCall0)(Box*, int64_t) = (Box* (*)(Box*, int64_t))runtimeCall; -static Box* (*runtimeCall1)(Box*, int64_t, Box*) = (Box* (*)(Box*, int64_t, Box*))runtimeCall; -static Box* (*runtimeCall2)(Box*, int64_t, Box*, Box*) = (Box* (*)(Box*, int64_t, Box*, Box*))runtimeCall; -static Box* (*runtimeCall3)(Box*, int64_t, Box*, Box*, Box*) = (Box* (*)(Box*, int64_t, Box*, Box*, Box*))runtimeCall; - -Box* getattr_internal(Box *obj, const char* attr, bool check_cls, bool allow_custom, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2) { - if (allow_custom) { - // Don't need to pass icentry args, since we special-case __getattribtue__ and __getattr__ to use - // invalidation rather than guards - Box* getattribute = getclsattr_internal(obj, "__getattribute__", NULL, NULL); - if (getattribute) { - // TODO this is a good candidate for interning? - Box* boxstr = boxStrConstant(attr); - Box* rtn = runtimeCall1(getattribute, 1, boxstr); - return rtn; - } - - if (rewrite_args) { - rewrite_args->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs); - } - if (rewrite_args2) { - rewrite_args2->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs); - } - } - - if (obj->cls->hasattrs) { - HCBox* hobj = static_cast(obj); - - Box* val = NULL; - if (rewrite_args) { - GetattrRewriteArgs hrewrite_args(rewrite_args->rewriter, rewrite_args->obj); - hrewrite_args.preferred_dest_reg = rewrite_args->preferred_dest_reg; - val = hobj->getattr(attr, &hrewrite_args, NULL); - - if (hrewrite_args.out_success) { - if (val) - rewrite_args->out_rtn = hrewrite_args.out_rtn; - } else { - rewrite_args = NULL; - } - } else if (rewrite_args2) { - GetattrRewriteArgs2 hrewrite_args(rewrite_args2->rewriter, std::move(rewrite_args2->obj), rewrite_args2->destination, rewrite_args2->more_guards_after); - val = hobj->getattr(attr, NULL, &hrewrite_args); - - if (hrewrite_args.out_success) { - if (val) - rewrite_args2->out_rtn = std::move(hrewrite_args.out_rtn); - else - rewrite_args2->obj = std::move(hrewrite_args.obj); - } else { - rewrite_args2 = NULL; - } - } else { - val = hobj->getattr(attr, NULL, NULL); - } - - if (val) { - if (rewrite_args) rewrite_args->out_success = true; - if (rewrite_args2) rewrite_args2->out_success = true; - return val; - } - } - - if (allow_custom) { - // Don't need to pass icentry args, since we special-case __getattribtue__ and __getattr__ to use - // invalidation rather than guards - Box* getattr = getclsattr_internal(obj, "__getattr__", NULL, NULL); - if (getattr) { - Box* boxstr = boxStrConstant(attr); - Box* rtn = runtimeCall1(getattr, 1, boxstr); - return rtn; - } - - if (rewrite_args) { - rewrite_args->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs); - } - if (rewrite_args2) { - rewrite_args2->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs); - } - } - - Box *rtn = NULL; - if (check_cls) { - if (rewrite_args) { - GetattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj); - rtn = getclsattr_internal(obj, attr, &crewrite_args, NULL); - - if (!crewrite_args.out_success) { - rewrite_args = NULL; - } else { - if (rtn) - rewrite_args->out_rtn = crewrite_args.out_rtn; - } - } else if (rewrite_args2) { - GetattrRewriteArgs2 crewrite_args(rewrite_args2->rewriter, std::move(rewrite_args2->obj), rewrite_args2->destination, rewrite_args2->more_guards_after); - rtn = getclsattr_internal(obj, attr, NULL, &crewrite_args); - - if (!crewrite_args.out_success) { - rewrite_args2 = NULL; - } else { - if (rtn) - rewrite_args2->out_rtn = std::move(crewrite_args.out_rtn); - else - rewrite_args2->obj = std::move(crewrite_args.obj); - } - } else { - rtn = getclsattr_internal(obj, attr, NULL, NULL); - } - } - if (rewrite_args) rewrite_args->out_success = true; - if (rewrite_args2) rewrite_args2->out_success = true; - - return rtn; -} - -extern "C" Box* getattr(Box* obj, const char* attr) { - static StatCounter slowpath_getattr("slowpath_getattr"); - slowpath_getattr.log(); - - if (VERBOSITY() >= 2) { - std::string per_name_stat_name = "getattr__" + std::string(attr); - int id = Stats::getStatId(per_name_stat_name); - Stats::log(id); - } - - { /* anonymous scope to make sure destructors get run before we err out */ -#if 1 - std::unique_ptr rewriter(Rewriter2::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getattr")); - - Box* val; - if (rewriter.get()) { - //rewriter->trap(); - GetattrRewriteArgs2 rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination(), false); - val = getattr_internal(obj, attr, 1, true, NULL, &rewrite_args); - - if (rewrite_args.out_success && val) { - rewriter->commitReturning(std::move(rewrite_args.out_rtn)); - } else { - rewrite_args.obj.setDoneUsing(); - } -#else - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, 1, "getattr")); - - Box* val; - if (rewriter.get()) { - //rewriter->trap(); - GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - val = getattr_internal(obj, attr, 1, true, &rewrite_args, NULL); - - if (rewrite_args.out_success && val) { - rewrite_args.out_rtn.move(-1); - rewriter->commit(); - } -#endif - } else { - val = getattr_internal(obj, attr, 1, true, NULL, NULL); - } - - if (val) { - return val; - } - } - - raiseAttributeError(obj, attr); -} - -extern "C" void setattr(Box *obj, const char* attr, Box* attr_val) { - assert(strcmp(attr, "__class__") != 0); - - static StatCounter slowpath_setattr("slowpath_setattr"); - slowpath_setattr.log(); - - if (!obj->cls->hasattrs) { - raiseAttributeError(obj, attr); - } - - if (obj->cls == type_cls) { - BoxedClass* cobj = static_cast(obj); - if (!isUserDefined(cobj)) { - fprintf(stderr, "TypeError: can't set attributes of built-in/extension type '%s'\n", getNameOfClass(cobj)->c_str()); - raiseExc(); - } - } - - HCBox* hobj = static_cast(obj); - -#if 0 - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "setattr")); - - if (rewriter.get()) { - //rewriter->trap(); - SetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2)); - hobj->setattr(attr, attr_val, &rewrite_args); - if (rewrite_args.out_success) { - rewriter->commit(); - } -#else - std::unique_ptr rewriter(Rewriter2::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "setattr")); - - if (rewriter.get()) { - //rewriter->trap(); - SetattrRewriteArgs2 rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2), false); - hobj->setattr(attr, attr_val, NULL, &rewrite_args); - if (rewrite_args.out_success) { - rewriter->commit(); - } else { - rewrite_args.obj.setDoneUsing(); - rewrite_args.attrval.setDoneUsing(); - } -#endif - } else { - hobj->setattr(attr, attr_val, NULL, NULL); - } -} - -bool isUserDefined(BoxedClass *cls) { - // TODO I don't think this is good enough? - return cls->hasattrs && (cls != function_cls && cls != type_cls) && !cls->is_constant; -} - -extern "C" bool nonzero(Box* obj) { - static StatCounter slowpath_nonzero("slowpath_nonzero"); - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 1, 0, "nonzero")); - - if (rewriter.get()) { - //rewriter->trap(); - rewriter->getArg(0).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)obj->cls); - } - - if (obj->cls == bool_cls) { - if (rewriter.get()) { - rewriter->getArg(0).getAttr(BOOL_B_OFFSET, -1); - rewriter->commit(); - } - - BoxedBool *bool_obj = static_cast(obj); - return bool_obj->b; - } else if (obj->cls == int_cls) { - if (rewriter.get()) { - // TODO should do: - // test %rsi, %rsi - // setne %al - RewriterVar n = rewriter->getArg(0).getAttr(INT_N_OFFSET, 1); - n.toBool(-1); - rewriter->commit(); - } - - BoxedInt *int_obj = static_cast(obj); - return int_obj->n != 0; - } else if (obj->cls == float_cls) { - return static_cast(obj)->d != 0; - } - - slowpath_nonzero.log(); - - //int id = Stats::getStatId("slowpath_nonzero_" + *getTypeName(obj)); - //Stats::log(id); - - Box* func = getclsattr_internal(obj, "__nonzero__", NULL, NULL); - if (func == NULL) { - RELEASE_ASSERT(isUserDefined(obj->cls), "%s.__nonzero__", getTypeName(obj)->c_str()); // TODO - return true; - } - - Box* r = runtimeCall0(func, 0); - if (r->cls == bool_cls) { - BoxedBool* b = static_cast(r); - bool rtn = b->b; - return rtn; - } else if (r->cls == int_cls) { - BoxedInt* b = static_cast(r); - bool rtn = b->n != 0; - return rtn; - } else { - fprintf(stderr, "TypeError: __nonzero__ should return bool or int, returned %s\n", getTypeName(r)->c_str()); - raiseExc(); - } -} - -extern "C" BoxedString* str(Box* obj) { - static StatCounter slowpath_str("slowpath_str"); - slowpath_str.log(); - - if (obj->cls != str_cls) { - Box *str = getclsattr_internal(obj, "__str__", NULL, NULL); - if (str == NULL) - str = getclsattr_internal(obj, "__repr__", NULL, NULL); - - if (str == NULL) { - ASSERT(isUserDefined(obj->cls), "%s.__str__", getTypeName(obj)->c_str()); - - char buf[80]; - snprintf(buf, 80, "<%s object at %p>", getTypeName(obj)->c_str(), obj); - return boxStrConstant(buf); - } else { - obj = runtimeCallInternal0(str, NULL, 0); - } - } - if (obj->cls != str_cls) { - fprintf(stderr, "__str__ did not return a string!\n"); - abort(); - } - return static_cast(obj); -} - -extern "C" BoxedString* repr(Box* obj) { - static StatCounter slowpath_repr("slowpath_repr"); - slowpath_repr.log(); - - Box *repr = getclsattr_internal(obj, "__repr__", NULL, NULL); - if (repr == NULL) { - ASSERT(isUserDefined(obj->cls), "%s", getTypeName(obj)->c_str()); - - char buf[80]; - if (obj->cls == type_cls) { - snprintf(buf, 80, "", getNameOfClass(static_cast(obj))->c_str()); - } else { - snprintf(buf, 80, "<%s object at %p>", getTypeName(obj)->c_str(), obj); - } - return boxStrConstant(buf); - } else { - obj = runtimeCall0(repr, 0); - } - - if (obj->cls != str_cls) { - fprintf(stderr, "__repr__ did not return a string!\n"); - raiseExc(); - } - return static_cast(obj); -} - -extern "C" BoxedInt* hash(Box* obj) { - static StatCounter slowpath_hash("slowpath_hash"); - slowpath_hash.log(); - - Box *hash = getclsattr_internal(obj, "__hash__", NULL, NULL); - if (hash == NULL) { - ASSERT(isUserDefined(obj->cls), "%s.__hash__", getTypeName(obj)->c_str()); - // TODO not the best way to handle this... - return static_cast(boxInt((i64)obj)); - } - - Box* rtn = runtimeCall0(hash, 0); - if (rtn->cls != int_cls) { - fprintf(stderr, "TypeError: an integer is required\n"); - raiseExc(); - } - return static_cast(rtn); -} - -extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs *rewrite_args) { - Box* rtn; - static std::string attr_str("__len__"); - if (rewrite_args) { - CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj); - crewrite_args.preferred_dest_reg = rewrite_args->preferred_dest_reg; - rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, &crewrite_args, 0); - if (!crewrite_args.out_success) - rewrite_args = NULL; - else if (rtn) - rewrite_args->out_rtn = crewrite_args.out_rtn; - } else { - rtn = callattrInternal0(obj, &attr_str, CLASS_ONLY, NULL, 0); - } - - if (rtn == NULL) { - fprintf(stderr, "TypeError: object of type '%s' has no len()\n", getTypeName(obj)->c_str()); - raiseExc(); - } - - if (rtn->cls != int_cls) { - fprintf(stderr, "TypeError: an integer is required\n"); - raiseExc(); - } - - if (rewrite_args) - rewrite_args->out_success = true; - return static_cast(rtn); -} - -extern "C" BoxedInt* len(Box* obj) { - static StatCounter slowpath_len("slowpath_len"); - slowpath_len.log(); - - return lenInternal(obj, NULL); -} - -extern "C" i64 unboxedLen(Box* obj) { - static StatCounter slowpath_unboxedlen("slowpath_unboxedlen"); - slowpath_unboxedlen.log(); - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 1, 1, "unboxedLen")); - - BoxedInt* lobj; - RewriterVar r_boxed; - if (rewriter.get()) { - //rewriter->trap(); - LenRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - rewrite_args.preferred_dest_reg = 0; - lobj = lenInternal(obj, &rewrite_args); - - if (!rewrite_args.out_success) - rewriter.reset(NULL); - else - r_boxed = rewrite_args.out_rtn; - } else { - lobj = lenInternal(obj, NULL); - } - - assert(lobj->cls == int_cls); - i64 rtn = lobj->n; - - if (rewriter.get()) { - RewriterVar rtn = r_boxed.getAttr(INT_N_OFFSET, -1); - rewriter->commit(); - } - return rtn; -} - -extern "C" void print(Box *obj) { - static StatCounter slowpath_print("slowpath_print"); - slowpath_print.log(); - - BoxedString *strd = str(obj); - printf("%s", strd->s.c_str()); -} - -extern "C" void dump(Box *obj) { - printf("dump: obj %p, cls %p\n", obj, obj->cls); -} - -// For rewriting purposes, this function assumes that nargs will be constant. -// That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand. -extern "C" Box* callattrInternal(Box* obj, const std::string *attr, LookupScope scope, CallRewriteArgs *rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box **args) { - if (rewrite_args) { - //if (VERBOSITY()) { - //printf("callattrInternal: %d", rewrite_args->obj.getArgnum()); - //if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum()); - //if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum()); - //if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum()); - //if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum()); - //printf("\n"); - //} - if (rewrite_args->obj.getArgnum() == -1) { - //rewrite_args->rewriter->trap(); - rewrite_args->obj = rewrite_args->obj.move(-3); - } - } - - if (rewrite_args && !rewrite_args->args_guarded) { - // TODO duplication with runtime_call - // TODO should know which args don't need to be guarded, ex if we're guaranteed that they - // already fit, either since the type inferencer could determine that, - // or because they only need to fit into an UNKNOWN slot. - - if (nargs >= 1) rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls); - if (nargs >= 2) rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls); - // Have to move(-1) since the arg is (probably/maybe) on the stack; - // TODO ideally would handle that case, but for now just do the move() which - // it knows how to handle - if (nargs >= 3) rewrite_args->arg3.move(-2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls); - - if (nargs > 3) { - RewriterVar r_args = rewrite_args->args.move(-3); - for (int i = 3; i < nargs; i++) { - // TODO if there are a lot of args (>16), might be better to increment a pointer - // rather index them directly? - r_args.getAttr((i - 3) * sizeof(Box*), -2).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i-3]->cls); - } - } - } - - - if (checkInst(scope)) { - Box* inst_attr; - RewriterVar r_instattr; - if (rewrite_args) { - GetattrRewriteArgs ga_rewrite_args(rewrite_args->rewriter, rewrite_args->obj); - - inst_attr = getattr_internal(obj, attr->c_str(), false, true, &ga_rewrite_args, NULL); - - if (!ga_rewrite_args.out_success) - rewrite_args = NULL; - else if (inst_attr) - r_instattr = ga_rewrite_args.out_rtn; - } else { - inst_attr = getattr_internal(obj, attr->c_str(), false, true, NULL, NULL); - } - - if (inst_attr) { - Box* rtn; - if (inst_attr->cls != function_cls) - rewrite_args = NULL; - - if (rewrite_args) { - r_instattr.push(); - - rewrite_args->args_guarded = true; - - r_instattr.addGuard((intptr_t)inst_attr); - rewrite_args->func_guarded = true; - - rtn = runtimeCallInternal(inst_attr, rewrite_args, nargs, arg1, arg2, arg3, args); - - if (rewrite_args->out_success) { - r_instattr = rewrite_args->rewriter->pop(0); - } - } else { - rtn = runtimeCallInternal(inst_attr, NULL, nargs, arg1, arg2, arg3, args); - } - - if (!rtn) { - fprintf(stderr, "TypeError: '%s' object is not callable\n", getTypeName(inst_attr)->c_str()); - raiseExc(); - } - - return rtn; - } - } - - Box* clsattr = NULL; - RewriterVar r_clsattr; - if (checkClass(scope)) { - if (rewrite_args) { - //rewrite_args->obj.push(); - RewriterVar r_cls = rewrite_args->obj.getAttr(BOX_CLS_OFFSET, -1); - GetattrRewriteArgs ga_rewrite_args(rewrite_args->rewriter, r_cls); - - r_cls.assertValid(); - clsattr = getattr_internal(obj->cls, attr->c_str(), false, false, &ga_rewrite_args, NULL); - - if (!ga_rewrite_args.out_success) - rewrite_args = NULL; - else if (clsattr) - r_clsattr = ga_rewrite_args.out_rtn.move(-1); - } else { - clsattr = getattr_internal(obj->cls, attr->c_str(), false, false, NULL, NULL); - } - } - - if (!clsattr) { - if (rewrite_args) rewrite_args->out_success = true; - return NULL; - } - - if (clsattr->cls == function_cls) { - if (rewrite_args) { - r_clsattr.addGuard((int64_t)clsattr); - } - - // TODO copy from runtimeCall - // TODO these two branches could probably be folded together (the first one is becoming - // a subset of the second) - if (nargs <= 2) { - Box* rtn; - if (rewrite_args) { - CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); - srewrite_args.arg1 = rewrite_args->obj; - - // should be no-ops: - if (nargs >= 1) srewrite_args.arg2 = rewrite_args->arg1; - if (nargs >= 2) srewrite_args.arg3 = rewrite_args->arg2; - - srewrite_args.func_guarded = true; - srewrite_args.args_guarded = true; - r_clsattr.push(); - - rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs+1, obj, arg1, arg2, NULL); - - if (!srewrite_args.out_success) { - rewrite_args = NULL; - } else { - r_clsattr = rewrite_args->rewriter->pop(0); - rewrite_args->out_rtn = srewrite_args.out_rtn; - } - } else { - rtn = runtimeCallInternal(clsattr, NULL, nargs+1, obj, arg1, arg2, NULL); - } - - if (rewrite_args) rewrite_args->out_success = true; - return rtn; - } else { - int alloca_size = sizeof(Box*) * (nargs + 1 - 3); - - Box **new_args = (Box**)alloca(alloca_size); - new_args[0] = arg3; - memcpy(new_args+1, args, (nargs - 3) * sizeof(Box*)); - - Box* rtn; - if (rewrite_args) { - const bool annotate = 0; - if (annotate) rewrite_args->rewriter->trap(); - //if (VERBOSITY()) printf("have to remunge: %d %d %d %d\n", rewrite_args->arg1.getArgnum(), rewrite_args->arg2.getArgnum(), rewrite_args->arg3.getArgnum(), rewrite_args->args.getArgnum()); - // The above line seems to print one of: - // 4 5 6 7 - // 2 3 4 5 - // Want to move them to - // 1 2 X X - - //if (nargs >= 1) rewrite_args->arg1 = rewrite_args->arg1.move(1); - //if (nargs >= 2) rewrite_args->arg2 = rewrite_args->arg2.move(2); - //if (nargs >= 3) rewrite_args->arg3 = rewrite_args->arg3.move(4); - //if (nargs >= 4) rewrite_args->args = rewrite_args->args.move(5); - - // There's nothing critical that these are in these registers, - // just that the register assignments for the rest of this - // section assume that this is true: - //assert(rewrite_args->obj.getArgnum() == 0); - assert(r_clsattr.getArgnum() == -1); - - int new_alloca_reg = -3; - RewriterVar r_new_args = rewrite_args->rewriter->alloca_(alloca_size, new_alloca_reg); - r_clsattr.push(); - - if (rewrite_args->arg3.isInReg()) - r_new_args.setAttr(0, rewrite_args->arg3, /* user_visible = */ false); - else { - r_new_args.setAttr(0, rewrite_args->arg3.move(-2), /* user_visible = */ false); - } - - //arg3 is now dead - for (int i = 0; i < nargs - 3; i++) { - RewriterVar arg; - if (rewrite_args->args.isInReg()) - arg = rewrite_args->args.getAttr(i * sizeof(Box*), -2); - else { - // TODO this is really bad: - arg = rewrite_args->args.move(-2).getAttr(i * sizeof(Box*), -2); - } - r_new_args.setAttr((i + 1) * sizeof(Box*), arg, /* user_visible = */ false); - } - //args is now dead - - CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); - srewrite_args.arg1 = rewrite_args->obj; - if (nargs >= 1) srewrite_args.arg2 = rewrite_args->arg1; - if (nargs >= 2) srewrite_args.arg3 = rewrite_args->arg2; - if (nargs >= 3) srewrite_args.args = r_new_args; - srewrite_args.args_guarded = true; - srewrite_args.func_guarded = true; - - if (annotate) rewrite_args->rewriter->annotate(0); - rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs + 1, obj, arg1, arg2, new_args); - if (annotate) rewrite_args->rewriter->annotate(1); - - if (!srewrite_args.out_success) - rewrite_args = NULL; - else { - r_clsattr = rewrite_args->rewriter->pop(0); - rewrite_args->out_rtn = srewrite_args.out_rtn; - - // TODO should be a dealloca or smth - rewrite_args->rewriter->alloca_(-alloca_size, 0); - rewrite_args->out_success = true; - } - if (annotate) rewrite_args->rewriter->annotate(2); - } else { - rtn = runtimeCallInternal(clsattr, NULL, nargs + 1, obj, arg1, arg2, new_args); - } - return rtn; - } - } else { - Box* rtn; - if (clsattr->cls != function_cls) - rewrite_args = NULL; - - if (rewrite_args) { - CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_clsattr); - if (nargs >= 1) srewrite_args.arg1 = rewrite_args->arg1; - if (nargs >= 2) srewrite_args.arg2 = rewrite_args->arg2; - if (nargs >= 3) srewrite_args.arg3 = rewrite_args->arg3; - if (nargs >= 4) srewrite_args.args = rewrite_args->args; - srewrite_args.args_guarded = true; - - rtn = runtimeCallInternal(clsattr, &srewrite_args, nargs, arg1, arg2, arg3, args); - - if (!srewrite_args.out_success) - rewrite_args = NULL; - else - rewrite_args->out_rtn = srewrite_args.out_rtn; - } else { - rtn = runtimeCallInternal(clsattr, NULL, nargs, arg1, arg2, arg3, args); - } - - if (!rtn) { - fprintf(stderr, "TypeError: '%s' object is not callable\n", getTypeName(clsattr)->c_str()); - raiseExc(); - } - - if (rewrite_args) rewrite_args->out_success = true; - return rtn; - } -} - -extern "C" Box* callattr(Box* obj, std::string *attr, bool clsonly, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box **args) { - static StatCounter slowpath_callattr("slowpath_callattr"); - slowpath_callattr.log(); - - assert(attr); - - int num_orig_args = 4 + std::min(4L, nargs); - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "callattr")); - Box* rtn; - - LookupScope scope = clsonly ? CLASS_ONLY : CLASS_OR_INST; - - if (rewriter.get()) { - //rewriter->trap(); - - // TODO feel weird about doing this; it either isn't necessary - // or this kind of thing is necessary in a lot more places - //rewriter->getArg(3).addGuard(nargs); - - CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - if (nargs >= 1) rewrite_args.arg1 = rewriter->getArg(4); - if (nargs >= 2) rewrite_args.arg2 = rewriter->getArg(5); - if (nargs >= 3) rewrite_args.arg3 = rewriter->getArg(6); - if (nargs >= 4) rewrite_args.args = rewriter->getArg(7); - rtn = callattrInternal(obj, attr, scope, &rewrite_args, nargs, arg1, arg2, arg3, args); - - if (!rewrite_args.out_success) { - rewriter.reset(NULL); - } else if (rtn) { - rewrite_args.out_rtn.move(-1); - } - } else { - rtn = callattrInternal(obj, attr, scope, NULL, nargs, arg1, arg2, arg3, args); - } - - if (rtn == NULL) { - raiseAttributeError(obj, attr->c_str()); - } - - if (rewriter.get()) rewriter->commit(); - return rtn; -} - -static const std::string _call_str("__call__"), _new_str("__new__"), _init_str("__init__"); -Box* runtimeCallInternal(Box* obj, CallRewriteArgs *rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box* *args) { - // the 10M upper bound isn't a hard max, just almost certainly a bug - // (also the alloca later will probably fail anyway) - ASSERT(nargs >= 0 && nargs < 10000000, "%ld", nargs); - - Box* orig_obj = obj; - - if (obj->cls != function_cls && obj->cls != instancemethod_cls) { - if (rewrite_args) { - // TODO is this ok? - //rewrite_args->rewriter->trap(); - return callattrInternal(obj, &_call_str, CLASS_ONLY, rewrite_args, nargs, arg1, arg2, arg3, args); - } else { - return callattrInternal(obj, &_call_str, CLASS_ONLY, NULL, nargs, arg1, arg2, arg3, args); - } - } - - if (rewrite_args) { - if (!rewrite_args->args_guarded) { - // TODO should know which args don't need to be guarded, ex if we're guaranteed that they - // already fit, either since the type inferencer could determine that, - // or because they only need to fit into an UNKNOWN slot. - - if (nargs >= 1) rewrite_args->arg1.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg1->cls); - if (nargs >= 2) rewrite_args->arg2.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg2->cls); - if (nargs >= 3) rewrite_args->arg3.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)arg3->cls); - for (int i = 3; i < nargs; i++) { - rewrite_args->args.getAttr((i - 3) * sizeof(Box*), -1).addAttrGuard(BOX_CLS_OFFSET, (intptr_t)args[i-3]->cls); - } - } - - rewrite_args->rewriter->addDecision(obj->cls == function_cls ? 1 : 0); - } - - if (obj->cls == function_cls) { - BoxedFunction *f = static_cast(obj); - - CompiledFunction *cf = resolveCLFunc(f->f, nargs, arg1, arg2, arg3, args); - - // typeCall (ie the base for constructors) is important enough that it knows - // how to do rewrites, so lets cut directly to the internal function rather - // than hitting its python bindings: - if (cf->code == typeCall) { - Box* rtn; - if (rewrite_args) { - CallRewriteArgs srewrite_args(rewrite_args->rewriter, RewriterVar()); - if (nargs >= 1) srewrite_args.arg1 = rewrite_args->arg1; - if (nargs >= 2) srewrite_args.arg2 = rewrite_args->arg2; - if (nargs >= 3) srewrite_args.arg3 = rewrite_args->arg3; - if (nargs >= 4) srewrite_args.args = rewrite_args->args; - rtn = typeCallInternal(&srewrite_args, nargs, arg1, arg2, arg3, args); - if (!srewrite_args.out_success) - rewrite_args = NULL; - else - rewrite_args->out_rtn = srewrite_args.out_rtn; - } else { - rtn = typeCallInternal(NULL, nargs, arg1, arg2, arg3, args); - } - - if (rewrite_args) rewrite_args->out_success = true; - return rtn; - } - - if (cf->sig->is_vararg) rewrite_args = NULL; - if (cf->is_interpreted) rewrite_args = NULL; - - if (rewrite_args) { - if (!rewrite_args->func_guarded) - rewrite_args->obj.addGuard((intptr_t)obj); - - rewrite_args->rewriter->addDependenceOn(cf->dependent_callsites); - - //if (VERBOSITY()) { - //printf("runtimeCallInternal: %d", rewrite_args->obj.getArgnum()); - //if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum()); - //if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum()); - //if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum()); - //if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum()); - //printf("\n"); - //} - - if (nargs >= 1) rewrite_args->arg1.move(0); - if (nargs >= 2) rewrite_args->arg2.move(1); - if (nargs >= 3) rewrite_args->arg3.move(2); - if (nargs >= 4) rewrite_args->args.move(3); - RewriterVar r_rtn = rewrite_args->rewriter->call(cf->code); - rewrite_args->out_rtn = r_rtn.move(-1); - } - Box* rtn = callCompiledFunc(cf, nargs, arg1, arg2, arg3, args); - - if (rewrite_args) rewrite_args->out_success = true; - return rtn; - } else if (obj->cls == instancemethod_cls) { - // TODO it's dumb but I should implement patchpoints here as well - // duplicated with callattr - BoxedInstanceMethod *im = static_cast(obj); - - if (rewrite_args && !rewrite_args->func_guarded) { - rewrite_args->obj.addAttrGuard(INSTANCEMETHOD_FUNC_OFFSET, (intptr_t)im->func); - } - - if (nargs <= 2) { - Box* rtn; - if (rewrite_args) { - // Kind of weird that we don't need to give this a valid RewriterVar, but it shouldn't need to access it - // (since we've already guarded on the function). - CallRewriteArgs srewrite_args(rewrite_args->rewriter, RewriterVar()); - - srewrite_args.arg1 = rewrite_args->obj.getAttr(INSTANCEMETHOD_OBJ_OFFSET, 0); - srewrite_args.func_guarded = true; - srewrite_args.args_guarded = true; - if (nargs >= 1) srewrite_args.arg2 = rewrite_args->arg1; - if (nargs >= 2) srewrite_args.arg3 = rewrite_args->arg2; - - rtn = runtimeCallInternal(im->func, &srewrite_args, nargs+1, im->obj, arg1, arg2, NULL); - - if (!srewrite_args.out_success) { - rewrite_args = NULL; - } else { - rewrite_args->out_rtn = srewrite_args.out_rtn.move(-1); - } - } else { - rtn = runtimeCallInternal(im->func, NULL, nargs+1, im->obj, arg1, arg2, NULL); - } - if (rewrite_args) rewrite_args->out_success = true; - return rtn; - } else { - Box **new_args = (Box**)alloca(sizeof(Box*) * (nargs + 1 - 3)); - new_args[0] = arg3; - memcpy(new_args+1, args, (nargs - 3) * sizeof(Box*)); - Box* rtn = runtimeCall(im->func, nargs + 1, im->obj, arg1, arg2, new_args); - return rtn; - } - } - assert(0); - abort(); -} - -extern "C" Box* runtimeCall(Box *obj, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box **args) { - static StatCounter slowpath_runtimecall("slowpath_runtimecall"); - slowpath_runtimecall.log(); - - int num_orig_args = 2 + std::min(4L, nargs); - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), num_orig_args, 2, "runtimeCall")); - Box* rtn; - - if (rewriter.get()) { - //rewriter->trap(); - - // TODO feel weird about doing this; it either isn't necessary - // or this kind of thing is necessary in a lot more places - //rewriter->getArg(1).addGuard(nargs); - - CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - if (nargs >= 1) rewrite_args.arg1 = rewriter->getArg(2); - if (nargs >= 2) rewrite_args.arg2 = rewriter->getArg(3); - if (nargs >= 3) rewrite_args.arg3 = rewriter->getArg(4); - if (nargs >= 4) rewrite_args.args = rewriter->getArg(5); - rtn = runtimeCallInternal(obj, &rewrite_args, nargs, arg1, arg2, arg3, args); - - if (!rewrite_args.out_success) { - rewriter.reset(NULL); - } else if (rtn) { - rewrite_args.out_rtn.move(-1); - } - } else { - rtn = runtimeCallInternal(obj, NULL, nargs, arg1, arg2, arg3, args); - } - - if (rewriter.get()) { - rewriter->commit(); - } - return rtn; -} - -extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) { - static StatCounter slowpath_binop("slowpath_binop"); - slowpath_binop.log(); - static StatCounter nopatch_binop("nopatch_binop"); - - std::string op_name = getOpName(op_type); - - //int id = Stats::getStatId("slowpath_binop_" + *getTypeName(lhs) + op_name + *getTypeName(rhs)); - //Stats::log(id); - - // TODO handle the case of the rhs being a subclass of the lhs - // this could get really annoying because you can dynamically make one type a subclass - // of the other! - - { // anonymous scope to make sure all variables get cleaned up before we error - - std::unique_ptr rewriter((Rewriter*)NULL); - bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls); - if (can_patchpoint) - rewriter.reset(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "binop")); - - if (rewriter.get()) { - //rewriter->trap(); - - RewriterVar r_lhs = rewriter->getArg(0); - RewriterVar r_rhs = rewriter->getArg(1); - // TODO probably don't need to guard on the lhs_cls since it - // will get checked no matter what, but the check that should be - // removed is probably the later one. - // ie we should have some way of specifying what we know about the values - // of objects and their attributes, and the attributes' attributes. - r_lhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)lhs->cls); - r_rhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls); - } - - Box* lrtn; - if (rewriter.get()) { - CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - rewrite_args.arg1 = rewriter->getArg(1); - lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &rewrite_args, 1, rhs); - - if (!rewrite_args.out_success) - rewriter.reset(NULL); - else if (lrtn) - rewrite_args.out_rtn.move(-1); - } else { - lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs); - } - - - if (lrtn) { - if (lrtn != NotImplemented) { - if (rewriter.get() && can_patchpoint) { - rewriter->commit(); - } - // - //printf("lfunc returned NotImplemented\n"); - return lrtn; - } - } else { - //printf("lfunc doesnt exist\n"); - } - - // TODO patch these cases - - std::string rop_name = getReverseOpName(op_type); - Box* rattr_func = getattr_internal(rhs->cls, rop_name.c_str(), false, false, NULL, NULL); - if (rattr_func) { - Box* rtn = runtimeCall2(rattr_func, 2, rhs, lhs); - if (rtn != NotImplemented) { - return rtn; - } - } else { - //printf("rfunc doesn't exist\n"); - } - - fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n", getOpSymbol(op_type).c_str(), getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str()); - if (VERBOSITY()) { - if (lrtn) - fprintf(stderr, "%s has %s, but returned NotImplemented\n", getTypeName(lhs)->c_str(), op_name.c_str()); - else - fprintf(stderr, "%s does not have %s\n", getTypeName(lhs)->c_str(), op_name.c_str()); - if (rattr_func) - fprintf(stderr, "%s has %s, but returned NotImplemented\n", getTypeName(rhs)->c_str(), rop_name.c_str()); - else - fprintf(stderr, "%s does not have %s\n", getTypeName(rhs)->c_str(), rop_name.c_str()); - } - } - raiseExc(); -} - -Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs *rewrite_args) { - if (op_type == AST_TYPE::Is || op_type == AST_TYPE::IsNot) { - bool neg = (op_type == AST_TYPE::IsNot); - - if (rewrite_args) { - if (neg) - rewrite_args->lhs.cmp(AST_TYPE::NotEq, rewrite_args->rhs, 0); - else - rewrite_args->lhs.cmp(AST_TYPE::Eq, rewrite_args->rhs, 0); - rewrite_args->out_rtn = rewrite_args->rewriter->call((void*)boxBool); - rewrite_args->out_success = true; - } - - return boxBool((lhs == rhs) ^ neg); - } - - // Can do the guard checks after the Is/IsNot handling, since that is - // irrespective of the object classes - if (rewrite_args) { - // TODO probably don't need to guard on the lhs_cls since it - // will get checked no matter what, but the check that should be - // removed is probably the later one. - // ie we should have some way of specifying what we know about the values - // of objects and their attributes, and the attributes' attributes. - rewrite_args->lhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)lhs->cls); - rewrite_args->rhs.addAttrGuard(BOX_CLS_OFFSET, (intptr_t)rhs->cls); - } - - std::string op_name = getOpName(op_type); - - Box* lrtn; - if (rewrite_args) { - CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->lhs); - crewrite_args.arg1 = rewrite_args->rhs; - lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, &crewrite_args, 1, rhs); - - if (!crewrite_args.out_success) - rewrite_args = NULL; - else if (lrtn) - rewrite_args->out_rtn = crewrite_args.out_rtn; - } else { - lrtn = callattrInternal1(lhs, &op_name, CLASS_ONLY, NULL, 1, rhs); - } - - if (lrtn) { - if (lrtn != NotImplemented) { - bool can_patchpoint = !isUserDefined(lhs->cls) && !isUserDefined(rhs->cls); - if (rewrite_args && can_patchpoint) { - rewrite_args->out_success = true; - } - return lrtn; - } - } else { - } - - std::string rop_name = getReverseOpName(op_type); - Box* rattr_func = getattr_internal(rhs->cls, rop_name.c_str(), false, false, NULL, NULL); - if (rattr_func) { - Box* rtn = runtimeCall2(rattr_func, 2, rhs, lhs); - if (rtn != NotImplemented) { - ////printf("rfunc returned NotImplemented\n"); - ////bool can_patchpoint = lhs->cls->is_constant && (lattr_func == NULL || (lattr; - //bool can_patchpoint = !isUserDefined(lhs->cls) && lhs->cls->is_constant; - //if (can_patchpoint && rhs->cls->is_constant && rattr_func->cls == function_cls) { - //void* rtn_addr = __builtin_extract_return_addr(__builtin_return_address(0)); - //_repatchBinExp(rtn_addr, true, lhs, rhs, rattr_func); - //} - return rtn; - } - } else { - //printf("rfunc doesn't exist\n"); - } - - - if (op_type == AST_TYPE::Eq) - return boxBool(lhs == rhs); - if (op_type == AST_TYPE::NotEq) - return boxBool(lhs != rhs); - - // TODO - // According to http://docs.python.org/2/library/stdtypes.html#comparisons - // CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address. - - if (op_type == AST_TYPE::Gt || op_type == AST_TYPE::GtE || op_type == AST_TYPE::Lt || op_type == AST_TYPE::LtE) { - intptr_t cmp1, cmp2; - if (lhs->cls == rhs->cls) { - cmp1 = (intptr_t)lhs; - cmp2 = (intptr_t)rhs; - } else { - // This isn't really necessary, but try to make sure that numbers get sorted first - if (lhs->cls == int_cls || lhs->cls == float_cls) - cmp1 = 0; - else - cmp1 = (intptr_t)lhs->cls; - if (rhs->cls == int_cls || rhs->cls == float_cls) - cmp2 = 0; - else - cmp2 = (intptr_t)rhs->cls; - } - - if (op_type == AST_TYPE::Gt) - return boxBool(cmp1 > cmp2); - if (op_type == AST_TYPE::GtE) - return boxBool(cmp1 >= cmp2); - if (op_type == AST_TYPE::Lt) - return boxBool(cmp1 < cmp2); - if (op_type == AST_TYPE::LtE) - return boxBool(cmp1 <= cmp2); - } - RELEASE_ASSERT(0, ""); -} - -extern "C" Box* compare(Box* lhs, Box* rhs, int op_type) { - static StatCounter slowpath_compare("slowpath_compare"); - slowpath_compare.log(); - static StatCounter nopatch_compare("nopatch_compare"); - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "compare")); - - Box* rtn; - if (rewriter.get()) { - //rewriter->trap(); - CompareRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1)); - rtn = compareInternal(lhs, rhs, op_type, &rewrite_args); - if (!rewrite_args.out_success) - rewriter.reset(NULL); - else - rewrite_args.out_rtn.move(-1); - } else { - rtn = compareInternal(lhs, rhs, op_type, NULL); - } - - if (rewriter.get()) { - rewriter->commit(); - } - - return rtn; -} - -extern "C" Box* unaryop(Box* operand, int op_type) { - static StatCounter slowpath_unaryop("slowpath_unaryop"); - slowpath_unaryop.log(); - - std::string op_name = getOpName(op_type); - - Box* attr_func = getclsattr_internal(operand, op_name.c_str(), NULL, NULL); - - ASSERT(attr_func, "%s.%s", getTypeName(operand)->c_str(), op_name.c_str()); - - Box* rtn = runtimeCall0(attr_func, 0); - return rtn; -} - -extern "C" Box* getitem(Box* value, Box* slice) { - static StatCounter slowpath_getitem("slowpath_getitem"); - slowpath_getitem.log(); - static std::string str_getitem("__getitem__"); - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, 1, "getitem")); - - Box* rtn; - if (rewriter.get()) { - CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - rewrite_args.arg1 = rewriter->getArg(1); - - rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, &rewrite_args, 1, slice); - - if (!rewrite_args.out_success) - rewriter.reset(NULL); - else if (rtn) - rewrite_args.out_rtn.move(-1); - } else { - rtn = callattrInternal1(value, &str_getitem, CLASS_ONLY, NULL, 1, slice); - } - - if (rtn == NULL) { - // different versions of python give different error messages for this: - if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR < 7) { - fprintf(stderr, "TypeError: '%s' object is unsubscriptable\n", getTypeName(value)->c_str()); // 2.6.6 - } else if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR == 7 && PYTHON_VERSION_MICRO < 3) { - fprintf(stderr, "TypeError: '%s' object is not subscriptable\n", getTypeName(value)->c_str()); // 2.7.1 - } else { - fprintf(stderr, "TypeError: '%s' object has no attribute '__getitem__'\n", getTypeName(value)->c_str()); // 2.7.3 - } - raiseExc(); - } - - if (rewriter.get()) rewriter->commit(); - return rtn; -} - -// target[slice] = value -extern "C" void setitem(Box* target, Box* slice, Box* value) { - static StatCounter slowpath_setitem("slowpath_setitem"); - slowpath_setitem.log(); - static std::string str_setitem("__setitem__"); - - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "setitem")); - - Box* rtn; - RewriterVar r_rtn; - if (rewriter.get()) { - CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - rewrite_args.arg1 = rewriter->getArg(1); - rewrite_args.arg2 = rewriter->getArg(2); - - rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, &rewrite_args, 2, slice, value); - - if (!rewrite_args.out_success) - rewriter.reset(NULL); - else if (rtn) - r_rtn = rewrite_args.out_rtn; - } else { - rtn = callattrInternal2(target, &str_setitem, CLASS_ONLY, NULL, 2, slice, value); - } - - if (rtn == NULL) { - fprintf(stderr, "TypeError: '%s' object does not support item assignment\n", getTypeName(target)->c_str()); - raiseExc(); - } - - if (rewriter.get()) { - rewriter->commit(); - } -} - -// A wrapper around the HCBox constructor -// TODO is there a way to avoid the indirection? -static Box* makeHCBox(ObjectFlavor *flavor, BoxedClass *cls) { - return new HCBox(flavor, cls); -} - -// For use on __init__ return values -static void assertInitNone(Box *obj) { - if (obj != None) { - fprintf(stderr, "TypeError: __init__() should return None, not '%s'\n", getTypeName(obj)->c_str()); - raiseExc(); - } -} - -Box* typeCallInternal(CallRewriteArgs *rewrite_args, int64_t nargs, Box* arg1, Box* arg2, Box* arg3, Box** args) { - static StatCounter slowpath_typecall("slowpath_typecall"); - slowpath_typecall.log(); - - //if (rewrite_args && VERBOSITY()) { - //printf("typeCallInternal: %d", rewrite_args->obj.getArgnum()); - //if (nargs >= 1) printf(" %d", rewrite_args->arg1.getArgnum()); - //if (nargs >= 2) printf(" %d", rewrite_args->arg2.getArgnum()); - //if (nargs >= 3) printf(" %d", rewrite_args->arg3.getArgnum()); - //if (nargs >= 4) printf(" %d", rewrite_args->args.getArgnum()); - //printf("\n"); - //} - - - RewriterVar r_ccls, r_new, r_init; - Box *new_attr, *init_attr; - if (rewrite_args) { - //rewrite_args->rewriter->annotate(0); - //rewrite_args->rewriter->trap(); - r_ccls = rewrite_args->arg1; - // This is probably a duplicate, but it's hard to really convince myself of that. - // Need to create a clear contract of who guards on what - r_ccls.addGuard((intptr_t)arg1); - } - - Box* cls = arg1; - if (cls->cls != type_cls) { - fprintf(stderr, "TypeError: descriptor '__call__' requires a 'type' object but received an '%s'\n", getTypeName(cls)->c_str()); - raiseExc(); - } - - BoxedClass* ccls = static_cast(cls); - - if (rewrite_args) { - GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls); - grewrite_args.preferred_dest_reg = -2; - new_attr = getattr_internal(ccls, "__new__", false, false, &grewrite_args, NULL); - - if (!grewrite_args.out_success) - rewrite_args = NULL; - else { - if (new_attr) { - r_new = grewrite_args.out_rtn.move(-2); - r_new.addGuard((intptr_t)new_attr); - } - } - } else { - new_attr = getattr_internal(ccls, "__new__", false, false, NULL, NULL); - } - - if (rewrite_args) { - GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls); - init_attr = getattr_internal(ccls, "__init__", false, false, &grewrite_args, NULL); - - if (!grewrite_args.out_success) - rewrite_args = NULL; - else { - if (init_attr) { - r_init = grewrite_args.out_rtn; - r_init.addGuard((intptr_t)init_attr); - } - } - } else { - init_attr = getattr_internal(ccls, "__init__", false, false, NULL, NULL); - } - - //Box* made = callattrInternal(ccls, &_new_str, INST_ONLY, NULL, nargs, cls, arg2, arg3, args); - Box* made; - RewriterVar r_made; - if (new_attr) { - if (rewrite_args) { - if (init_attr) r_init.push(); - if (nargs >= 1) r_ccls.push(); - if (nargs >= 2) rewrite_args->arg2.push(); - if (nargs >= 3) rewrite_args->arg3.push(); - if (nargs >= 4) rewrite_args->args.push(); - - CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_new); - if (nargs >= 1) srewrite_args.arg1 = r_ccls; - if (nargs >= 2) srewrite_args.arg2 = rewrite_args->arg2; - if (nargs >= 3) srewrite_args.arg3 = rewrite_args->arg3; - if (nargs >= 4) srewrite_args.args = rewrite_args->args; - srewrite_args.args_guarded = true; - srewrite_args.func_guarded = true; - - r_new.push(); - - made = runtimeCallInternal(new_attr, &srewrite_args, nargs, cls, arg2, arg3, args); - - if (!srewrite_args.out_success) - rewrite_args = NULL; - else { - r_made = srewrite_args.out_rtn; - - r_new = rewrite_args->rewriter->pop(0); - r_made = r_made.move(-1); - - if (nargs >= 4) rewrite_args->args = rewrite_args->rewriter->pop(3); - if (nargs >= 3) rewrite_args->arg3 = rewrite_args->rewriter->pop(2); - if (nargs >= 2) rewrite_args->arg2 = rewrite_args->rewriter->pop(1); - if (nargs >= 1) r_ccls = rewrite_args->arg1 = rewrite_args->rewriter->pop(0); - if (init_attr) r_init = rewrite_args->rewriter->pop(-2); - } - } else { - made = runtimeCallInternal(new_attr, NULL, nargs, cls, arg2, arg3, args); - } - } else { - if (isUserDefined(ccls)) { - made = new HCBox(&user_flavor, ccls); - - if (rewrite_args) { - if (init_attr) r_init.push(); - if (nargs >= 1) r_ccls.push(); - if (nargs >= 2) rewrite_args->arg2.push(); - if (nargs >= 3) rewrite_args->arg3.push(); - if (nargs >= 4) rewrite_args->args.push(); - - r_ccls.move(1); - rewrite_args->rewriter->loadConst(0, (intptr_t)&user_flavor); - r_made = rewrite_args->rewriter->call((void*)&makeHCBox); - - if (nargs >= 4) rewrite_args->args = rewrite_args->rewriter->pop(3); - if (nargs >= 3) rewrite_args->arg3 = rewrite_args->rewriter->pop(2); - if (nargs >= 2) rewrite_args->arg2 = rewrite_args->rewriter->pop(1); - if (nargs >= 1) r_ccls = rewrite_args->arg1 = rewrite_args->rewriter->pop(0); - if (init_attr) r_init = rewrite_args->rewriter->pop(-2); - } - } else { - // Not sure what type of object to make here; maybe an HCBox? would be disastrous if it ever - // made the wrong one though, so just err for now: - fprintf(stderr, "no __new__ defined for %s!\n", getNameOfClass(ccls)->c_str()); - raiseExc(); - } - } - - assert(made); - // If this is true, not supposed to call __init__: - assert(made->cls == ccls && "allowed but unsupported"); - - if (init_attr) { - Box* initrtn; - if (rewrite_args) { - CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_init); - if (nargs >= 1) srewrite_args.arg1 = r_made; - if (nargs >= 2) srewrite_args.arg2 = rewrite_args->arg2; - if (nargs >= 3) srewrite_args.arg3 = rewrite_args->arg3; - if (nargs >= 4) srewrite_args.args = rewrite_args->args; - srewrite_args.args_guarded = true; - srewrite_args.func_guarded = true; - - r_made.push(); - r_init.push(); - //initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, &srewrite_args, nargs, made, arg2, arg3, args); - initrtn = runtimeCallInternal(init_attr, &srewrite_args, nargs, made, arg2, arg3, args); - - if (!srewrite_args.out_success) - rewrite_args = NULL; - else { - srewrite_args.out_rtn.move(0); - rewrite_args->rewriter->call((void*)assertInitNone); - - r_init = rewrite_args->rewriter->pop(0); - r_made = rewrite_args->rewriter->pop(-1); - } - } else { - //initrtn = callattrInternal(ccls, &_init_str, INST_ONLY, NULL, nargs, made, arg2, arg3, args); - initrtn = runtimeCallInternal(init_attr, NULL, nargs, made, arg2, arg3, args); - } - assertInitNone(initrtn); - } else { - if (new_attr == NULL && nargs != 1) { - fprintf(stderr, "TypeError: object.__new__() takes no parameters\n"); - raiseExc(); - } - } - - if (rewrite_args) { - rewrite_args->out_rtn = r_made; - rewrite_args->out_success = true; - } - return made; -} - -Box* typeCall(Box* obj, BoxedList* vararg) { - assert(vararg->cls == list_cls); - if (vararg->size == 0) - return typeCallInternal1(NULL, 1, obj); - else if (vararg->size == 1) - return typeCallInternal2(NULL, 2, obj, vararg->elts->elts[0]); - else if (vararg->size == 2) - return typeCallInternal3(NULL, 3, obj, vararg->elts->elts[0], vararg->elts->elts[1]); - else - return typeCallInternal(NULL, 1 + vararg->size, obj, vararg->elts->elts[0], vararg->elts->elts[1], &vararg->elts->elts[2]); -} - -Box* typeNew(Box* cls, Box* obj) { - assert(cls == type_cls); - - BoxedClass *rtn = obj->cls; - return rtn; -} - -extern "C" Box* getGlobal(BoxedModule* m, std::string *name, bool from_global) { - static StatCounter slowpath_getglobal("slowpath_getglobal"); - slowpath_getglobal.log(); - static StatCounter nopatch_getglobal("nopatch_getglobal"); - - if (VERBOSITY() >= 2) { - std::string per_name_stat_name = "getglobal__" + *name; - int id = Stats::getStatId(per_name_stat_name); - Stats::log(id); - } - - { /* anonymous scope to make sure destructors get run before we err out */ - std::unique_ptr rewriter(Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, 1, "getGlobal")); - - Box *r; - if (rewriter.get()) { - //rewriter->trap(); - - GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); - r = m->getattr(*name, &rewrite_args, NULL); - if (!rewrite_args.out_success) - rewriter.reset(NULL); - } else { - r = m->getattr(*name, NULL, NULL); - nopatch_getglobal.log(); - } - - if (r) { - if (rewriter.get()) { - rewriter->commit(); - } - return r; - } - - - static StatCounter stat_builtins("getglobal_builtins"); - stat_builtins.log(); - - if ((*name) == "__builtins__") { - if (rewriter.get()) { - RewriterVar r_rtn = rewriter->loadConst(-1, (intptr_t)builtins_module); - rewriter->commit(); - } - return builtins_module; - } - - Box* rtn; - if (rewriter.get()) { - RewriterVar builtins = rewriter->loadConst(3, (intptr_t)builtins_module); - GetattrRewriteArgs rewrite_args(rewriter.get(), builtins); - rtn = builtins_module->getattr(*name, &rewrite_args, NULL); - - if (!rewrite_args.out_success) - rewriter.reset(NULL); - } else { - rtn = builtins_module->getattr(*name, NULL, NULL); - } - - if (rewriter.get()) { - rewriter->commit(); - } - - if (rtn) - return rtn; - } - - if (from_global) - fprintf(stderr, "NameError: name '%s' is not defined\n", name->c_str()); - else - fprintf(stderr, "NameError: global name '%s' is not defined\n", name->c_str()); - raiseExc(); -} - -extern "C" Box* import(const std::string *name) { - static StatCounter slowpath_import("slowpath_import"); - slowpath_import.log(); - - assert(name); - - if ((*name) == "math") { - return math_module; - } - - if ((*name) == "time") { - return time_module; - } - - if ((*name) == "test") { - return getTestModule(); - } - - fprintf(stderr, "ImportError: No module named %s\n", name->c_str()); - raiseExc(); -} - - -} diff --git a/src/runtime/objmodel.h b/src/runtime/objmodel.h deleted file mode 100644 index 6ffc443f7..000000000 --- a/src/runtime/objmodel.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_OBJMODEL_H -#define PYSTON_RUNTIME_OBJMODEL_H - -#include -#include - -#include "core/types.h" - -namespace pyston { - -class Box; -class BoxedClass; -class BoxedInt; -class BoxedList; -class BoxedString; - -extern "C" const std::string* getTypeName(Box* o); -extern "C" const std::string* getNameOfClass(BoxedClass* cls); - -// TODO sort this -extern "C" void my_assert(bool b); -extern "C" Box* getattr(Box* obj, const char* attr); -extern "C" void setattr(Box* obj, const char* attr, Box* attr_val); -extern "C" bool nonzero(Box* obj); -extern "C" Box* runtimeCall(Box*, int64_t, Box*, Box*, Box*, Box**); -extern "C" Box* callattr(Box*, std::string*, bool, int64_t, Box*, Box*, Box*, Box**); -extern "C" BoxedString* str(Box* obj); -extern "C" BoxedString* repr(Box* obj); -extern "C" BoxedInt* hash(Box* obj); -//extern "C" Box* abs_(Box* obj); -//extern "C" Box* min_(Box* o0, Box* o1); -//extern "C" Box* max_(Box* o0, Box* o1); -extern "C" Box* open1(Box* arg); -extern "C" Box* open2(Box* arg1, Box* arg2); -//extern "C" Box* chr(Box* arg); -extern "C" Box* compare(Box*, Box*, int); -extern "C" BoxedInt* len(Box* obj); -extern "C" void print(Box* obj); -extern "C" void dump(Box* obj); -//extern "C" Box* trap(); -extern "C" i64 unboxedLen(Box* obj); -extern "C" Box* binop(Box* lhs, Box* rhs, int op_type); -extern "C" Box* getGlobal(BoxedModule* m, std::string *name, bool from_global); -extern "C" Box* getitem(Box* value, Box* slice); -extern "C" void setitem(Box* target, Box* slice, Box* value); -extern "C" Box* getclsattr(Box* obj, const char* attr); -extern "C" Box* unaryop(Box* operand, int op_type); -extern "C" Box* import(const std::string *name); -extern "C" void checkUnpackingLength(i64 expected, i64 given); -extern "C" void assertNameDefined(bool b, const char* name); - -struct CompareRewriteArgs; -Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs *rewrite_args); -Box* getattr_internal(Box *obj, const char* attr, bool check_cls, bool allow_custom, GetattrRewriteArgs* rewrite_args, GetattrRewriteArgs2* rewrite_args2); - -extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) __attribute__((__noreturn__)); -extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((__noreturn__)); -extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__noreturn__)); - -Box* typeCall(Box*, BoxedList*); -Box* typeNew(Box*, Box*); -bool isUserDefined(BoxedClass *cls); - -} -#endif diff --git a/src/runtime/stacktrace.cpp b/src/runtime/stacktrace.cpp deleted file mode 100644 index 7fbcb37bb..000000000 --- a/src/runtime/stacktrace.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define UNW_LOCAL_ONLY -#include - - -#include "core/options.h" - -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -// from http://www.nongnu.org/libunwind/man/libunwind(3).html -void showBacktrace() { - unw_cursor_t cursor; - unw_context_t uc; - unw_word_t ip, sp; - - unw_getcontext(&uc); - unw_init_local(&cursor, &uc); - - while (unw_step(&cursor) > 0) { - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - printf ("ip = %lx, sp = %lx\n", (long) ip, (long) sp); - - std::string py_info = getPythonFuncAt((void*)ip, (void*)sp); - if (py_info.size()) { - printf("Which is: %s\n", py_info.c_str()); - } - } -} - -void raiseExc() { - if (VERBOSITY()) showBacktrace(); - //if (VERBOSITY()) raise(SIGTRAP); - if (VERBOSITY()) abort(); - exit(1); -} - -} diff --git a/src/runtime/str.cpp b/src/runtime/str.cpp deleted file mode 100644 index 992630d6b..000000000 --- a/src/runtime/str.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "core/common.h" -#include "core/types.h" - -// For STR -#include "codegen/compvars.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -extern "C" BoxedString* strAdd(BoxedString* lhs, BoxedString* rhs) { - assert(lhs->cls == str_cls); - assert(rhs->cls == str_cls); - return new BoxedString(lhs->s + rhs->s); -} - -extern "C" Box* strMod(BoxedString* lhs, Box* rhs) { - const std::vector *elts; - std::vector _elts; - if (rhs->cls == tuple_cls) { - elts = &static_cast(rhs)->elts; - } else { - elts = &_elts; - _elts.push_back(rhs); - } - - const char* fmt = lhs->s.c_str(); - const char* fmt_end = fmt + lhs->s.size(); - - int elt_num = 0; - int num_elts = elts->size(); - - std::ostringstream os(""); - while (fmt < fmt_end) { - if (*fmt != '%') { - os << (*fmt); - fmt++; - } else { - fmt++; - - int nspace = 0; - int ndot = 0; - int nzero = 0; - int mode = 0; - while (true) { - RELEASE_ASSERT(fmt < fmt_end, ""); - char c = *fmt; - fmt++; - - if (c == ' ') { - assert(mode == 0); - mode = 1; - } else if (c == '.') { - assert(mode == 0); - mode = 2; - } else if (mode == 0 && c == '0') { - mode = 3; - } else if ('0' <= c && c <= '9') { - assert(mode == 1 || mode == 2 || mode == 3); - if (mode == 1) { - nspace = nspace * 10 + c - '0'; - } else if (mode == 2) { - ndot = ndot * 10 + c - '0'; - } else if (mode == 3) { - nzero = nzero * 10 + c - '0'; - } else { - assert(0); - } - } else if (c == '%') { - for (int i = 1; i < nspace; i++) { - os << ' '; - } - os << '%'; - break; - } else if (c == 's') { - RELEASE_ASSERT(ndot == 0, ""); - RELEASE_ASSERT(nzero == 0, ""); - RELEASE_ASSERT(nspace == 0, ""); - - RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); - Box* b = (*elts)[elt_num]; - elt_num++; - - BoxedString *s = str(b); - os << s->s; - break; - } else if (c == 'd') { - RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); - Box* b = (*elts)[elt_num]; - elt_num++; - - RELEASE_ASSERT(b->cls == int_cls, "unsupported"); - - std::ostringstream fmt(""); - fmt << '%'; - if (nspace) - fmt << ' ' << nspace; - else if (ndot) - fmt << '.' << ndot; - else if (nzero) - fmt << '0' << nzero; - fmt << "ld"; - - char buf[20]; - snprintf(buf, 20, fmt.str().c_str(), static_cast(b)->n); - os << std::string(buf); - break; - } else if (c == 'f') { - RELEASE_ASSERT(elt_num < num_elts, "insufficient number of arguments for format string"); - Box* b = (*elts)[elt_num]; - elt_num++; - - double d; - if (b->cls == float_cls) { - d = static_cast(b)->d; - } else if (b->cls == int_cls) { - d = static_cast(b)->n; - } else { - RELEASE_ASSERT(0, "unsupported"); - } - - std::ostringstream fmt(""); - fmt << '%'; - if (nspace) - fmt << ' ' << nspace; - else if (ndot) - fmt << '.' << ndot; - else if (nzero) - fmt << '0' << nzero; - fmt << "f"; - - char buf[20]; - snprintf(buf, 20, fmt.str().c_str(), d); - os << std::string(buf); - break; - } else { - RELEASE_ASSERT(0, "unsupported format character '%c'", c); - } - } - } - } - assert(fmt == fmt_end && "incomplete format"); - - return boxString(os.str()); -} - -extern "C" BoxedString* strMul(BoxedString* lhs, BoxedInt* rhs) { - assert(lhs->cls == str_cls); - assert(rhs->cls == int_cls); - - RELEASE_ASSERT(rhs->n >= 0, ""); - - int sz = lhs->s.size(); - int n = rhs->n; - char* buf = new char[sz * n + 1]; - for (int i = 0; i < n; i++) { - memcpy(buf + (sz * i), lhs->s.c_str(), sz); - } - buf[sz * n] = '\0'; - - return new BoxedString(buf); -} - -extern "C" Box* strEq(BoxedString* lhs, Box* rhs) { - if (rhs->cls != str_cls) - return boxBool(false); - - BoxedString* srhs = static_cast(rhs); - return boxBool(lhs->s == srhs->s); -} - -extern "C" Box* strLen(BoxedString* self) { - return boxInt(self->s.size()); -} - -extern "C" Box* strStr(BoxedString* self) { - return self; -} - -static bool _needs_escaping[256] = { - true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true -}; -static char _hex[17] = "0123456789abcdef"; // really only needs to be 16 but clang will complain -extern "C" Box* strRepr(BoxedString* self) { - std::ostringstream os(""); - - const std::string &s = self->s; - os << '\''; - for (int i = 0; i < s.size(); i++) { - char c = s[i]; - if (!_needs_escaping[c & 0xff]) { - os << c; - } else { - char special = 0; - switch (c) { - case '\t': - special = 't'; - break; - case '\n': - special = 'n'; - break; - case '\r': - special = 'r'; - break; - case '\'': - special = '\''; - break; - case '\"': - special = '\"'; - break; - case '\\': - special = '\\'; - break; - } - if (special) { - os << '\\'; - os << special; - } else { - os << '\\'; - os << 'x'; - os << _hex[(c & 0xff) / 16]; - os << _hex[(c & 0xff) % 16]; - } - } - } - os << '\''; - - return boxString(os.str()); -} - -extern "C" Box* strHash(BoxedString* self) { - std::hash H; - return boxInt(H(self->s)); -} - -extern "C" Box* strNonzero(BoxedString* self) { - return boxBool(self->s.size() != 0); -} - -extern "C" Box* strNew1(BoxedClass* cls) { - assert(cls == str_cls); - return boxStrConstant(""); -} - -extern "C" Box* strNew2(BoxedClass* cls, Box* obj) { - assert(cls == str_cls); - - return str(obj); -} - -Box* _strSlice(BoxedString *self, i64 start, i64 stop, i64 step) { - const std::string &s = self->s; - - assert(step != 0); - if (step > 0) { - assert(0 <= start); - assert(stop <= s.size()); - } else { - assert(start < s.size()); - assert(-1 <= stop); - } - - std::vector chars; - int cur = start; - while ((step > 0 && cur < stop) || (step < 0 && cur > stop)) { - chars.push_back(s[cur]); - cur += step; - } - // TODO too much copying - return boxString(std::string(chars.begin(), chars.end())); -} - -Box* strLower(BoxedString* self) { - assert(self->cls == str_cls); - std::string lowered(self->s); - std::transform(lowered.begin(), lowered.end(), lowered.begin(), tolower); - return boxString(std::move(lowered)); -} - -Box* strJoin(BoxedString* self, Box* rhs) { - assert(self->cls == str_cls); - - if (rhs->cls == list_cls) { - BoxedList *list = static_cast(rhs); - std::ostringstream os; - for (int i = 0; i < list->size; i++) { - if (i > 0) os << self->s; - BoxedString *elt_str = str(list->elts->elts[i]); - os << elt_str->s; - } - return boxString(os.str()); - } else { - fprintf(stderr, "TypeError\n"); - raiseExc(); - } -} - -extern "C" Box* strGetitem(BoxedString* self, Box* slice) { - if (slice->cls == int_cls) { - BoxedInt* islice = static_cast(slice); - int64_t n = islice->n; - int size = self->s.size(); - if (n < 0) - n = size + n; - - if (n < 0 || n >= size) { - fprintf(stderr, "IndexError: string index out of range\n"); - raiseExc(); - } - - char c = self->s[n]; - return new BoxedString(std::string(1, c)); - } else if (slice->cls == slice_cls) { - BoxedSlice *sslice = static_cast(slice); - - i64 start, stop, step; - parseSlice(sslice, self->s.size(), &start, &stop, &step); - return _strSlice(self, start, stop, step); - } else { - fprintf(stderr, "TypeError: string indices must be integers, not %s\n", getTypeName(slice)->c_str()); - raiseExc(); - } -} - -void setupStr() { - str_cls->giveAttr("__name__", boxStrConstant("str")); - - str_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)strLen, NULL, 1, false))); - str_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)strStr, NULL, 1, false))); - str_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)strRepr, NULL, 1, false))); - str_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)strHash, NULL, 1, false))); - str_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)strNonzero, NULL, 1, false))); - - str_cls->giveAttr("lower", new BoxedFunction(boxRTFunction((void*)strLower, STR, 1, false))); - - str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, NULL, 2, false))); - str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, NULL, 2, false))); - str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, NULL, 2, false))); - str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, NULL, 2, false))); - str_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)strGetitem, NULL, 2, false))); - - str_cls->giveAttr("join", new BoxedFunction(boxRTFunction((void*)strJoin, NULL, 2, false))); - - CLFunction *__new__ = boxRTFunction((void*)strNew1, NULL, 1, false); - addRTFunction(__new__, (void*)strNew2, NULL, 2, false); - str_cls->giveAttr("__new__", new BoxedFunction(__new__)); - - str_cls->freeze(); -} - -void teardownStr() { -} - -} diff --git a/src/runtime/tuple.cpp b/src/runtime/tuple.cpp deleted file mode 100644 index 41924394f..000000000 --- a/src/runtime/tuple.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "core/ast.h" -#include "core/common.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -extern "C" Box* createTuple(int64_t nelts, Box* *elts) { - std::vector velts(elts, elts + nelts); - return new BoxedTuple(velts); -} - -void tuple_dtor(BoxedTuple* t) { - typedef std::vector T; - (&t->elts)->~T(); -} - -Box* tupleGetitem(BoxedTuple *self, Box* slice) { - assert(self->cls == tuple_cls); - - i64 size = self->elts.size(); - - if (slice->cls == int_cls) { - i64 n = static_cast(slice)->n; - - if (n < 0) n = size - n; - if (n < 0 || n >= size) { - fprintf(stderr, "indexerror\n"); - raiseExc(); - } - - Box* rtn = self->elts[n]; - return rtn; - } else { - RELEASE_ASSERT(0, ""); - } -} - -Box* tupleLen(BoxedTuple *t) { - assert(t->cls == tuple_cls); - return boxInt(t->elts.size()); -} - -Box* tupleRepr(BoxedTuple *t) { - assert(t->cls == tuple_cls); - - std::ostringstream os(""); - os << "("; - - int n = t->elts.size(); - for (int i = 0; i < n; i++) { - if (i) os << ", "; - - BoxedString *elt_repr =repr(t->elts[i]); - os << elt_repr->s; - } - if (n == 1) os << ","; - os << ")"; - - return boxString(os.str()); -} - -Box* _tupleCmp(BoxedTuple *lhs, BoxedTuple *rhs, AST_TYPE::AST_TYPE op_type) { - int lsz = lhs->elts.size(); - int rsz = rhs->elts.size(); - - bool is_order = (op_type == AST_TYPE::Lt || op_type == AST_TYPE::LtE || op_type == AST_TYPE::Gt || op_type == AST_TYPE::GtE); - - int n = std::min(lsz, rsz); - for (int i = 0; i < n; i++) { - Box* is_eq = compareInternal(lhs->elts[i], rhs->elts[i], AST_TYPE::Eq, NULL); - bool bis_eq = nonzero(is_eq); - - if (bis_eq) continue; - - if (op_type == AST_TYPE::Eq) { - return boxBool(false); - } else if (op_type == AST_TYPE::NotEq) { - return boxBool(true); - } else { - Box* r = compareInternal(lhs->elts[i], rhs->elts[i], op_type, NULL); - return r; - } - } - - if (op_type == AST_TYPE::Lt) - return boxBool(lsz < rsz); - else if (op_type == AST_TYPE::LtE) - return boxBool(lsz <= rsz); - else if (op_type == AST_TYPE::Gt) - return boxBool(lsz > rsz); - else if (op_type == AST_TYPE::GtE) - return boxBool(lsz >= rsz); - else if (op_type == AST_TYPE::Eq) - return boxBool(lsz == rsz); - else if (op_type == AST_TYPE::NotEq) - return boxBool(lsz != rsz); - - RELEASE_ASSERT(0, "%d", op_type); -} - -Box* tupleLt(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::Lt); -} - -Box* tupleLe(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::LtE); -} - -Box* tupleGt(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::Gt); -} - -Box* tupleGe(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::GtE); -} - -Box* tupleEq(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::Eq); -} - -Box* tupleNe(BoxedTuple *self, Box *rhs) { - if (rhs->cls != tuple_cls) { - return NotImplemented; - } - return _tupleCmp(self, static_cast(rhs), AST_TYPE::NotEq); -} - -void setupTuple() { - tuple_cls->giveAttr("__name__", boxStrConstant("tuple")); - - tuple_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)tupleGetitem, NULL, 2, false))); - - tuple_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)tupleLt, NULL, 2, false))); - tuple_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)tupleLe, NULL, 2, false))); - tuple_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)tupleGt, NULL, 2, false))); - tuple_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)tupleGe, NULL, 2, false))); - tuple_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)tupleEq, NULL, 2, false))); - tuple_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)tupleNe, NULL, 2, false))); - - tuple_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)tupleLen, NULL, 1, false))); - tuple_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)tupleRepr, NULL, 1, false))); - tuple_cls->setattr("__str__", tuple_cls->peekattr("__repr__"), NULL, NULL); - - tuple_cls->freeze(); -} - -void teardownTuple() { -} - -} diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp deleted file mode 100644 index fa4174ea4..000000000 --- a/src/runtime/types.cpp +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include "core/options.h" -#include "core/stats.h" -#include "core/types.h" - -#include "runtime/gc_runtime.h" -#include "runtime/objmodel.h" -#include "runtime/types.h" - -#include "gc/collector.h" - -#include "codegen/compvars.h" - -namespace pyston { - -bool IN_SHUTDOWN = false; - -extern "C" BoxedFunction::BoxedFunction(CLFunction *f) : HCBox(&function_flavor, function_cls), f(f) { - if (f->source) { - assert(f->source->ast); - //this->giveAttr("__name__", boxString(&f->source->ast->name)); - this->giveAttr("__name__", boxString(f->source->getName())); - - Box* modname = f->source->parent_module->getattr("__name__", NULL, NULL); - this->giveAttr("__module__", modname); - } -} - -BoxedModule::BoxedModule(const std::string *name, const std::string *fn) : HCBox(&module_flavor, module_cls), fn(*fn) { - this->giveAttr("__name__", boxString(*name)); - this->giveAttr("__file__", boxString(*fn)); -} - -extern "C" Box* boxCLFunction(CLFunction *f) { - return new BoxedFunction(f); -} - -extern "C" CLFunction* unboxCLFunction(Box* b) { - return static_cast(b)->f; -} - -extern "C" void boxGCHandler(GCVisitor *v, void* p) { - Box* b = (Box*)p; - - if (b->cls) { - v->visit(b->cls); - } else { - assert(type_cls == NULL || p == type_cls); - } -} - -extern "C" void hcBoxGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - - HCBox* b = (HCBox*)p; - v->visit(b->hcls); - int nattrs = b->hcls->attr_offsets.size(); - if (nattrs) { - HCBox::AttrList *attr_list = b->attr_list; - assert(attr_list); - v->visit(attr_list); - for (int i = 0; i < nattrs; i++) { - v->visit(attr_list->attrs[i]); - } - } -} - -extern "C" void typeGCHandler(GCVisitor *v, void* p) { - hcBoxGCHandler(v, p); - - BoxedClass *b = (BoxedClass*)p; -} - -extern "C" void hcGCHandler(GCVisitor *v, void* p) { - HiddenClass *hc = (HiddenClass*)p; - for (auto it : hc->children) { - v->visit(it.second); - } -} - -extern "C" void instancemethodGCHandler(GCVisitor *v, void* p) { - BoxedInstanceMethod* im = (BoxedInstanceMethod*)p; - - v->visit(im->obj); - v->visit(im->func); -} - -// This probably belongs in list.cpp? -extern "C" void listGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - - BoxedList *l = (BoxedList*)p; - int size = l->size; - if (size) { - v->visit(l->elts); - v->visitRange((void**)&l->elts->elts[0], (void**)&l->elts->elts[size]); - } - - static StatCounter sc("gc_listelts_visited"); - sc.log(size); -} - -// This probably belongs in tuple.cpp? -extern "C" void tupleGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - - BoxedTuple *t = (BoxedTuple*)p; - int size = t->elts.size(); - for (int i = 0; i < size; i++) { - v->visit(t->elts[i]); - } -} - -// This probably belongs in dict.cpp? -extern "C" void dictGCHandler(GCVisitor *v, void* p) { - boxGCHandler(v, p); - - BoxedDict *d = (BoxedDict*)p; - - // This feels like a cludge, but we need to find anything that - // the unordered_map might have allocated. - // Another way to handle this would be to rt_alloc the unordered_map - // as well, though that incurs extra memory dereferences which would - // be nice to avoid. - void **start = (void**)&d->d; - void **end = start + (sizeof(d->d) / 8); - v->visitPotentialRange(start, end); -} - -extern "C" void conservativeGCHandler(GCVisitor *v, void* p) { - ConservativeWrapper *wrapper = static_cast(p); - assert(wrapper->gc_header.kind_id == conservative_kind.kind_id); - - int size = wrapper->gc_header.kind_data; - assert(size % sizeof(void*) == 0); - - void** start = &wrapper->data[0]; - //printf("Found a %d-byte object; header is %p (object is %p)\n", size, p, start); - v->visitPotentialRange(start, start + (size / sizeof(void*))); -} - -extern "C" { - BoxedClass *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *str_cls, *function_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls; - - const ObjectFlavor type_flavor(&typeGCHandler, NULL); - const ObjectFlavor none_flavor(&boxGCHandler, NULL); - const ObjectFlavor bool_flavor(&boxGCHandler, NULL); - const ObjectFlavor int_flavor(&boxGCHandler, NULL); - const ObjectFlavor float_flavor(&boxGCHandler, NULL); - const ObjectFlavor str_flavor(&boxGCHandler, NULL); - const ObjectFlavor function_flavor(&hcBoxGCHandler, NULL); - const ObjectFlavor instancemethod_flavor(&instancemethodGCHandler, NULL); - const ObjectFlavor list_flavor(&listGCHandler, NULL); - const ObjectFlavor slice_flavor(&hcBoxGCHandler, NULL); - const ObjectFlavor module_flavor(&hcBoxGCHandler, NULL); - const ObjectFlavor dict_flavor(&dictGCHandler, NULL); - const ObjectFlavor tuple_flavor(&tupleGCHandler, NULL); - const ObjectFlavor file_flavor(&boxGCHandler, NULL); - const ObjectFlavor user_flavor(&hcBoxGCHandler, NULL); - - const AllocationKind untracked_kind(NULL, NULL); - const AllocationKind hc_kind(&hcGCHandler, NULL); - const AllocationKind conservative_kind(&conservativeGCHandler, NULL); -} - -void instancemethod_dtor(BoxedInstanceMethod* b) { -} - -extern "C" Box* createClass(std::string *name, BoxedModule *parent_module) { - BoxedClass* rtn = new BoxedClass(true, NULL); - rtn->giveAttr("__name__", boxString(*name)); - - Box* modname = parent_module->getattr("__name__", NULL, NULL); - rtn->giveAttr("__module__", modname); - - return rtn; -} - -extern "C" Box* boxInstanceMethod(Box* obj, Box* func) { - static StatCounter num_ims("num_instancemethods"); - num_ims.log(); - - return new BoxedInstanceMethod(obj, func); -} - -extern "C" BoxedString* noneRepr(Box* v) { - return new BoxedString("None"); -} - -extern "C" BoxedString* functionRepr(BoxedFunction* v) { - // TODO there has to be a better way - if (v == repr_obj) - return boxStrConstant(""); - if (v == len_obj) - return boxStrConstant(""); - if (v == hash_obj) - return boxStrConstant(""); - if (v == range_obj) - return boxStrConstant(""); - if (v == abs_obj) - return boxStrConstant(""); - if (v == min_obj) - return boxStrConstant(""); - if (v == max_obj) - return boxStrConstant(""); - if (v == open_obj) - return boxStrConstant(""); - if (v == chr_obj) - return boxStrConstant(""); - return new BoxedString("function"); -} - -extern "C" BoxedModule* createModule(const std::string *name, const std::string *fn) { - return new BoxedModule(name, fn); -} - -extern "C" { - Box *None = NULL; - Box *NotImplemented = NULL; - Box *repr_obj = NULL; - Box *len_obj = NULL; - Box *hash_obj = NULL; - Box *abs_obj = NULL; - Box *min_obj = NULL; - Box *max_obj = NULL; - Box *open_obj = NULL; - Box *chr_obj = NULL; - Box *trap_obj = NULL; - Box *range_obj = NULL; -} - -extern "C" Box* createSlice(Box* start, Box* stop, Box* step) { - BoxedSlice *rtn = new BoxedSlice(start, stop, step); - rtn->setattr("start", start, NULL, NULL); - rtn->setattr("stop", stop, NULL, NULL); - rtn->setattr("step", step, NULL, NULL); - return rtn; -} - -Box* instancemethodRepr(BoxedInstanceMethod* self) { - return boxStrConstant(""); -} - -Box* sliceRepr(BoxedSlice* self) { - BoxedString *start = repr(self->start); - BoxedString *stop = repr(self->stop); - BoxedString *step = repr(self->step); - std::string s = "slice(" + start->s + ", " + stop->s + ", " + step->s + ")"; - return new BoxedString(s); -} - -Box* typeRepr(BoxedClass* self) { - if (isUserDefined(self)) { - std::ostringstream os; - os << "peekattr("__module__"); - RELEASE_ASSERT(m, ""); - if (m->cls == str_cls) { - BoxedString *sm = static_cast(m); - os << sm->s << '.'; - } - - Box *n = self->peekattr("__name__"); - RELEASE_ASSERT(n, ""); - RELEASE_ASSERT(n->cls == str_cls, "should have prevented you from setting __name__ to non-string"); - BoxedString *sn = static_cast(n); - os << sn->s; - - os << "'>"; - - return boxString(os.str()); - } else { - char buf[80]; - snprintf(buf, 80, "", getNameOfClass(self)->c_str()); - return boxStrConstant(buf); - } -} - -Box* moduleRepr(BoxedModule* m) { - assert(m->cls == module_cls); - - std::ostringstream os; - os << "peekattr("__name__"); - if (!name || name->cls != str_cls) { - os << '?'; - } else { - BoxedString *sname = static_cast(name); - os << sname->s; - } - - // TODO not all modules will be built-in - os << "' (built-in)>"; - return boxString(os.str()); -} - -void str_dtor(BoxedString* s) { - typedef std::string T; - (&s->s)->~T(); -} - -CLFunction* unboxRTFunction(Box* b) { - assert(b->cls == function_cls); - return static_cast(b)->f; -} - -bool TRACK_ALLOCATIONS = false; -void setupRuntime() { - HiddenClass::getRoot(); - - type_cls = new BoxedClass(true, NULL); - type_cls->cls = type_cls; - - none_cls = new BoxedClass(false, NULL); - None = new Box(&none_flavor, none_cls); - gc::registerStaticRootObj(None); - - module_cls = new BoxedClass(true, NULL); - - bool_cls = new BoxedClass(false, NULL); - int_cls = new BoxedClass(false, NULL); - float_cls = new BoxedClass(false, NULL); - str_cls = new BoxedClass(false, (BoxedClass::Dtor)str_dtor); - function_cls = new BoxedClass(true, NULL); - instancemethod_cls = new BoxedClass(false, (BoxedClass::Dtor)instancemethod_dtor); - list_cls = new BoxedClass(false, (BoxedClass::Dtor)list_dtor); - slice_cls = new BoxedClass(true, NULL); - dict_cls = new BoxedClass(false, (BoxedClass::Dtor)dict_dtor); - tuple_cls = new BoxedClass(false, (BoxedClass::Dtor)tuple_dtor); - file_cls = new BoxedClass(false, (BoxedClass::Dtor)file_dtor); - - STR = typeFromClass(str_cls); - BOXED_INT = typeFromClass(int_cls); - BOXED_FLOAT = typeFromClass(float_cls); - BOXED_BOOL = typeFromClass(bool_cls); - NONE = typeFromClass(none_cls); - LIST = typeFromClass(list_cls); - SLICE = typeFromClass(slice_cls); - MODULE = typeFromClass(module_cls); - DICT = typeFromClass(dict_cls); - BOXED_TUPLE = typeFromClass(tuple_cls); - - type_cls->giveAttr("__name__", boxStrConstant("type")); - type_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)typeCall, NULL, 1, true))); - type_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)typeNew, NULL, 2, true))); - type_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)typeRepr, NULL, 1, true))); - type_cls->setattr("__str__", type_cls->peekattr("__repr__"), NULL, NULL); - type_cls->freeze(); - - none_cls->giveAttr("__name__", boxStrConstant("NoneType")); - none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, NULL, 1, false))); - none_cls->setattr("__str__", none_cls->peekattr("__repr__"), NULL, NULL); - none_cls->freeze(); - - module_cls->giveAttr("__name__", boxStrConstant("module")); - module_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)moduleRepr, NULL, 1, false))); - module_cls->setattr("__str__", module_cls->peekattr("__repr__"), NULL, NULL); - module_cls->freeze(); - - setupBool(); - setupInt(); - setupFloat(); - setupStr(); - setupList(); - setupDict(); - setupTuple(); - setupFile(); - - function_cls->giveAttr("__name__", boxStrConstant("function")); - function_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)functionRepr, NULL, 1, false))); - function_cls->setattr("__str__", function_cls->peekattr("__repr__"), NULL, NULL); - function_cls->freeze(); - - instancemethod_cls->giveAttr("__name__", boxStrConstant("instancemethod")); - instancemethod_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instancemethodRepr, NULL, 1, true))); - instancemethod_cls->freeze(); - - slice_cls->giveAttr("__name__", boxStrConstant("slice")); - slice_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)sliceRepr, NULL, 1, true))); - slice_cls->setattr("__str__", slice_cls->peekattr("__repr__"), NULL, NULL); - slice_cls->freeze(); - - setupMath(); - gc::registerStaticRootObj(math_module); - setupTime(); - gc::registerStaticRootObj(time_module); - setupBuiltins(); - gc::registerStaticRootObj(builtins_module); - - - setupCAPI(); - - TRACK_ALLOCATIONS = true; -} - -void freeHiddenClasses(HiddenClass *hcls) { - for (auto it : hcls->children) { - freeHiddenClasses(it.second); - } - rt_free(hcls); -} - -void teardownRuntime() { - // Things start to become very precarious after this point, as the basic classes stop to work. - // TODO it's probably a waste of time to tear these down in non-debugging mode - IN_SHUTDOWN = true; - - if (VERBOSITY("runtime") >= 1) printf("In teardownRuntime\n"); - - teardownCAPI(); - - teardownList(); - teardownInt(); - teardownFloat(); - teardownStr(); - teardownBool(); - teardownDict(); - teardownTuple(); - teardownFile(); - - /* - // clear all the attributes on the base classes before freeing the classes themselves, - // since we will run into problem if we free a class but there is an object somewhere - // else that refers to it. - clearAttrs(bool_cls); - clearAttrs(int_cls); - clearAttrs(float_cls); - clearAttrs(none_cls); - clearAttrs(function_cls); - clearAttrs(instancemethod_cls); - clearAttrs(str_cls); - clearAttrs(list_cls); - clearAttrs(slice_cls); - clearAttrs(type_cls); - clearAttrs(module_cls); - clearAttrs(dict_cls); - clearAttrs(tuple_cls); - clearAttrs(file_cls); - - decref(bool_cls); - decref(int_cls); - decref(float_cls); - decref(function_cls); - decref(instancemethod_cls); - decref(str_cls); - decref(list_cls); - decref(slice_cls); - decref(module_cls); - decref(dict_cls); - decref(tuple_cls); - decref(file_cls); - - ASSERT(None->nrefs == 1, "%ld", None->nrefs); - decref(None); - - decref(none_cls); - decref(type_cls); - */ - - freeHiddenClasses(HiddenClass::getRoot()); - - gc_teardown(); -} - -} diff --git a/src/runtime/types.h b/src/runtime/types.h deleted file mode 100644 index ed41a6722..000000000 --- a/src/runtime/types.h +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_TYPES_H -#define PYSTON_RUNTIME_TYPES_H - -#include "core/types.h" - -namespace pyston { - -extern bool IN_SHUTDOWN; - -class BoxedString; -class BoxedList; -class BoxedDict; -class BoxedTuple; -class BoxedFile; - -void setupInt(); -void teardownInt(); -void setupFloat(); -void teardownFloat(); -void setupStr(); -void teardownStr(); -void setupList(); -void teardownList(); -void list_dtor(BoxedList* l); -void setupBool(); -void teardownBool(); -void dict_dtor(BoxedDict* d); -void setupDict(); -void teardownDict(); -void tuple_dtor(BoxedTuple* d); -void setupTuple(); -void teardownTuple(); -void file_dtor(BoxedFile* d); -void setupFile(); -void teardownFile(); -void setupCAPI(); -void teardownCAPI(); - -void setupMath(); -void setupTime(); -void setupBuiltins(); - -extern "C" { extern BoxedClass *type_cls, *bool_cls, *int_cls, *float_cls, *str_cls, *function_cls, *none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *xrange_cls; } -extern "C" { extern const ObjectFlavor type_flavor, bool_flavor, int_flavor, float_flavor, str_flavor, function_flavor, none_flavor, instancemethod_flavor, list_flavor, slice_flavor, module_flavor, dict_flavor, tuple_flavor, file_flavor, xrange_flavor; } -extern "C" { extern const ObjectFlavor user_flavor; } - -extern "C" { extern Box *None, *NotImplemented, *True, *False; } -extern "C" { extern Box *repr_obj, *len_obj, *hash_obj, *range_obj, *abs_obj, *min_obj, *max_obj, *open_obj, *chr_obj, *trap_obj; } // these are only needed for functionRepr, which is hacky -extern "C" { extern BoxedModule *math_module, *time_module, *builtins_module; } - -extern "C" Box* boxBool(bool); -extern "C" Box* boxInt(i64); -extern "C" i64 unboxInt(Box*); -extern "C" Box* boxFloat(double d); -extern "C" Box* boxInstanceMethod(Box* obj, Box* func); -extern "C" Box* boxStringPtr(const std::string *s); -Box* boxString(const std::string &s); -extern "C" BoxedString* boxStrConstant(const char* chars); -extern "C" void listAppendInternal(Box* self, Box* v); -extern "C" Box* boxCLFunction(CLFunction *f); -extern "C" CLFunction* unboxCLFunction(Box* b); -extern "C" Box* createClass(std::string *name, BoxedModule *parent_module); -extern "C" double unboxFloat(Box *b); -extern "C" Box* createDict(); -extern "C" Box* createList(); -extern "C" Box* createSlice(Box* start, Box* stop, Box* step); -extern "C" Box* createTuple(int64_t nelts, Box* *elts); -extern "C" void printFloat(double d); - - -struct BoxedInt : public Box { - int64_t n; - - BoxedInt(int64_t n) __attribute__((visibility("default"))) : Box(&int_flavor, int_cls), n(n) {} -}; - -struct BoxedFloat : public Box { - double d; - - BoxedFloat(double d) __attribute__((visibility("default"))) : Box(&float_flavor, float_cls), d(d) {} -}; - -struct BoxedBool : public Box { - bool b; - - BoxedBool(bool b) __attribute__((visibility("default"))) : Box(&bool_flavor, bool_cls), b(b) {} -}; - -struct BoxedString : public Box { - const std::string s; - - BoxedString(const std::string &s) __attribute__((visibility("default"))) : Box(&str_flavor, str_cls), s(s) {} -}; - -struct BoxedInstanceMethod : public Box { - Box *obj, *func; - - BoxedInstanceMethod(Box *obj, Box *func) __attribute__((visibility("default"))) : Box(&instancemethod_flavor, instancemethod_cls), obj(obj), func(func) {} -}; - -struct BoxedList : public Box { - struct ElementArray : GCObject { - Box* elts[0]; - - ElementArray() : GCObject(&untracked_kind) {} - - void *operator new(size_t size, int capacity) { - return rt_alloc(capacity * sizeof(Box*) + sizeof(BoxedList::ElementArray)); - } - }; - - int64_t size, capacity; - ElementArray *elts; - - BoxedList() __attribute__((visibility("default"))) : Box(&list_flavor, list_cls), size(0), capacity(0) {} - - void ensure(int space); -}; - -struct BoxedTuple : public Box { - const std::vector elts; - - BoxedTuple(std::vector &elts) __attribute__((visibility("default"))) : Box(&tuple_flavor, tuple_cls), elts(elts) {} -}; - -struct BoxedFile : public Box { - FILE *f; - bool closed; - BoxedFile(FILE* f) __attribute__((visibility("default"))) : Box(&file_flavor, file_cls), f(f), closed(false) {} -}; - -struct PyHasher { - size_t operator()(Box*) const; -}; - -struct PyEq { - bool operator()(Box*, Box*) const; -}; - -struct PyLt { - bool operator()(Box*, Box*) const; -}; - -struct ConservativeWrapper : GCObject { - void* data[0]; - - ConservativeWrapper(size_t data_size) : GCObject(&conservative_kind), data() { - assert(data_size % sizeof(void*) == 0); - gc_header.kind_data = data_size; - } - - void *operator new(size_t size, size_t data_size) { - assert(size == sizeof(ConservativeWrapper)); - return rt_alloc(data_size + size); - } - - static ConservativeWrapper* fromPointer(void* p) { - ConservativeWrapper* o = (ConservativeWrapper*)((void**)p - 1); - assert(&o->data == p); - return o; - } -}; - -template -class StlCompatAllocator { - public: - typedef size_t size_type; - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef std::ptrdiff_t difference_type; - - StlCompatAllocator() {} - template - StlCompatAllocator(const StlCompatAllocator& other) {} - - template - struct rebind { - typedef StlCompatAllocator other; - }; - - pointer allocate(size_t n) { - size_t to_allocate = n * sizeof(value_type); - assert(to_allocate < (1<<16)); - - ConservativeWrapper* rtn = new (to_allocate) ConservativeWrapper(to_allocate); - return (pointer)&rtn->data[0]; - } - - void deallocate(pointer p, size_t n) { - ConservativeWrapper* o = ConservativeWrapper::fromPointer(p); - rt_free(o); - } - - // I would never be able to come up with this on my own: - // http://en.cppreference.com/w/cpp/memory/allocator/construct - template - void construct(U* p, Args&&... args) { - ::new((void*)p) U(std::forward(args)...); - } - - template - void destroy(U* p) { - p->~U(); - } -}; - -struct BoxedDict : public Box { - typedef std::unordered_map > > PyDict; - PyDict d; - - BoxedDict() __attribute__((visibility("default"))) : Box(&dict_flavor, dict_cls) {} - - void verify() { - int i = 0; - for (auto it : d) { - ++i; - } - assert(i == d.size()); - } -}; - -struct BoxedFunction : public HCBox { - CLFunction *f; - - BoxedFunction(CLFunction *f); -}; - -struct BoxedModule : public HCBox { - const std::string fn; // for traceback purposes; not the same as __file__ - - BoxedModule(const std::string *name, const std::string *fn); -}; - -struct BoxedSlice : public HCBox { - Box *start, *stop, *step; - BoxedSlice(Box *lower, Box *upper, Box *step) : HCBox(&slice_flavor, slice_cls), start(lower), stop(upper), step(step) {} -}; - -extern "C" void boxGCHandler(GCVisitor *v, void* p); - -} -#endif - diff --git a/src/runtime/util.cpp b/src/runtime/util.cpp deleted file mode 100644 index 5ad81223a..000000000 --- a/src/runtime/util.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "core/options.h" - -#include "runtime/types.h" -#include "runtime/util.h" - -namespace pyston { - -void parseSlice(BoxedSlice* slice, int size, i64 *out_start, i64 *out_stop, i64 *out_step) { - BoxedSlice *sslice = static_cast(slice); - - Box *start = sslice->start; - assert(start); - Box *stop = sslice->stop; - assert(stop); - Box *step = sslice->step; - assert(step); - - RELEASE_ASSERT(start->cls == int_cls || start->cls == none_cls, ""); - RELEASE_ASSERT(stop->cls == int_cls || stop->cls == none_cls, ""); - RELEASE_ASSERT(step->cls == int_cls || step->cls == none_cls, ""); - - int64_t istart; - int64_t istop; - int64_t istep = 1; - - if (step->cls == int_cls) { - istep = static_cast(step)->n; - } - - if (start->cls == int_cls) { - istart = static_cast(start)->n; - if (istart < 0) - istart = size + istart; - } else { - if (istep > 0) - istart = 0; - else - istart = size - 1; - } - if (stop->cls == int_cls) { - istop = static_cast(stop)->n; - if (istop < 0) - istop = size + istop; - } else { - if (istep > 0) - istop = size; - else - istop = -1; - } - - if (istep == 0) { - fprintf(stderr, "ValueError: slice step cannot be zero\n"); - raiseExc(); - } - - if (istep > 0) { - if (istart < 0) - istart = 0; - if (istop > size) - istop = size; - } else { - if (istart >= size) - istart = size-1; - if (istop < 0) - istop = -1; - } - - *out_start = istart; - *out_stop = istop; - *out_step = istep; -} - -} diff --git a/src/runtime/util.h b/src/runtime/util.h deleted file mode 100644 index b6514c686..000000000 --- a/src/runtime/util.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2014 Dropbox, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PYSTON_RUNTIME_UTIL_H -#define PYSTON_RUNTIME_UTIL_H - -#include "core/types.h" - -namespace pyston { - -class BoxedSlice; - -void parseSlice(BoxedSlice* slice, int size, i64 *out_start, i64 *out_stop, i64 *out_end); - -void raiseExc() __attribute__((__noreturn__)); - -} -#endif diff --git a/test/test.c b/test/test.c deleted file mode 100644 index 7122fd514..000000000 --- a/test/test.c +++ /dev/null @@ -1,8 +0,0 @@ -struct C { - long a; - char* b; -}; - -void main() { - struct C c; -} diff --git a/test/test.cpp b/test/test.cpp deleted file mode 100644 index a9b389f2a..000000000 --- a/test/test.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include "stdint.h" - -void set64(int64_t* ptr) { - *ptr = 0x1234; -} - -void set64full(int64_t* ptr) { - *ptr = 0x1234567890; -} - -void set32(int64_t* ptr) { - *(int32_t*)ptr = 0x1234; -} diff --git a/test/test.s b/test/test.s deleted file mode 100644 index 5aa0c079c..000000000 --- a/test/test.s +++ /dev/null @@ -1,6 +0,0 @@ - .text - movq $123, 4(%rsp) - movq $123, 4(%rcx) - movsd %xmm0, %xmm1 - movsd %xmm0, %xmm9 - sub $123, %rsp diff --git a/test/test_extension/setup.py b/test/test_extension/setup.py deleted file mode 100644 index 1d22d4dc4..000000000 --- a/test/test_extension/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from distutils.core import setup, Extension - -test_module = Extension("test", sources = ["test.c"]) - -setup(name="test", - version="1.0", - description="test", - ext_modules=[test_module], - ) diff --git a/test/test_extension/test.c b/test/test_extension/test.c deleted file mode 100644 index 030713563..000000000 --- a/test/test_extension/test.c +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include - -static PyObject* stored = NULL; -static PyObject * -test_store(PyObject *self, PyObject *args) -{ - PyObject* arg; - - //raise(SIGTRAP); - if (!PyArg_ParseTuple(args, "O", &arg)) - return NULL; - - Py_INCREF(arg); - stored = arg; - return Py_BuildValue(""); -} - -void incref(PyObject *o) { - Py_INCREF(o); -} - -static PyObject * -test_load(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, "")) - return NULL; - - assert(stored); - Py_INCREF(stored); - return stored; -} - -static PyMethodDef TestMethods[] = { - {"store", test_store, METH_VARARGS, "Store."}, - {"load", test_load, METH_VARARGS, "Load."}, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - -PyMODINIT_FUNC -inittest(void) -{ - PyObject *m; - - m = Py_InitModule("test", TestMethods); - if (m == NULL) - return; -} diff --git a/test/tests/1.py b/test/tests/1.py deleted file mode 100644 index f56eefb2f..000000000 --- a/test/tests/1.py +++ /dev/null @@ -1,4 +0,0 @@ -x = 1 + 2 -print x * 3 -print 1, -print 2 diff --git a/test/tests/10.py b/test/tests/10.py deleted file mode 100644 index 068e76060..000000000 --- a/test/tests/10.py +++ /dev/null @@ -1,16 +0,0 @@ -x = 10 -y = x - 1 -z = 1 -while x: - x = x - 1 - if x == 2: - break - # dead but legal: - 0 - continue - elif x == 5: - continue - print x -else: - print "finished" -print y, z diff --git a/test/tests/11.py b/test/tests/11.py deleted file mode 100644 index f0ce70f23..000000000 --- a/test/tests/11.py +++ /dev/null @@ -1,27 +0,0 @@ -total = 0 -i = 1 -while i < 1000: - i = i + 1 - j = 2 - while j * j <= i: - if i % j == 0: - break - j = j + 1 - else: - total = total + i -print total - -def f(): - total = 0 - i = 1 - while i < 1000: - i = i + 1 - j = 2 - while j * j <= i: - if i % j == 0: - break - j = j + 1 - else: - total = total + i - print total -f() diff --git a/test/tests/12.py b/test/tests/12.py deleted file mode 100644 index ee1c27c79..000000000 --- a/test/tests/12.py +++ /dev/null @@ -1,9 +0,0 @@ -def f(x): - if x: - return 1 - else: - return 2 - -print f(-1) -print f(0) -print f(1) diff --git a/test/tests/13.py b/test/tests/13.py deleted file mode 100644 index 5cd962b44..000000000 --- a/test/tests/13.py +++ /dev/null @@ -1,14 +0,0 @@ -def f(x): - if x: - pass - else: - x = 1 - return x -def ident(o): - return o - -ident = ident(ident) -f = ident(f) -print f(-1) -print f(0) -print f(1) diff --git a/test/tests/14.py b/test/tests/14.py deleted file mode 100644 index 6c7cc9025..000000000 --- a/test/tests/14.py +++ /dev/null @@ -1,8 +0,0 @@ -# None handling -def f1(): - pass -n = f1() -print "got n" -print n -print None - diff --git a/test/tests/15.py b/test/tests/15.py deleted file mode 100644 index aa0d98238..000000000 --- a/test/tests/15.py +++ /dev/null @@ -1,12 +0,0 @@ -# Regression test: -# use the same string constant from two different functions. MCJIT will allow you to use a -# global variable from another module, but it will crash at deallocation. - -def f1(): - print "hello world" - return 0 -def f2(): - print "hello world" - return 0 -f1() -f2() diff --git a/test/tests/16.py b/test/tests/16.py deleted file mode 100644 index c47cb1d1c..000000000 --- a/test/tests/16.py +++ /dev/null @@ -1,23 +0,0 @@ -# Deoptimization test: - -def main(z): - def ident(x): - return x - - def f1(x): - return x - def f2(x): - return "x" - - f1 = ident(f1) - f2 = ident(f2) - - x = ident(z) - y = 10 - while y: - x = x + y - y = y - 1 - - print f1(y), f2(y) -main(10) - diff --git a/test/tests/17.py b/test/tests/17.py deleted file mode 100644 index 0251134ef..000000000 --- a/test/tests/17.py +++ /dev/null @@ -1,31 +0,0 @@ -# A harder deopt test: there can be temporaries that aren't in the symbol table that need to be transferred -# to the deopt version - -def p(x, y): - print x, y -def i1(x): - return x -def i2(x): - return "x" -p(i1(1), i2(1)) - -def ident(x): - return 2 -print 1 + ident(1) -def m(): - def ident(x): - return 2 - print 1 + ident(1) -m() - -def f(n, f): - if n <= 0: - return 0 - return 1 + f(n-1, f) + 1 -print f(10, f) - -def f2(n, f): - if n <= 2: - return n - return f(n-1, f) + f(n-2, f) -print f2(10, f2) diff --git a/test/tests/18.py b/test/tests/18.py deleted file mode 100644 index 2268f009c..000000000 --- a/test/tests/18.py +++ /dev/null @@ -1,14 +0,0 @@ -# Regression test: making sure we can deopt unboxed int methods later: - -def ident(x): - return x - -x = 1 -a = x.__add__ -print a(2) -print ident(a)(2) -print ident(a)(ident(2)) - -def o(): - return 1 -print 1 + o() diff --git a/test/tests/19.py b/test/tests/19.py deleted file mode 100644 index a19f3e74d..000000000 --- a/test/tests/19.py +++ /dev/null @@ -1,9 +0,0 @@ -# Simple refcounting test: make sure the temporary (result of f()) doesn't get freed until after g returns - -def f(): - return "hi" - -def g(s): - print s - -print g(f()) diff --git a/test/tests/2.py b/test/tests/2.py deleted file mode 100644 index 88a5228cf..000000000 --- a/test/tests/2.py +++ /dev/null @@ -1,4 +0,0 @@ -def ident(x): - return x -print 1, ident(2), 3, ident(4) -print ident("hello") diff --git a/test/tests/20.py b/test/tests/20.py deleted file mode 100644 index 1a03c2fc8..000000000 --- a/test/tests/20.py +++ /dev/null @@ -1,30 +0,0 @@ -# Programs are well-defined even if they contain potentially-undefined variables -# The exceptions are well-defined too, but I don't support that yet - -if 1: - x = 1 -print x - - -z = 1 - -if z: - y = 2 -else: - pass - -if z: - print y - w = y -else: - pass -print w - -while 1: - a = 1 - break -print a - -if 0: - # this is only an error if the code gets hit: - print not_defined diff --git a/test/tests/21.py b/test/tests/21.py deleted file mode 100644 index c06e97a0b..000000000 --- a/test/tests/21.py +++ /dev/null @@ -1,8 +0,0 @@ -# Expected failure: even though we could copy the "definedness" information in the assignment, -# that's actually an error. - -if 0: - x = 1 -y = x -if 0: - print y diff --git a/test/tests/22.py b/test/tests/22.py deleted file mode 100644 index 609f5ae9e..000000000 --- a/test/tests/22.py +++ /dev/null @@ -1,3 +0,0 @@ -# Expected failure: stacktrace testing - -print 5 % 0 diff --git a/test/tests/23.py b/test/tests/23.py deleted file mode 100644 index 2020504d3..000000000 --- a/test/tests/23.py +++ /dev/null @@ -1 +0,0 @@ -not_defined diff --git a/test/tests/24.py b/test/tests/24.py deleted file mode 100644 index 68506b1a9..000000000 --- a/test/tests/24.py +++ /dev/null @@ -1,3 +0,0 @@ -# Expected failure: adding things that can't be added - -1 + "" diff --git a/test/tests/25.py b/test/tests/25.py deleted file mode 100644 index d049d3dd5..000000000 --- a/test/tests/25.py +++ /dev/null @@ -1,19 +0,0 @@ -# Regression test - -def ident(x): - return x - -y = 10 -while y: - print ident(y) - y = y - 1 - -def a(x): - print "a", x - -def b(a, x): - a(x) - -b(a, 1) -b(a, 2) - diff --git a/test/tests/26.py b/test/tests/26.py deleted file mode 100644 index d2984ed3d..000000000 --- a/test/tests/26.py +++ /dev/null @@ -1,20 +0,0 @@ -# run_args: -n -# statcheck: stats["slowpath_runtimecall"] <= 5 -# statcheck: stats.get("slowpath_callclfunc", 0) <= 5 -# Simple patchpoint test: - -def f(): - def p(a, b, c, d): - print a, b, c, d - - y = 100 - while y: - p(1, y, 2, 3) - y = y - 1 - - y = 100 - while y: - p(1, y, "hello", 5) - y = y - 1 -f() - diff --git a/test/tests/27.py b/test/tests/27.py deleted file mode 100644 index b50a8a523..000000000 --- a/test/tests/27.py +++ /dev/null @@ -1,24 +0,0 @@ -# Re-patching test: have a single callsite that frequently has different target functions: - -def a(): - print "a" - return 1 - -def b(): - print "b" - return 2 - -def c(f): - # The difficult callsite: - return f() - -x = 100 -y = 0 -while x: - y = y + c(a) - print y - y = y + c(b) - print y - x = x - 1 - -print y diff --git a/test/tests/28.py b/test/tests/28.py deleted file mode 100644 index ad10627e8..000000000 --- a/test/tests/28.py +++ /dev/null @@ -1,15 +0,0 @@ -# patching test: change type arguments - -def c(f, p): - return f(p()) * 1 - -def pi(): - return 1 -def ps(): - return "hello world" - -def ident(x): - return x - -print c(ident, pi) -print c(ident, ps) diff --git a/test/tests/29.py b/test/tests/29.py deleted file mode 100644 index 07b85f1ea..000000000 --- a/test/tests/29.py +++ /dev/null @@ -1,13 +0,0 @@ -# Repatching test: more arguments - -def p(a, b, c, d, e, f): - print a, b, c, d, e, f - -y = 10 -while y: - x = 5 - if y == 2: - x = "hello world" - p(1, y, 2, x, 4, 5) - y = y - 1 - diff --git a/test/tests/3.py b/test/tests/3.py deleted file mode 100644 index 3db9dbfc6..000000000 --- a/test/tests/3.py +++ /dev/null @@ -1,9 +0,0 @@ -def double(x=1): - return x * 2 -def f2(x): - return 0 - -print double(2) -print double(3) -print double(4) -print double(5) diff --git a/test/tests/30.py b/test/tests/30.py deleted file mode 100644 index 6582f1d24..000000000 --- a/test/tests/30.py +++ /dev/null @@ -1,13 +0,0 @@ -# run_args: -n -# statcheck: 1 <= stats["OSR exits"] <= 2 -# statcheck: stats['slowpath_binop'] <= 10 - -x = 100000 -y = 0 -while x: - x = x - 1 - y = y + x - # print x, y - -print y - diff --git a/test/tests/31.expected b/test/tests/31.expected deleted file mode 100644 index 10e3c6863..000000000 --- a/test/tests/31.expected +++ /dev/null @@ -1 +0,0 @@ -100094995 diff --git a/test/tests/31.py b/test/tests/31.py deleted file mode 100644 index 9a7399cae..000000000 --- a/test/tests/31.py +++ /dev/null @@ -1,21 +0,0 @@ -# nested OSR test -# While in the outer invocations (level=0 or 1), the inner-most invocation will cause -# an OSR recompilation. -# The outer versions should be able to join the optimized version once they decide -# to osr as well. -# Actually, I'm not so sure what this actually ends up testing - -def f(level, f): - if level == 0: - n = 10010 - else: - n = 10 - - k = 0 - while n: - if level <= 2: - k = k + f(level + 1, f) - n = n - 1 - k = k + n - return k -print f(0, f) diff --git a/test/tests/32.expected b/test/tests/32.expected deleted file mode 100644 index ba5baa812..000000000 --- a/test/tests/32.expected +++ /dev/null @@ -1 +0,0 @@ -166666500 diff --git a/test/tests/32.py b/test/tests/32.py deleted file mode 100644 index a519de3a8..000000000 --- a/test/tests/32.py +++ /dev/null @@ -1,11 +0,0 @@ -# Nested-loop test for OSR - -y = 1000 -t = 0 -while y: - x = y - while x: - x = x - 1 - t = t + x - y = y - 1 -print t diff --git a/test/tests/33.py b/test/tests/33.py deleted file mode 100644 index e36cc5efc..000000000 --- a/test/tests/33.py +++ /dev/null @@ -1,16 +0,0 @@ -# making sure we can deoptimize within a loop (line 9) - -def d(x): - return x - 1 - -def f(d): - x = 10 - while x: - x = d(x) - -x = 10000 -y = 0 -while x: - f(d) - x = x - 1 -print y diff --git a/test/tests/34.py b/test/tests/34.py deleted file mode 100644 index 9185b9f60..000000000 --- a/test/tests/34.py +++ /dev/null @@ -1,8 +0,0 @@ -# making sure we can deoptimize within a loop (line 9) - -if 1: - x = 2 -else: - x = d() # d is undefined - -print x diff --git a/test/tests/35.py b/test/tests/35.py deleted file mode 100644 index 2f064cd61..000000000 --- a/test/tests/35.py +++ /dev/null @@ -1,12 +0,0 @@ -# Osr test where we will OSR into a version with speculations, but where the existing speculations will already be false - -def i(y): - print y * 2 - return "hello" - -n = 20000 -x = 0 -while n: - n = n - 1 - x = i(x) * 2 -print x diff --git a/test/tests/36.py b/test/tests/36.py deleted file mode 100644 index a8e3799cb..000000000 --- a/test/tests/36.py +++ /dev/null @@ -1,19 +0,0 @@ -# Another variation on a theme: - -def d(x): - return x - 1 - -def f(d): - x = 10 - while x: - x = d(x) - -x = 100005 -while x: - f(d) - x = x - 1 - -f(d) -if 0: - pass -d diff --git a/test/tests/37.py b/test/tests/37.py deleted file mode 100644 index a900b9145..000000000 --- a/test/tests/37.py +++ /dev/null @@ -1,17 +0,0 @@ -def call(f): - return f() - -def f(): - return 1 - -print call(f) -print call(int) -print int(1) -print int("2") - -print int(1.1) -print int(1.5) -print int(1.9) -print int(-1.1) -print int(-1.5) -print int(-1.9) diff --git a/test/tests/38.py b/test/tests/38.py deleted file mode 100644 index 0edff466f..000000000 --- a/test/tests/38.py +++ /dev/null @@ -1,14 +0,0 @@ -# setattr/getattr test: turns out functions are the only mutable objects I support right now - -def f(): - pass -def g(): - pass - -def print_x(o): - print o.x - -f.x = 1 -g.x = 2 -print_x(f) -print_x(g) diff --git a/test/tests/39.py b/test/tests/39.py deleted file mode 100644 index 9e209e1dd..000000000 --- a/test/tests/39.py +++ /dev/null @@ -1 +0,0 @@ -int.a = 1 diff --git a/test/tests/4.py b/test/tests/4.py deleted file mode 100644 index 788161f5f..000000000 --- a/test/tests/4.py +++ /dev/null @@ -1,3 +0,0 @@ -def ident(x): - return x -print ident(1) + 1 diff --git a/test/tests/40.py b/test/tests/40.py deleted file mode 100644 index 750215ccc..000000000 --- a/test/tests/40.py +++ /dev/null @@ -1,2 +0,0 @@ -i = 0 -i.a = 0 diff --git a/test/tests/41.py b/test/tests/41.py deleted file mode 100644 index c69886dd5..000000000 --- a/test/tests/41.py +++ /dev/null @@ -1,28 +0,0 @@ -# Harder function-setattr tests: -def f(n): - def inner(): - pass - inner.n = n - return inner - -f1 = f(1) -f2 = f(2) -print f1.n -print f2.n - -def a(): - pass - -def i(x): - return x - -if i(1) != 0: - a.x = 1 -print a.x - -def b(): - pass -b.x = 1 -print b.x -if i(0) != 0: - print b.x diff --git a/test/tests/42.py b/test/tests/42.py deleted file mode 100644 index bc8914382..000000000 --- a/test/tests/42.py +++ /dev/null @@ -1,15 +0,0 @@ -def p(x): - print x.a - print x.b - -def s(x, n): - x.a = n - x.b = "hello world" - -n = 100 -while n: - n = n - 1 - def f(): - pass - s(f, n) - p(f) diff --git a/test/tests/43.py b/test/tests/43.py deleted file mode 100644 index aa7dd4361..000000000 --- a/test/tests/43.py +++ /dev/null @@ -1,10 +0,0 @@ -# icsetattr-existingattr test - -def f(): - pass - -n = 10 -while n: - n = n - 1 - f.x = n - print f.x diff --git a/test/tests/44.py b/test/tests/44.py deleted file mode 100644 index 62281c4dc..000000000 --- a/test/tests/44.py +++ /dev/null @@ -1,10 +0,0 @@ -# icsetattr-newattr test - -n = 10 -while n: - def f(): - pass - - n = n - 1 - f.x = n - print f.x diff --git a/test/tests/45.py b/test/tests/45.py deleted file mode 100644 index f0616920d..000000000 --- a/test/tests/45.py +++ /dev/null @@ -1,15 +0,0 @@ -# Testing to make sure that functions like __add__ only get looked up on the class, not the instance: - -class C(object): - def __add__(self, rhs): - print "C.__add__" - -def new_add(lhs, rhs): - print "new __add__" - -c = C() -c.__add__ = new_add # this should NOT change the result of the next add: -c + c - -C.__add__ = new_add -c + c diff --git a/test/tests/46.py b/test/tests/46.py deleted file mode 100644 index 3eed3d896..000000000 --- a/test/tests/46.py +++ /dev/null @@ -1,18 +0,0 @@ -# Metaclass test: - -class M(type): - a = 1 - -class C(object): - __metaclass__ = M - b = 2 - -o = C() -o.c = 3 - -print M.a -print C.b -print C.a -print o.c -print o.b -print o.a # this should error diff --git a/test/tests/47.py b/test/tests/47.py deleted file mode 100644 index 38cfc5c9a..000000000 --- a/test/tests/47.py +++ /dev/null @@ -1,9 +0,0 @@ -# run_args: -n -# statcheck: 1 <= stats['slowpath_binop'] <= 5 -def i(): - return 0 - -n = 10000 -while n: - n = n - 1 - i() + i() diff --git a/test/tests/48.py b/test/tests/48.py deleted file mode 100644 index 701214cad..000000000 --- a/test/tests/48.py +++ /dev/null @@ -1,5 +0,0 @@ -# This should raise a python level error, not an assertion in the compiler - -x = 1 -y = x.doesnt_exist -print y + 1 diff --git a/test/tests/49.py b/test/tests/49.py deleted file mode 100644 index eacab0ee7..000000000 --- a/test/tests/49.py +++ /dev/null @@ -1,3 +0,0 @@ -# This should raise a python level error, not an assertion in the compiler - -print int.doesnt_exist diff --git a/test/tests/5.py b/test/tests/5.py deleted file mode 100644 index 5bfaf96e4..000000000 --- a/test/tests/5.py +++ /dev/null @@ -1,3 +0,0 @@ -print "hello world" -b = "b" -print "a" + b diff --git a/test/tests/50.py b/test/tests/50.py deleted file mode 100644 index 51c639667..000000000 --- a/test/tests/50.py +++ /dev/null @@ -1,10 +0,0 @@ -# Very basic class handling - -class C(object): - pass -print C.__name__ - -C.n = 1 -print C.n -c = C() -print c.n diff --git a/test/tests/51.py b/test/tests/51.py deleted file mode 100644 index 32a2c16d4..000000000 --- a/test/tests/51.py +++ /dev/null @@ -1,26 +0,0 @@ -# Basic class functionality test - -class C(object): - def __init__(self, n): - print "C.__init__" - self.n = n - - def f(self, m): - n = self.n - self.n = m - return n + m - - def __add__(self, rhs): - print "C.__add__" - return self.n + rhs - -print C.__name__ - -c = C(1) -print c.f(2) -print c.f(3) -print c + 4 -c = C(5) -print c.f(6) -print c.f(7) -print c + 8 diff --git a/test/tests/52.py b/test/tests/52.py deleted file mode 100644 index 2f74b07ce..000000000 --- a/test/tests/52.py +++ /dev/null @@ -1,22 +0,0 @@ -# Making sure that classes can stay mutable: - -class C(object): - def f(self): - return 1 - - def __add__(self, rhs): - print "C.__add__", - return 1 + rhs - -c = C() - -def new_add(self, rhs): - print "new_add", - return 2 + rhs - -n = 10 -while n: - n = n - 1 - print n, c + n - if n == 6: - C.__add__ = new_add diff --git a/test/tests/53.py b/test/tests/53.py deleted file mode 100644 index 7f91bca4d..000000000 --- a/test/tests/53.py +++ /dev/null @@ -1,21 +0,0 @@ -# handling re-built classes: - -def make_class(n): - class C(object): - pass - C.n = n - return C - -C1 = make_class(1) -C2 = make_class(2) -print C1.n -print C2.n -print C1 == C1 -print C1 == C2 - -c1 = C1() -print c1.n -c2 = C2() -print c2.n -print c1 == c1 -print c1 == c2 diff --git a/test/tests/54.py b/test/tests/54.py deleted file mode 100644 index 3f6d716a1..000000000 --- a/test/tests/54.py +++ /dev/null @@ -1,28 +0,0 @@ -# o() and o.__call__() are not always equivalent due to the possibility of __getattribute__ or instance attributes: - -def f(): - print "func" - -class C(object): - def __getattribute__(self, attr): - print "__getattribute__", attr - if attr == "__call__": - return f - return object.__getattribute__(self, attr) - - def __call__(self): - print "__call__" - -c = C() -c() -c.__call__() - -print type -print type(1) - -# As evidenced by the following real + important example: -# type() is a special function that gets the type of an object: -print type(C) # prints "" -# but type.__call__() is the clsattr for any (non-metaclassed) class, -# which is how object creation gets handled: -print repr(type.__call__(C))[:20] # prints "<__main__.C object at 0xXXXXXXX>" diff --git a/test/tests/55.py b/test/tests/55.py deleted file mode 100644 index e67e46b16..000000000 --- a/test/tests/55.py +++ /dev/null @@ -1,34 +0,0 @@ -# attr-getting resolution. - -class M(type): - def __getattribute__(self, attr): - print "M.__getattribute__" - return type.__getattribute__(self, attr) - - def __eq__(lhs, rhs): - print "__eq__" - return 0 - -class C(object): - __metaclass__ = M - - def __getattribute__(self, attr): - print "C.__getattribute__" - if attr == "n": - return 1 - return object.__getattribute__(self, attr) - - def __getattr__(self, attr): - print "C.__getattr__" - if attr == "m": - return 2 - return object.__getattr__(self, attr) - -c = C() -print c.n -print c.m -c.__getattribute__ -C.__getattribute__ - -print C == C -print c == c diff --git a/test/tests/56.py b/test/tests/56.py deleted file mode 100644 index b1b905daf..000000000 --- a/test/tests/56.py +++ /dev/null @@ -1,7 +0,0 @@ -# I guess type.__name__ works specially: - -class C(object): - __name__ = 1 -print C.__name__ -c = C() -print c.__name__ diff --git a/test/tests/57.py b/test/tests/57.py deleted file mode 100644 index 326126675..000000000 --- a/test/tests/57.py +++ /dev/null @@ -1,20 +0,0 @@ -# Testing im-boxing: - -class C(object): - def __call__(*args): - print args - return args -def mul(*args): - return args -class C1(object): - __add__ = C() - __sub__ = lambda *args: args - __mul__ = mul - -c = C1() -print c + 1 -print c - 1 -print c * 1 -print c.__add__ == C1.__add__ -print c.__sub__ == C1.__sub__ -print c.__mul__ == C1.__mul__ diff --git a/test/tests/58.py b/test/tests/58.py deleted file mode 100644 index d5a1862e3..000000000 --- a/test/tests/58.py +++ /dev/null @@ -1,12 +0,0 @@ -# int.__init__ should do nothing; it should all be handled by int.__new__ - -i = 1 -j = 1 -print int.__init__(i, 2) - -def p(n): - print n - -p(i) -p(j) - diff --git a/test/tests/59.py b/test/tests/59.py deleted file mode 100644 index 5385ed4ae..000000000 --- a/test/tests/59.py +++ /dev/null @@ -1,16 +0,0 @@ -# List test - -l = [] -print l - -l.append(2) -print l.__len__() -print l - -l2 = [] -l.append(l2) -print l - -print list() - -print [1, 2, 3] diff --git a/test/tests/6.py b/test/tests/6.py deleted file mode 100644 index 6b869ec33..000000000 --- a/test/tests/6.py +++ /dev/null @@ -1,5 +0,0 @@ -def ident(x): - return x - -print ident(1) + 1 -print ident("hello ") + "world" diff --git a/test/tests/60.py b/test/tests/60.py deleted file mode 100644 index 2c04d4179..000000000 --- a/test/tests/60.py +++ /dev/null @@ -1,26 +0,0 @@ -# len() and repr() - -l = [] -print len(l) -l.append(1) -print len(l) - -print len("hello world") - -print repr("hello 2") -print repr(1) -print repr -print repr(repr) -print str -print len -print str(str) - -class C(object): - def __init__(self, n): - self.n = n - def __len__(self): - return self.n - -print len(C(1)) -print len(1) -print len(C("hello world")) diff --git a/test/tests/61.py b/test/tests/61.py deleted file mode 100644 index e64c25c15..000000000 --- a/test/tests/61.py +++ /dev/null @@ -1,8 +0,0 @@ -# varargs (but not starargs yet) - -def f(*args): - print args - -f() -f(1) -f(1, "hello world") diff --git a/test/tests/62.py b/test/tests/62.py deleted file mode 100644 index 755803350..000000000 --- a/test/tests/62.py +++ /dev/null @@ -1,8 +0,0 @@ -# Stackmaps don't get emitted for code that's dead even if it exists in IR: - -class C(object): - pass - -c = C() -if 1 == 0: - c.x = 1 diff --git a/test/tests/63.py b/test/tests/63.py deleted file mode 100644 index 7508d5395..000000000 --- a/test/tests/63.py +++ /dev/null @@ -1,12 +0,0 @@ -class C(object): - def __str__(self): - return "str" - def __repr__(self): - return "repr" - -print C() - -print int(1) -print repr(1) -print str("hi") -print repr("hi") diff --git a/test/tests/65.py b/test/tests/65.py deleted file mode 100644 index 897b04e52..000000000 --- a/test/tests/65.py +++ /dev/null @@ -1,18 +0,0 @@ -# Checking how functions get references to their modules - -import sys -m = sys.modules['__main__'] - -class C(object): - pass -print C - -m.__name__ = "test" - -print C -print C.__module__ # should still be "__main__" -class C(object): - pass -print C -print C.__module__ # should now be "test" - diff --git a/test/tests/66.py b/test/tests/66.py deleted file mode 100644 index fa649ac33..000000000 --- a/test/tests/66.py +++ /dev/null @@ -1,7 +0,0 @@ -# Make sure that overriding __file__ doesn't change the traceback - -import sys -m = sys.modules['__main__'] -m.__file__ = "/dev/null" - -a # not defined, should throw diff --git a/test/tests/67.py b/test/tests/67.py deleted file mode 100644 index 312d22008..000000000 --- a/test/tests/67.py +++ /dev/null @@ -1,7 +0,0 @@ -print type(1) -print type("") -print type(None) -print type([]) -print slice -print type(str) -print type(type) diff --git a/test/tests/68.py b/test/tests/68.py deleted file mode 100644 index c25c9677c..000000000 --- a/test/tests/68.py +++ /dev/null @@ -1,5 +0,0 @@ -def f(): - pass - -print f.__name__ -print f.__module__ diff --git a/test/tests/69.py b/test/tests/69.py deleted file mode 100644 index c1a58bc9c..000000000 --- a/test/tests/69.py +++ /dev/null @@ -1,12 +0,0 @@ -# I guess the __name__ attribute on classes is weird? - -class C(object): - pass - -print C.__name__ -print C.__module__ -# print C.__dict__.keys() # __name__ doesn't appear! -# print dir(C) # __name__ doesn't appear! -c = C() - -print c.__name__ # this should err diff --git a/test/tests/7.py b/test/tests/7.py deleted file mode 100644 index 4f0a88a53..000000000 --- a/test/tests/7.py +++ /dev/null @@ -1,60 +0,0 @@ -def ident(x): - return x -def f0(): - print "f0" - return 0 -def f1(a1): - print "f1", a1 - return 0 -def f2(a1, a2): - print "f2", a1, a2 - return 0 -def f3(a1, a2, a3): - print "f3", a1, a2, a3 - return 0 -def f4(a1, a2, a3, a4): - print "f4", a1, a2, a3, a4 - return 0 -def f5(a1, a2, a3, a4, a5): - print "f5", a1, a2, a3, a4, a5 - return 0 -def f6(a1, a2, a3, a4, a5, a6): - print "f6", a1, a2, a3, a4, a5, a6 - return 0 -def f7(a1, a2, a3, a4, a5, a6, a7): - print "f7", a1, a2, a3, a4, a5, a6, a7 - return 0 -def f8(a1, a2, a3, a4, a5, a6, a7, a8): - print "f8", a1, a2, a3, a4, a5, a6, a7, a8 - return 0 -def f9(a1, a2, a3, a4, a5, a6, a7, a8, a9): - print "f9", a1, a2, a3, a4, a5, a6, a7, a8, a9 - return 0 -def f10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10): - print "f10", a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 - return 0 - - -for i in xrange(5): - f0() - f1(1) - f2(1, 2) - f3(1, 2, 3) - f4(1, 2, 3, 4) - f5(1, 2, 3, 4, 5) - f6(1, 2, 3, 4, 5, 6) - f7(1, 2, 3, 4, 5, 6, 7) - f8(1, 2, 3, 4, 5, 6, 7, 8) - f9(1, 2, 3, 4, 5, 6, 7, 8, 9) - f10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - ident(f0)() - ident(f1)(1) - ident(f2)(1, 2) - ident(f3)(1, 2, 3) - ident(f4)(1, 2, 3, 4) - ident(f5)(1, 2, 3, 4, 5) - ident(f6)(1, 2, 3, 4, 5, 6) - ident(f7)(1, 2, 3, 4, 5, 6, 7) - ident(f8)(1, 2, 3, 4, 5, 6, 7, 8) - ident(f9)(1, 2, 3, 4, 5, 6, 7, 8, 9) - ident(f10)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) diff --git a/test/tests/70.py b/test/tests/70.py deleted file mode 100644 index db36749a5..000000000 --- a/test/tests/70.py +++ /dev/null @@ -1 +0,0 @@ -print type.__call__.__name__ # should print "__call__" (w/o quotes) diff --git a/test/tests/71.py b/test/tests/71.py deleted file mode 100644 index d843f8965..000000000 --- a/test/tests/71.py +++ /dev/null @@ -1,21 +0,0 @@ -# __getattribute__, __getattr__ - -class C1(object): - def __getattr__(self, name): - print "__getattr__", name - return name - -class C2(object): - def __getattribute__(self, name): - print "__getattribute__", name - return name - -c1 = C1() -c1.a = 1 -print c1.a -print c1.b - -c2 = C2() -c2.a = 2 -print c2.a -print c2.b diff --git a/test/tests/72.py b/test/tests/72.py deleted file mode 100644 index 19339c907..000000000 --- a/test/tests/72.py +++ /dev/null @@ -1,12 +0,0 @@ -# objmodel classattrs (like __add__) can be non-functions, so might not get bound into instancemethods: - -class Adder(object): - def __call__(self, *args): - print args - return 2 - -class C(object): - __add__ = Adder() - -c = C() -print c + c diff --git a/test/tests/73.py b/test/tests/73.py deleted file mode 100644 index 947170398..000000000 --- a/test/tests/73.py +++ /dev/null @@ -1,35 +0,0 @@ -# slice slicing - -l = [2, 3, 5, 7] - -# exhaustively try all index pairs: -i = -5 -while i < 6: - print "a", i, l[i:] - print range(i) - print "b", i, l[i::] - print "c", i, l[:i] - print "d", i, l[:i:] - if i != 0: - print "e", i, l[::i] - - j = -5 - while j < 6: - print "f", i, j, l[i:j] - print range(i, j) - print "g", i, j, l[i:j:] - if j != 0: - print "h", i, j, l[i::j] - print "i", i, j, l[:i:j] - - k = -5 - while k < 6: - if k != 0: - print "l", i, j, k, l[i:j:k] - print range(i, j, k) - k = k + 1 - j = j + 1 - i = i + 1 - - -print "hello world"[:5] diff --git a/test/tests/74.py b/test/tests/74.py deleted file mode 100644 index ff218c21f..000000000 --- a/test/tests/74.py +++ /dev/null @@ -1,11 +0,0 @@ -# Slice attributes should be visible - -class C(object): - def __getitem__(self, i): - print i.start, i.step, i.stop - # i.start = 1 # this should fail - return i - -c = C() -print c[:] -print c[::-1] diff --git a/test/tests/75.py b/test/tests/75.py deleted file mode 100644 index 9893fe565..000000000 --- a/test/tests/75.py +++ /dev/null @@ -1,5 +0,0 @@ -def f(): - if 0: - str = 0 - print str -f() diff --git a/test/tests/8.py b/test/tests/8.py deleted file mode 100644 index a557e3c19..000000000 --- a/test/tests/8.py +++ /dev/null @@ -1,2 +0,0 @@ -x = True -print x, False diff --git a/test/tests/9.py b/test/tests/9.py deleted file mode 100644 index 545e270ab..000000000 --- a/test/tests/9.py +++ /dev/null @@ -1,14 +0,0 @@ -x = 1 -if x: - y = 1 - print "true" -elif x: - y = 2 - print "true here?" -elif x: - y = 3 - print "ok..." -else: - y = 4 - print "false" -print y diff --git a/test/tests/arith.py b/test/tests/arith.py deleted file mode 100644 index f1961a212..000000000 --- a/test/tests/arith.py +++ /dev/null @@ -1,34 +0,0 @@ -def f(x, y): - print x + y - print x - y - print x * y - print x / y - print x // y - print x % y - print x ** y - print x & y - print x | y - print x ^ y - print x << y - print x >> y - print ~x - -f(1, 2) -f(-1, 2) -f(0, 5) - -print 1.0 % 0.3 -print 2.5 % 2 -print -1.0 % 0.3 -print -2.5 % 2 -print 1.0 % -0.3 -print 2.5 % -2 -print -1.0 % -0.3 -print -2.5 % -2 - -print 1.0 ** 0.3 -print 2.5 ** 2 -print -1.0 ** 0.3 -print -2.5 ** 2 - -f(2.0, 1.0) diff --git a/test/tests/binop_ics.py b/test/tests/binop_ics.py deleted file mode 100644 index 9bb9701e5..000000000 --- a/test/tests/binop_ics.py +++ /dev/null @@ -1,16 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_binop'] <= 10 -# statcheck: stats['slowpath_runtimecall'] <= 10 - -i = 1 -f = 1.0 -for i in xrange(1000): - print 1 + 1 - print 1 + i - print i + 1 - print i + i - print f + i - print i + f - print f + 1 - print 1.0 + 1.0 - diff --git a/test/tests/binop_invalidation.py b/test/tests/binop_invalidation.py deleted file mode 100644 index 4ebfaf4a3..000000000 --- a/test/tests/binop_invalidation.py +++ /dev/null @@ -1,79 +0,0 @@ -# run_args: -n - - -class O(object): - pass -o = O() - -def _add(): - return o.x + o.y -def add(x, y): - o.x = x - o.y = y - return _add() - -print add(0, 1) -print add(0, 2.0) - -print add(0, 3) -print add(1.0, 4) - -print add(0, 5) -print add(1.0, 6.0) - - -class C(object): - def __init__(self, n): - self.n = n - -def add1(self, rhs): - print "add1" - return self.n + rhs.n -def add2(self, rhs): - print "add2" - return -self.n + rhs.n -def add3(self, rhs): - print "add3" - if rhs.n == 6: - return NotImplemented - return self.n + rhs.n - -class D(object): - def __init__(self, n): - self.n = n - def __radd__(self, rhs): - print "radd" - return 1 + self.n + rhs.n - -C.__add__ = add1 -print add(C(1), C(1)) -print add(C(1.0), C(2)) -C.__add__ = add2 -print add(C(1), C(3)) -print add(C(1), D(4)) -C.__add__ = add3 -print add(C(1), D(5)) -print add(C(1), D(6)) # this one, but not the ones above or below, should call radd! -print add(C(1), D(7)) - - - -class V(object): - def __init__(self, x, y, z): - self.x = x - self.y = y - self.z = z - - def dot(self, other): - print self.x, other.x, self.y, other.y, self.z, other.z - return self.x * other.x + self.y * other.y + self.z * other.z - -v0 = V(1, 1, 1) -# Calling this first will establish all the dot() operations as [int,int] -print v0.dot(v0) - -v = V(1, 1.0, 1) -# But here we give it floats, which could mess it up -print v.dot(v0) -print v0.dot(v) -print v.dot(v) diff --git a/test/tests/binops_reverse.py b/test/tests/binops_reverse.py deleted file mode 100644 index 772f5c30e..000000000 --- a/test/tests/binops_reverse.py +++ /dev/null @@ -1,24 +0,0 @@ -class C(object): - def __add__(self, rhs): - print "__add__", rhs - return 1 - def __radd__(self, lhs): - print "__radd__", lhs - return 2 - -class D(object): - def __repr__(self): - return "" - -def f(): - print 1.0 + 1 - print 1 + 1.0 - print D() + C() - print C() + D() - print 1 + C() - print C() + 1 -# Call it twice to test patching -f() -f() - -print 1.0 / 2 diff --git a/test/tests/binops_subclass.py b/test/tests/binops_subclass.py deleted file mode 100644 index ec0b245a0..000000000 --- a/test/tests/binops_subclass.py +++ /dev/null @@ -1,37 +0,0 @@ -class M(type): - def __instancecheck__(self, rhs): - print "M.instancecheck", - return True - def __subclasscheck__(self, rhs): - print "M.subclasscheck", - return True - -class A(object): - __metaclass__ = M - def __add__(self, rhs): - print "A.add()" - def __radd__(self, rhs): - print "A.radd()" - -class B(A): - __metaclass__ = type - def __add__(self, rhs): - print "B.add()" - def __radd__(self, rhs): - print "B.radd()" - -class C(object): - def __add__(self, rhs): - print "C.add()" - def __radd__(self, rhs): - print "C.radd()" - -def add(x, y): - print type(x), type(y), isinstance(y, type(x)), issubclass(type(y), type(x)) - x + y - -add(A(), A()) -add(A(), B()) -add(A(), C()) -add(B(), B()) -add(B(), C()) diff --git a/test/tests/boolops.py b/test/tests/boolops.py deleted file mode 100644 index 03fea54ed..000000000 --- a/test/tests/boolops.py +++ /dev/null @@ -1,34 +0,0 @@ -def f(msg, rtn): - print msg - return rtn - -n = 0 -while n < 64: - i = n & 3 - j = (n >> 2) & 3 - k = (n >> 4) & 3 - - print f('a', i) and f('b', j) - print f('a', i) or f('b', j) - print f('a', i) and f('b', j) and f('c', k) - print f('a', i) and f('b', j) or f('c', k) - print f('a', i) or f('b', j) and f('c', k) - print f('a', i) or f('b', j) or f('c', k) - - n = n + 1 - -class C(object): - def __init__(self, x): - self.x = x - def __nonzero__(self): - print "C.__nonzero__", self.x - return self.x - def __repr__(self): - return "" - -c = C("hello") # This object has an invalid __nonzero__ return type -if 0: - print bool(c) # this will fail -print 1 and c # Note: nonzero isn't called on the second argument! -print C(True) or 1 # prints the object repr, not the nonzero repr -print c and 1 diff --git a/test/tests/break_outside_loop.py b/test/tests/break_outside_loop.py deleted file mode 100644 index bf3fdcd66..000000000 --- a/test/tests/break_outside_loop.py +++ /dev/null @@ -1 +0,0 @@ -break diff --git a/test/tests/builtins.py b/test/tests/builtins.py deleted file mode 100644 index 3a7a28548..000000000 --- a/test/tests/builtins.py +++ /dev/null @@ -1,13 +0,0 @@ -__builtins__.aoeu = 1 -print aoeu - -__builtins__.True = 2 -print True -print bool(1) -print bool(1) is True - -__builtins__.__builtins__ = 1 -print __builtins__ - -__builtins__ = 2 -print __builtins__ diff --git a/test/tests/call_patches.py b/test/tests/call_patches.py deleted file mode 100644 index 542b425f5..000000000 --- a/test/tests/call_patches.py +++ /dev/null @@ -1,20 +0,0 @@ -# run_args: -n -# statcheck: stats.get('slowpath_callattr', 0) <= 20 -# statcheck: stats['slowpath_runtimecall'] <= 20 -# statcheck: stats.get("slowpath_callclfunc", 0) <= 20 -# statcheck: stats['rewriter_nopatch'] <= 20 - -def outer(): - def f(): - return 1 - - t = 0 - for i in xrange(10000): - t = t + f() - print t -outer() - -t = 0 -for i in xrange(1000): - t = t + i -print t diff --git a/test/tests/callattr.py b/test/tests/callattr.py deleted file mode 100644 index 7054eda15..000000000 --- a/test/tests/callattr.py +++ /dev/null @@ -1,27 +0,0 @@ -# run_args: -n -# callattr: c.foo(i) should theoretically create an instancemethod object and then call that, -# but calling an attribute is such a common case that I special case it as a callattr(), -# which avoids the allocation/immediate deallocation of the instancemethod object. -# statcheck: stats.get('num_instancemethods', 0) <= 10 -# statcheck: stats['slowpath_callattr'] <= 20 -class C(object): - def foo(self, a0, a1, a2, a3, a4, a5, a6, a7): - print "foo", a0, a1, a2, a3, a4, a5, a6, a7 - - def baz(self, a0, a1): - print "baz", a0, a1 - -def bar(a0, a1, a2, a3, a4, a5, a6, a7): - print "bar", a0, a1, a2, a3, a4, a5, a6, a7 - -c = C() -c.bar = bar - -for i in xrange(1000): - c.bar(i, 100, i, 1, i, 2, i, 3) - -for i in xrange(1000): - c.baz(i, 100) - -for i in xrange(1000): - c.foo(i, 100, i, 1, i, 2, i, 3) diff --git a/test/tests/callattr_caching.py b/test/tests/callattr_caching.py deleted file mode 100644 index 2c20a9b03..000000000 --- a/test/tests/callattr_caching.py +++ /dev/null @@ -1,18 +0,0 @@ -# run_args: -n - -class C(object): - def foo(self): - print "C.foo()" -class D(object): - def foo(self): - print "D.foo()" - -class EH(object): - def __call__(self): - print "EH()" -class E(object): - pass -E.foo = EH() - -for i in [C(), D(), E(), C()]: - i.foo() diff --git a/test/tests/class_changing.py b/test/tests/class_changing.py deleted file mode 100644 index 61989375c..000000000 --- a/test/tests/class_changing.py +++ /dev/null @@ -1,18 +0,0 @@ -# Tests to make sure that setting __class__ changes the class, and that it's ok to disallow -# having anything other than a type as the class -class C(object): - def foo(self): - print "C.foo()" - -class D(object): - def foo(self): - print "D.foo()" - -c = C() -c.foo() - -c.__class__ = D -c.foo() - -# This should err: -c.__class__ = 1 diff --git a/test/tests/class_clsgetattr_ics.py b/test/tests/class_clsgetattr_ics.py deleted file mode 100644 index bd4da0d9a..000000000 --- a/test/tests/class_clsgetattr_ics.py +++ /dev/null @@ -1,13 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_getattr'] <= 10 - -class C(object): - pass - - -c = C() -c.n = 1 -C.m = 2 - -for i in xrange(1000): - print c.n, c.m diff --git a/test/tests/class_freeing.py b/test/tests/class_freeing.py deleted file mode 100644 index 0b4c548f1..000000000 --- a/test/tests/class_freeing.py +++ /dev/null @@ -1,24 +0,0 @@ -# Have to be careful to incref any classes when instances are created; -# we can skip it for builtin classes, but this is an example of why it's required - -class C(object): - pass - -c = C() -c.n = 10 -C.n2 = 11 - -C = None -# No direct references to c's class (original 'C') anymore! - -# Can still get it with: -print type(c) -print type(c).n2 - -# Some random stuff to try to elicit errors: -l = [] -for i in xrange(10): - l.append(len(l)) -print l - -print type(c).n2 diff --git a/test/tests/class_freeing_time.py b/test/tests/class_freeing_time.py deleted file mode 100644 index 6888e5091..000000000 --- a/test/tests/class_freeing_time.py +++ /dev/null @@ -1,20 +0,0 @@ -# Classes should be freed right away - -class DeallocShower(object): - def __init__(self, n): - self.n = n - def __del__(self): - print "del", self.n - -class C(object): - pass -c = C() -c.d = DeallocShower(1) -C.d2 = DeallocShower(2) -print 1 -C = None -print 2 -c = None -# C can be freed here I believe -print 3 -# But cPython doesn't dealloc it until program termination diff --git a/test/tests/class_getattrsetattr_ics.py b/test/tests/class_getattrsetattr_ics.py deleted file mode 100644 index 69747978e..000000000 --- a/test/tests/class_getattrsetattr_ics.py +++ /dev/null @@ -1,14 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_setattr'] <= 10 -# statcheck: stats['slowpath_getattr'] <= 10 - -class C(object): - pass - - -c = C() -c.x = 0 - -for i in xrange(1000): - c.x = c.x + 1 - print c.x diff --git a/test/tests/class_noctor.py b/test/tests/class_noctor.py deleted file mode 100644 index 942a1a551..000000000 --- a/test/tests/class_noctor.py +++ /dev/null @@ -1,16 +0,0 @@ -# Regression test: -# If the init function doesn't exist, shouldn't just silently ignore any args -# that got passed - -class C(object): - def __new__(cls, args): - return object.__new__(cls) - -c = C(1) -print "This should have worked" - -class D(object): - pass - -d = D(1) -print "This should have failed" diff --git a/test/tests/classdef_arbitrary.py b/test/tests/classdef_arbitrary.py deleted file mode 100644 index 708298a45..000000000 --- a/test/tests/classdef_arbitrary.py +++ /dev/null @@ -1,43 +0,0 @@ -# You can put arbitrary stuff in class definitions, which end up being added as class attributes - -class C(object): - n = 10 - a = 1 - b = 2 - x = 100 - y = 101 - while n > 0: - t = a + b - a = b - b = t - n = n - 1 - - if b == 20: - break - - if b == 13: - x = "hello" - else: - y = "world" - - class S(object): - pass - - [123] - -class D(object): - x = 1 - # Note: this fails in Python 3: - l = [x for y in range(1)] - -def p(o): - print o.a - print o.b - print o.t - print o.n - print o.x - print o.y - print o.S - -p(C) -p(C()) diff --git a/test/tests/classname.py b/test/tests/classname.py deleted file mode 100644 index 31732404a..000000000 --- a/test/tests/classname.py +++ /dev/null @@ -1,12 +0,0 @@ -class C(object): - pass - -print C -C.__name__ = "new_name" -print C -print repr(C.__module__) -C.__module__ = "new_module" -print C - -C.__module__ = 1 -print C diff --git a/test/tests/clsattr_clears_itself.py b/test/tests/clsattr_clears_itself.py deleted file mode 100644 index 82e96c2d7..000000000 --- a/test/tests/clsattr_clears_itself.py +++ /dev/null @@ -1,19 +0,0 @@ -# run_args: -n -# This is a test to make sure that clsattrs get incref'd for the duration of their execution. -# It feels pretty wasteful but theoretically the clsattr could clear itself (or indirectly) -# which would dealloc it while running if it wasn't incref'd. - -# I'm not sure this test would actually crash though, since we're not freeing the code -# memory... - -class C(object): - def f(self): - C.f = None - # random stuff to try to make it crash: - l = [1,2,3] - while l: - l.pop() - -print C.f is None -C().f() -print C.f is None diff --git a/test/tests/comparisons.py b/test/tests/comparisons.py deleted file mode 100644 index 8010895a0..000000000 --- a/test/tests/comparisons.py +++ /dev/null @@ -1,71 +0,0 @@ -def f(a, b): - print a, b, "<", a < b - print a, b, "<=", a <= b - print a, b, ">", a > b - print a, b, ">=", a >= b - print a, b, "==", a == b - print a, b, "!=", a != b - print a, b, "is", a is b - print a, b, "is not", a is not b - -class C(object): - pass - -class Z(object): - pass - -args = [0, 1, 0.1, 1.1, "hello", float('nan'), float('inf'), float('-inf')]#, C(), Z()] - -for i in xrange(len(args)): - for j in xrange(i): - f(args[i], args[j]) - -def sort(l): - n = len(l) - for i in xrange(n): - for j in xrange(i): - if l[j] > l[i]: - l[j], l[i] = l[i], l[j] - return l - -sortable_args = [0, 1, 0.1, 1.1, "hello", float('inf'), float('-inf')]#, C(), Z()] -print sort(sortable_args) - -# Nevermind, the ordering isn't defined (only defined to be consistent), and I don't feel like matching it -# # Ordering across types: -# class C(object): - # pass -# l = [1, 2.0, "hello", [], (), {}, C, int, C(), repr] -# sort(l) -# print l - -class C(object): - def __init__(self, n): - self.n = n - def __repr__(self): - return "<>" - def __lt__(self, rhs): - print "lt" - return self.n - def __le__(self, rhs): - print "le" - return False - def __eq__(self, rhs): - print "eq" - return False - def __gt__(self, rhs): - print "gt" - return self.n - def __ge__(self, rhs): - print "ge" - return False - -for i in xrange(2): - print C("") > 2 - print i < 2 - print min(C("hello"), 2) - print min(C(""), 2) - print max(C("ello"), 2) - print max(C(""), 2) - print C("hi") > 1 - print C("") > 1 diff --git a/test/tests/comparisons_more.py b/test/tests/comparisons_more.py deleted file mode 100644 index e46b971ed..000000000 --- a/test/tests/comparisons_more.py +++ /dev/null @@ -1,3 +0,0 @@ -print (1, 2) < (1, 3) -print [1, 2] < [1, 3] -print {1:2} < {1:3} diff --git a/test/tests/continue_outside_loop.py b/test/tests/continue_outside_loop.py deleted file mode 100644 index 44c5d7d65..000000000 --- a/test/tests/continue_outside_loop.py +++ /dev/null @@ -1 +0,0 @@ -continue diff --git a/test/tests/ctor_ics.py b/test/tests/ctor_ics.py deleted file mode 100644 index a19775818..000000000 --- a/test/tests/ctor_ics.py +++ /dev/null @@ -1,42 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_runtimecall'] < 40 -# statcheck: stats['slowpath_typecall'] < 30 -def f(): - class B(object): - def __init__(self): - pass - - for i in xrange(10000): - b = B() - - class C(object): - pass - - for i in xrange(10000): - c = C() - - class D(object): - def __init__(self, a, b, c, d, e): - pass - - class E(object): - def __init__(self, a, b, c): - pass - - for i in xrange(10000): - e = E(i, i, i) - d = D(i, i, i, i, i) - - - - # Can't define a custom new yet, since can't call object.__new__ - # class F(object): - # def __new__(self, a, b, c): - # pass - - for i in xrange(1000): - # F(1, 2, 3) - - # Use this instead: - xrange(1, 2, 3) -f() diff --git a/test/tests/dict.py b/test/tests/dict.py deleted file mode 100644 index 07c4e4503..000000000 --- a/test/tests/dict.py +++ /dev/null @@ -1,11 +0,0 @@ -d = {2:2} -d[1] = 1 -print d -print d[1] - -d = {} -for i in xrange(10): - d[i] = i ** 2 -print sorted(d.items()) -print sorted(d.values()) -print sorted(d.keys()) diff --git a/test/tests/dict_internals.py b/test/tests/dict_internals.py deleted file mode 100644 index c2a4cba26..000000000 --- a/test/tests/dict_internals.py +++ /dev/null @@ -1,30 +0,0 @@ -class C(object): - def __init__(self, n): - self.n = n - - def __hash__(self): - print "__hash__" - return self.n % 2 - - def __eq__(self, rhs): - print "__eq__", self.n + rhs.n - return self.n % 2 == rhs.n % 2 - - def __repr__(self): - return "C(" + str(self.n) + ")" - -d = {} -c1 = C(1) -c2 = C(2) -c3 = C(3) -d.__setitem__(c1, 1) -d.__setitem__(c2, 2) - - -# This will cause a dict colision. -# I'm not sure this is specified, but I happen to handle it the same way cPython does, -# which is to update the value but not the key, so the result should be that -# there is an entry from C(1) to 3 -d.__setitem__(c3, 3) - -print d diff --git a/test/tests/extension.expected b/test/tests/extension.expected deleted file mode 100644 index e66b5e8a7..000000000 --- a/test/tests/extension.expected +++ /dev/null @@ -1,4 +0,0 @@ - -[] -This will break -[] diff --git a/test/tests/extension.py b/test/tests/extension.py deleted file mode 100644 index b4294b5da..000000000 --- a/test/tests/extension.py +++ /dev/null @@ -1,15 +0,0 @@ -import test - -print test -test.store([]) -print test.load() - -class C(object): - def __init__(self): - self.x = self.y = self.z = self.w = self.k = self.a = self.b = self.c = 1 - -for i in xrange(1000000): - C() - -print "This will break" -print test.load() diff --git a/test/tests/fannkuch_small.py b/test/tests/fannkuch_small.py deleted file mode 100644 index 7dd2485d9..000000000 --- a/test/tests/fannkuch_small.py +++ /dev/null @@ -1,49 +0,0 @@ -import time - -def fannkuch(n): - count = range(1, n+1) - max_flips = 0 - m = n-1 - r = n - check = 0 - perm1 = range(n) - perm = range(n) - perm1_ins = perm1.insert - perm1_pop = perm1.pop - - while 1: - if check < 30: - #print "".join(str(i+1) for i in perm1) - check = check + 1 - - while r != 1: - count[r-1] = r - r = r - 1 - - if perm1[0] != 0 and perm1[m] != m: - perm = perm1[:] - flips_count = 0 - k = perm[0] - while k: - perm[:k+1] = perm[k::-1] - flips_count = flips_count + 1 - k = perm[0] - - if flips_count > max_flips: - max_flips = flips_count - - while r != n: - perm1_ins(r, perm1_pop(0)) - count[r] = count[r] - 1 - if count[r] > 0: - break - r = r + 1 - else: - return max_flips - -DEFAULT_ARG = 9 - -def main(n): - for i in range(2, n): - print fannkuch(i) -main(8) diff --git a/test/tests/fib_small.py b/test/tests/fib_small.py deleted file mode 100644 index b106d5847..000000000 --- a/test/tests/fib_small.py +++ /dev/null @@ -1,7 +0,0 @@ -def fib(n): - if n <= 2: - return n - return fib(n - 1) + fib(n - 2) - -print fib(20) - diff --git a/test/tests/file.py b/test/tests/file.py deleted file mode 100644 index 6b60b41f7..000000000 --- a/test/tests/file.py +++ /dev/null @@ -1,8 +0,0 @@ -f = open("/dev/null") -print repr(f.read()) - -f2 = file("/dev/null") -print repr(f2.read()) - -with open("/dev/null") as f3: - print repr(f3.read()) diff --git a/test/tests/finalization_cycles.py b/test/tests/finalization_cycles.py deleted file mode 100644 index 0574320f0..000000000 --- a/test/tests/finalization_cycles.py +++ /dev/null @@ -1,21 +0,0 @@ -# Finalizers should be called before any objects are deallocated -# Note: the behavior here will differ from cPython and maybe PyPy - -finalizers_run = [] -class C(object): - def __init__(self, n): - self.n = n - self.x = None - - def __del__(self): - finalizers_run.append((self.n, self.x.n if self.x else None)) - -def f(): - x1 = C(1) - x2 = C(2) - x1.x = x2 - x2.x = x1 -f() - -finalizers_run.sort() -print finalizers_run diff --git a/test/tests/float.py b/test/tests/float.py deleted file mode 100644 index bcdaba1f0..000000000 --- a/test/tests/float.py +++ /dev/null @@ -1,5 +0,0 @@ -print 123542598.12938712938192831293812983 -f = 1.0 -print f - -# print f - 2 diff --git a/test/tests/float_locals.py b/test/tests/float_locals.py deleted file mode 100644 index da42e57a3..000000000 --- a/test/tests/float_locals.py +++ /dev/null @@ -1,30 +0,0 @@ -# Test having some float locals, which live in XMM registers, to exercise -# code paths that handle those. - -class C(object): - pass -C.x = 2.0 -c = C() -c.x = 1.0 - -def getattr_test(c, n): - t = 0.0 - for i in xrange(n): - c.x - t = t + 1.0 - return t - -def setattr_test(c, n): - t = 0.0 - for i in xrange(n): - c.x = t - t = t + 1.0 - return t - -print getattr_test(c, 1000000) -print setattr_test(c, 1000000) - -# Calling this with an empty C -# will cause the getattr to hit the class-level x attribute: -print getattr_test(C(), 1000000) - diff --git a/test/tests/float_osr.py b/test/tests/float_osr.py deleted file mode 100644 index 87dcee15e..000000000 --- a/test/tests/float_osr.py +++ /dev/null @@ -1,15 +0,0 @@ -# Floats are separately difficult to OSR due to the fact that they use different registers -# and aren't directly bitcast-able to pointers: - -def f(): - a = 1.0 - b = 2.0 - c = 3.0 - d = 4.0 - e = 5.0 - f = 6.0 - - for i in xrange(20000): - a = b * c + a - print a, b, c, d, e, f -f() diff --git a/test/tests/float_precision.py b/test/tests/float_precision.py deleted file mode 100644 index 8a4efc00e..000000000 --- a/test/tests/float_precision.py +++ /dev/null @@ -1,33 +0,0 @@ -def smallest(): - x = 1.0 - n = 1.0 - while x + n != x: - n = n * 0.99 - return n - -for i in xrange(1000): - print smallest() - -def test(): - BIG = 2.0 ** 53 - t = BIG ** 1.0 - x = 1.0 - - n = 10000 - while n: - t = t + x - n = n - 1 - return t - BIG - -for i in xrange(1000): - print test() - -def divtest(x): - return (1.0 / x) * x - 1 - -f = 1.0 -while True: - print divtest(f) - f = f * 0.999 - if f < 1e-1: - break diff --git a/test/tests/for.py b/test/tests/for.py deleted file mode 100644 index abace038f..000000000 --- a/test/tests/for.py +++ /dev/null @@ -1,36 +0,0 @@ -for i in range(10): - print i -for i in xrange(1, 15, 2): - print i - -l = [2, 3, 5, 7] -d = {} -for i in l: - d[i-1] = i+1 -for t in sorted(d.iteritems()): - print t - -for i in xrange(-5, 5): - for j in xrange(i): - print i, j - else: - print "else" - -for i in xrange(-10, 10): - if i % 3 == 0: - continue - print i - if i == 3: - break -else: - print "else" - -for i in xrange(5): - print i - continue -else: - print "else", i - -for i in xrange(5): - print i - break diff --git a/test/tests/for_iter.py b/test/tests/for_iter.py deleted file mode 100644 index 00d587c21..000000000 --- a/test/tests/for_iter.py +++ /dev/null @@ -1,35 +0,0 @@ -class C(object): - def __iter__(self): - print "orig iter" - return [1,2,3].__iter__() - - def next(self): - print "next?" - -def newiter(): - print "new iter" - return [9,8,7].__iter__() - -# This shouldn't matter: -iter = None - -# this should hit the original iter function: -for i in C(): - print i - -class C(object): - def __iter__(self): - return self - - def next(self): - print "next" - raise StopIteration() - -def newnext(): - print "newnext" - raise StopIteration() -c = C() -c.next = newnext - -for i in c: # should hit the old next - print i diff --git a/test/tests/func_caching.py b/test/tests/func_caching.py deleted file mode 100644 index 38eba23b6..000000000 --- a/test/tests/func_caching.py +++ /dev/null @@ -1,10 +0,0 @@ -# run_args: -n -def foo(): - print "foo" - -def bar(): - print "bar" - -l = [foo, foo, bar, bar] -for i in l: - i() diff --git a/test/tests/getattr.py b/test/tests/getattr.py deleted file mode 100644 index f16710e71..000000000 --- a/test/tests/getattr.py +++ /dev/null @@ -1,5 +0,0 @@ -l = range(5) -print getattr(l, "pop")() - -print getattr([], "a", "default") -print getattr([], "a") diff --git a/test/tests/getattr_ics.py b/test/tests/getattr_ics.py deleted file mode 100644 index b86db294d..000000000 --- a/test/tests/getattr_ics.py +++ /dev/null @@ -1,12 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_getattr'] <= 10 - -class C(object): - def f(self): - print self.n - -c = C() -c.n = 1 - -for i in xrange(100): - c.f() diff --git a/test/tests/getattr_nonstring.py b/test/tests/getattr_nonstring.py deleted file mode 100644 index 3132a17ea..000000000 --- a/test/tests/getattr_nonstring.py +++ /dev/null @@ -1 +0,0 @@ -print getattr([], []) diff --git a/test/tests/getitem.py b/test/tests/getitem.py deleted file mode 100644 index 978f578a0..000000000 --- a/test/tests/getitem.py +++ /dev/null @@ -1,24 +0,0 @@ -# getitem - -def f(l): - n = 0 - while n < len(l): - print l[n] - n = n + 1 - -f([2, 3, 5, 7]) -f("hello world") - -class C(object): - def __getitem__(self, sl): - print "orig getitem" - return sl - -def gi(sl): - print "new getitem" - return -1 -c = C() -c.__getitem__ = gi -print c[1] - -print 1[1] diff --git a/test/tests/global_and_local.py b/test/tests/global_and_local.py deleted file mode 100644 index 6ebf055c9..000000000 --- a/test/tests/global_and_local.py +++ /dev/null @@ -1,11 +0,0 @@ -# I would have expected this to be valid, but cPython and pypy err out saying "name 'x' is local and global" -# Interestingly, this SyntaxError gets thrown *after* AST creation, which I guess makes sense but I wasn't -# expecting - -x = 1 -def f(x): - global x - -print "calling" -f(2) -print x diff --git a/test/tests/global_directive.py b/test/tests/global_directive.py deleted file mode 100644 index d5423f326..000000000 --- a/test/tests/global_directive.py +++ /dev/null @@ -1,19 +0,0 @@ -def f(): - global x # executed, simple case - if 0: - global z # never executed, doesn't matter - x = 2 - y = 2 - z = 2 - w = 2 - print x, y, z, w - - # This generates a syntax warning: - global w # executed after, still counts - -x = 1 -y = 1 -z = 1 -w = 1 -f() -print x, y, z, w diff --git a/test/tests/global_ics.py b/test/tests/global_ics.py deleted file mode 100644 index d46168832..000000000 --- a/test/tests/global_ics.py +++ /dev/null @@ -1,12 +0,0 @@ -# run_args: -n -# statcheck: stats["slowpath_getglobal"] <= 10 - -def f(): - print True - -True = True - -n = 1000 -while n: - f() - n = n - 1 diff --git a/test/tests/globals.py b/test/tests/globals.py deleted file mode 100644 index 788652334..000000000 --- a/test/tests/globals.py +++ /dev/null @@ -1,12 +0,0 @@ -def f(): - z = 1 - print x # non-builtin, but defined - print True # builtin, redefined - print False # builtin, not redefined - print z # local - print y # non-builtin, not defined - -x = 2 -z = 2 -True = "new_true" -f() diff --git a/test/tests/hash.py b/test/tests/hash.py deleted file mode 100644 index dc2084480..000000000 --- a/test/tests/hash.py +++ /dev/null @@ -1,8 +0,0 @@ -# hash - -print hash -print hash(1) - -i = hash("hello world") -j = hash("hello" + " world") -print i == j diff --git a/test/tests/icgetattr_invalid.py b/test/tests/icgetattr_invalid.py deleted file mode 100644 index 9e215fa84..000000000 --- a/test/tests/icgetattr_invalid.py +++ /dev/null @@ -1,53 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_getattr'] <= 10 -# Different ways that getattrs can be invalidated - -class C(object): - pass - -def f(o): - print o.n - -c = C() -c.n = 1 -f(c) - -def ga(o, attr): - print "in ga()" - return 2 -# Setting __getattribute__ invalidates all ics: -C.__getattribute__ = ga -f(c) - - -# Here we get a class attr, which should also be cached, -# but there are a few more ways that it can be invalidated. -# Also, test setting non-functions -class C(object): - def f(self): - print "f()" -class Callable(object): - def __init__(self, n): - self.n = n - def __call__(self): - print "Callable", self.n - -def new_f(self): - print "new_f" - -c = C() -for i in xrange(1000): - print i - c.f() - if i == 100: - C.f = Callable(i) - if i == 150: - C.z0 = 1 - if i == 200: - C.f = new_f - if i == 250: - C.z1 = 2 - if i == 300: - c.f = Callable(i) - if i == 350: - C.z2 = 3 diff --git a/test/tests/im_caching.py b/test/tests/im_caching.py deleted file mode 100644 index 99482ffb7..000000000 --- a/test/tests/im_caching.py +++ /dev/null @@ -1,35 +0,0 @@ -# run_args: -n -# Tests to make sure that we guard on enough things for instance methods: - -class C(object): - def foo(self): - print "C.foo()" - def bar(self): - print "C.bar()" - def baz(self, a, b, c, d, e, f, g, h, i): - print "C.baz()" - def faz(self, a, b, c, d, e, f, g, h, i): - print "C.faz()" -class D(object): - def foo(self): - print "D.foo()" - def bar(self): - print "D.bar()" - def baz(self, a, b, c, d, e, f, g, h, i): - print "D.baz()" - def faz(self, a, b, c, d, e, f, g, h, i): - print "D.faz()" - -c = C() -d = D() -l = [c.foo, c.bar, d.foo, d.bar, - c.foo, d.foo, c.bar, d.bar] - -for i in l: - i() - -l = [c.faz, c.baz, d.faz, d.baz, - c.faz, d.faz, c.baz, d.baz] -for i in l: - i(1, 2, 3, 4, 5, 6, 7, 8, 9) - diff --git a/test/tests/im_ics.py b/test/tests/im_ics.py deleted file mode 100644 index 8a5a05b76..000000000 --- a/test/tests/im_ics.py +++ /dev/null @@ -1,10 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_runtimecall'] < 10 - -class C(object): - def foo(self, a, b, c, d, e): - print a, b, c, d, e - -c = C() -for i in xrange(1000): - c.foo(1, i, 3, i, 5) diff --git a/test/tests/init_must_return_none.py b/test/tests/init_must_return_none.py deleted file mode 100644 index 42c18523c..000000000 --- a/test/tests/init_must_return_none.py +++ /dev/null @@ -1,14 +0,0 @@ -# As the test filename says, init functions must return None. -# This file tests that; it also makes sure that it gets tested -# when in a patchpoint. - -class C(object): - def __init__(self, n): - self.n = n - if n == 500: - return n - -# Call it in a loop to make sure that the constructor gets inlined: -for i in xrange(1000): - c = C(i) - print c.n diff --git a/test/tests/instance_callable.py b/test/tests/instance_callable.py deleted file mode 100644 index 09504f780..000000000 --- a/test/tests/instance_callable.py +++ /dev/null @@ -1,10 +0,0 @@ -class C(object): - def __init__(self, f): - self.f = f - -def foo(n): - print "foo", n - -c = C(foo) -for i in xrange(100): - c.f(i) diff --git a/test/tests/int_ics.py b/test/tests/int_ics.py deleted file mode 100644 index 9b581e736..000000000 --- a/test/tests/int_ics.py +++ /dev/null @@ -1,5 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_runtimecall'] < 10 - -for i in xrange(1000): - print int(i * 1.1) diff --git a/test/tests/interp2_small.py b/test/tests/interp2_small.py deleted file mode 100644 index 57d1430cd..000000000 --- a/test/tests/interp2_small.py +++ /dev/null @@ -1,139 +0,0 @@ -class Random(object): - def __init__(self, seed): - self.cur = seed - - def next(self): - self.cur = (self.cur * 1103515245 + 12345) % (1 << 31) - return self.cur - -class AstAssign(object): - def __init__(self, name, expr): - self.name = name - self.expr = expr - -class AstWhile(object): - def __init__(self, test, body): - self.test = test - self.body = body - -class AstBinop(object): - def __init__(self, lhs, rhs, op): - self.lhs = lhs - self.rhs = rhs - self.op = op - -class AstPrint(object): - def __init__(self, expr): - self.expr = expr - -class AstIf(object): - def __init__(self, test, then, orelse): - self.test = test - self.then = then - self.orelse = orelse - -class State(object): - def __init__(self): - self.syms = {} - -def visit(visitor, node): - if isinstance(node, list): - for s in node: - visit(visitor, s) - return None - - type_name = type(node).__name__.lower() - return getattr(visitor, "visit_" + type_name)(node) - -class InterpVisitor(object): - def __init__(self): - self.syms = {} - - def visit(self, node): - return visit(self, node) - - def visit_astassign(self, node): - v = self.visit(node.expr) - self.syms[node.name] = v - - def visit_int(self, node): - return node - - def visit_str(self, node): - return self.syms[node] - - def visit_astwhile(self, node): - while True: - v = self.visit(node.test) - if not v: - break - self.visit(node.body) - - def visit_astbinop(self, node): - l = self.visit(node.lhs) - r = self.visit(node.rhs) - if node.op == '+': - return l + r - if node.op == '-': - return l - r - if node.op == '*': - return l * r - if node.op == '%': - return l % r - if node.op == "<": - return l < r - if node.op == "<=": - return l <= r - if node.op == "==": - return l == r - print node.op - 1/0 - - def visit_astif(self, node): - v = self.visit(node.test) - if v: - self.visit(node.then) - else: - self.visit(node.orelse) - - def visit_astprint(self, node): - v = self.visit(node.expr) - print v - -def run(node): - visit(InterpVisitor(), node) - -prog = [ - AstAssign("x", 1000), - AstAssign("t", 0), - AstWhile("x", [ - AstAssign("t", AstBinop("t", "x", '+')), - AstAssign("x", AstBinop("x", 1, '-')), - ]), - AstPrint("t"), - ] -run(prog) - -prog = [ - AstAssign("i", 2), - AstAssign("t", 0), - AstWhile(AstBinop("i", 100, '<'), [ - AstAssign("j", 2), - AstAssign("good", 1), - AstWhile(AstBinop(AstBinop("j", "j", '*'), "i", "<="), [ - AstIf(AstBinop(AstBinop("i", "j", "%"), 0, "=="), [ - AstAssign("good", 0), - ], [ - ]), - AstAssign("j", AstBinop("j", 1, "+")), - ]), - AstIf("good", [ - AstPrint("i"), - AstAssign("t", AstBinop("t", "i", "+")), - ], []), - AstAssign("i", AstBinop("i", 1, "+")), - ]), - AstPrint("t"), - ] - -run(prog) diff --git a/test/tests/is.py b/test/tests/is.py deleted file mode 100644 index b949ca8cb..000000000 --- a/test/tests/is.py +++ /dev/null @@ -1,9 +0,0 @@ -class C(object): - pass - -c = C() -print c is c -print c is C - -print range is True -print c is None diff --git a/test/tests/list.py b/test/tests/list.py deleted file mode 100644 index e2ba5c301..000000000 --- a/test/tests/list.py +++ /dev/null @@ -1,28 +0,0 @@ -l = range(5) -print l -print l * 5 -l[0] = 1 -print l -print l[2] - -l = range(5) -while l: - print l.pop() - -l = range(7, -1, -2) -print sorted(l) -print l - -for i in xrange(-10, 10): - l2 = range(5) - l2.insert(i, 99) - print i, l2 - -for i in xrange(-5, 4): - l3 = range(5) - print i, l3.pop(i), l3 - -for i in xrange(-5, 4): - l3 = range(5) - l3[:i] = [7, 8] - print l3 diff --git a/test/tests/list_unpacking.py b/test/tests/list_unpacking.py deleted file mode 100644 index 0a229b247..000000000 --- a/test/tests/list_unpacking.py +++ /dev/null @@ -1,7 +0,0 @@ -# regression test: - -def f(): - l = [13,17] - i, j = l - print i, j -f() diff --git a/test/tests/longargs_stackusage.py b/test/tests/longargs_stackusage.py deleted file mode 100644 index 564244d5d..000000000 --- a/test/tests/longargs_stackusage.py +++ /dev/null @@ -1,31 +0,0 @@ -# This is a test to make sure that the stack space we allocate -# for "long arg" calls (ie calls that take more than 4 arguments) -# gets restored. - -def f6(a1, a2, a3, a4, a5, a6, l1, l2, l3, l4, l5, l6, x1, x2, x3, x4, x5, x6): - return 1 - -def f(): - a = 1 - b = 2 - c = 3 - d = 4 - e = 5 - - n = 100000000 - t = 0 - - l1 = [] - l2 = [] - l3 = [] - l4 = [] - l5 = [] - l6 = [] - while n: - t = t + f6(l1, l2, l3, l4, l5, l6, l1, l2, l3, l4, l5, l6, l1, l2, l3, l4, l5, l6) - n = n - 1 - if n % 10000 == 0: - print n - - print a, b, c, d, e -f() diff --git a/test/tests/loops.py b/test/tests/loops.py deleted file mode 100644 index a8355816f..000000000 --- a/test/tests/loops.py +++ /dev/null @@ -1,7 +0,0 @@ -def f(): - for i in xrange(5): - for j in xrange(5): - print i, j - break - break -f() diff --git a/test/tests/many_attrs.py b/test/tests/many_attrs.py deleted file mode 100644 index debf223b3..000000000 --- a/test/tests/many_attrs.py +++ /dev/null @@ -1,111 +0,0 @@ -class C(object): - pass - -c = C() -c.a0 = 0 -c.a1 = 1 -c.a2 = 2 -c.a3 = 3 -c.a4 = 4 -c.a5 = 5 -c.a6 = 6 -c.a7 = 7 -c.a8 = 8 -c.a9 = 9 -c.a10 = 10 -c.a11 = 11 -c.a12 = 12 -c.a13 = 13 -c.a14 = 14 -c.a15 = 15 -c.a16 = 16 -c.a17 = 17 -c.a18 = 18 -c.a19 = 19 -c.a20 = 20 -c.a21 = 21 -c.a22 = 22 -c.a23 = 23 -c.a24 = 24 -c.a25 = 25 -c.a26 = 26 -c.a27 = 27 -c.a28 = 28 -c.a29 = 29 -c.a30 = 30 -c.a31 = 31 -c.a32 = 32 -c.a33 = 33 -c.a34 = 34 -c.a35 = 35 -c.a36 = 36 -c.a37 = 37 -c.a38 = 38 -c.a39 = 39 -c.a40 = 40 -c.a41 = 41 -c.a42 = 42 -c.a43 = 43 -c.a44 = 44 -c.a45 = 45 -c.a46 = 46 -c.a47 = 47 -c.a48 = 48 -c.a49 = 49 - -def f(o): - print o.a0 - print o.a1 - print o.a2 - print o.a3 - print o.a4 - print o.a5 - print o.a6 - print o.a7 - print o.a8 - print o.a9 - print o.a10 - print o.a11 - print o.a12 - print o.a13 - print o.a14 - print o.a15 - print o.a16 - print o.a17 - print o.a18 - print o.a19 - print o.a20 - print o.a21 - print o.a22 - print o.a23 - print o.a24 - print o.a25 - print o.a26 - print o.a27 - print o.a28 - print o.a29 - print o.a30 - print o.a31 - print o.a32 - print o.a33 - print o.a34 - print o.a35 - print o.a36 - print o.a37 - print o.a38 - print o.a39 - print o.a40 - print o.a41 - print o.a42 - print o.a43 - print o.a44 - print o.a45 - print o.a46 - print o.a47 - print o.a48 - print o.a49 - -f(c) -f(c) -f(c) -f(c) diff --git a/test/tests/many_attrs_setattr.py b/test/tests/many_attrs_setattr.py deleted file mode 100644 index b4077b453..000000000 --- a/test/tests/many_attrs_setattr.py +++ /dev/null @@ -1,20 +0,0 @@ -class C(object): - pass - -c = C() - -n = 0 -while n < 100000: - setattr(c, "a" + str(n), n) - n = n + 1 - -def f(o): - print o.a1 - print o.a10 - print o.a100 - print o.a1000 - print o.a10000 - print o.a99999 - -f(c) -f(c) diff --git a/test/tests/math_more.py b/test/tests/math_more.py deleted file mode 100644 index 6ea316e38..000000000 --- a/test/tests/math_more.py +++ /dev/null @@ -1,5 +0,0 @@ - -print max(range(5)) -print min(range(5)) - -print math.sqrt(-1) diff --git a/test/tests/math_test.py b/test/tests/math_test.py deleted file mode 100644 index db16ef0b1..000000000 --- a/test/tests/math_test.py +++ /dev/null @@ -1,15 +0,0 @@ -import math -print math.sqrt(2) -print math.sqrt(0) - -print math.pi -print math.tan(math.pi) - -print abs(1.0) -print abs(1) -print abs(-1) -print abs(-1.0) - -print max(1, 2) -print min(1, 2) - diff --git a/test/tests/metaclass_parent.py b/test/tests/metaclass_parent.py deleted file mode 100644 index 47f56b6dc..000000000 --- a/test/tests/metaclass_parent.py +++ /dev/null @@ -1,10 +0,0 @@ -# This would make a good Python quiz: - -sl = slice(1,2) -class C(sl): - pass - -print C - -print C.start, C.stop, C.step -print type(C) diff --git a/test/tests/mod.py b/test/tests/mod.py deleted file mode 100644 index d5d50ee07..000000000 --- a/test/tests/mod.py +++ /dev/null @@ -1,11 +0,0 @@ -print 1.3 % 0.4 -print -1.3 % 0.4 -print 1.3 % -0.4 -print -1.3 % -0.4 - -l = [2, 3, 1.0, 2.0, 0.3, 1.6] -for i in list(l): - l.append(-i) -for i in l: - for j in l: - print i, j, i % j diff --git a/test/tests/nbody_small.py b/test/tests/nbody_small.py deleted file mode 100644 index f7a58d3f6..000000000 --- a/test/tests/nbody_small.py +++ /dev/null @@ -1,132 +0,0 @@ -# -*- coding: utf-8 -*- -# The Computer Language Benchmarks Game -# http://shootout.alioth.debian.org/ -# -# contributed by Kevin Carson -# modified by Tupteq, Fredrik Johansson, and Daniel Nanz - -import time - -def combinations(l): - result = [] - for x in xrange(len(l) - 1): - for j in xrange(x+1, len(l)): - # ls = l[x+1:] - # for y in ls: - y = l[j] - result.append((l[x],y)) - return result - -PI = 3.14159265358979323 -SOLAR_MASS = 4 * PI * PI -DAYS_PER_YEAR = 365.24 - -BODIES = { -1: ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), - -2: ([4.84143144246472090e+00, - -1.16032004402742839e+00, - -1.03622044471123109e-01], - [1.66007664274403694e-03 * DAYS_PER_YEAR, - 7.69901118419740425e-03 * DAYS_PER_YEAR, - -6.90460016972063023e-05 * DAYS_PER_YEAR], - 9.54791938424326609e-04 * SOLAR_MASS), - -3: ([8.34336671824457987e+00, - 4.12479856412430479e+00, - -4.03523417114321381e-01], - [-2.76742510726862411e-03 * DAYS_PER_YEAR, - 4.99852801234917238e-03 * DAYS_PER_YEAR, - 2.30417297573763929e-05 * DAYS_PER_YEAR], - 2.85885980666130812e-04 * SOLAR_MASS), - -4: ([1.28943695621391310e+01, - -1.51111514016986312e+01, - -2.23307578892655734e-01], - [2.96460137564761618e-03 * DAYS_PER_YEAR, - 2.37847173959480950e-03 * DAYS_PER_YEAR, - -2.96589568540237556e-05 * DAYS_PER_YEAR], - 4.36624404335156298e-05 * SOLAR_MASS), - -5: ([1.53796971148509165e+01, - -2.59193146099879641e+01, - 1.79258772950371181e-01], - [2.68067772490389322e-03 * DAYS_PER_YEAR, - 1.62824170038242295e-03 * DAYS_PER_YEAR, - -9.51592254519715870e-05 * DAYS_PER_YEAR], - 5.15138902046611451e-05 * SOLAR_MASS) } - - -SYSTEM = list(sorted(BODIES.values())) -PAIRS = combinations(SYSTEM) - - -def advance(dt, n): - bodies=SYSTEM - pairs=PAIRS - - for i in xrange(n): - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) - b1m = m1 * mag - b2m = m2 * mag - v1[0] = v1[0] - dx * b2m - v1[1] = v1[1] - dy * b2m - v1[2] = v1[2] - dz * b2m - v2[0] = v2[0] + dx * b1m - v2[1] = v2[1] + dy * b1m - v2[2] = v2[2] + dz * b1m - for (r, (vx, vy, vz), m) in bodies: - r[0] = r[0] + dt * vx - r[1] = r[1] + dt * vy - r[2] = r[2] + dt * vz - - -def report_energy(): - bodies=SYSTEM - pairs=PAIRS - e=0.0 - for (((x1, y1, z1), v1, m1), - ((x2, y2, z2), v2, m2)) in pairs: - dx = x1 - x2 - dy = y1 - y2 - dz = z1 - z2 - e = e - (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) - for (r, (vx, vy, vz), m) in bodies: - e = e + m * (vx * vx + vy * vy + vz * vz) / 2. - return e - -def offset_momentum(ref, bodies, px, py, pz): - - for (r, (vx, vy, vz), m) in bodies: - px = px - vx * m - py = py - vy * m - pz = pz - vz * m - (r, v, m) = ref - v[0] = px / m - v[1] = py / m - v[2] = pz / m - -NUMBER_OF_ITERATIONS = 1000 - -def main(n, ref): - # XXX warmup - - times = [] - for i in range(n): - t0 = time.time() - offset_momentum(BODIES[ref], SYSTEM, 0.0, 0.0, 0.0) - e1 = report_energy() - advance(0.01, NUMBER_OF_ITERATIONS) - print e1 - report_energy() - tk = time.time() - times.append(tk - t0) - return times - -main(10,2) - - diff --git a/test/tests/non_function_ctors.py b/test/tests/non_function_ctors.py deleted file mode 100644 index 7df6ddfb2..000000000 --- a/test/tests/non_function_ctors.py +++ /dev/null @@ -1,17 +0,0 @@ -class CallableNew(object): - def __call__(self, cls, arg): - print "new", cls, arg - return object.__new__(cls) -class CallableInit(object): - def __call__(self, arg): - print "init", arg -class C(object): - def __getattribute__(self, name): - # This shouldn't get called - print "__getattribute__", name - -C.__new__ = CallableNew() -C.__init__ = CallableInit() - -c = C(1) -print c diff --git a/test/tests/nondirectly_callable_ics.py b/test/tests/nondirectly_callable_ics.py deleted file mode 100644 index 81a418b82..000000000 --- a/test/tests/nondirectly_callable_ics.py +++ /dev/null @@ -1,20 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_runtimecall'] < 10 - -class Callable(object): - def __init__(self): - self.n = 1 - def __call__(self, a, b, c, d, e): - print self.n, a, b, c, d, e - -c = Callable() -for i in xrange(1000): - c(1, 2, i, 3, 4) - -class D(object): - pass -D.__call__ = c - -d = D() -for i in xrange(1000): - d(1, 2, i, 3, 4) diff --git a/test/tests/none_not_settable.py b/test/tests/none_not_settable.py deleted file mode 100644 index 9546289aa..000000000 --- a/test/tests/none_not_settable.py +++ /dev/null @@ -1,21 +0,0 @@ -class C(object): - def print_none(self): - print None -c = C() -c.print_none() -# Can't do this: -# c.None = 1 -setattr(C, "None", 1) -print dir(C) -print C.None # prints None! -c.print_none() # prints None! - -import sys -m = sys.modules["__main__"] -setattr(m, "None", 1) -print None # prints None! - -# # this throws a syntax error: -# def f(None): - # print None -# f() diff --git a/test/tests/nonself_resurrection.py b/test/tests/nonself_resurrection.py deleted file mode 100644 index d4b4926be..000000000 --- a/test/tests/nonself_resurrection.py +++ /dev/null @@ -1,18 +0,0 @@ -# Objects are allowed to resurrect other objects too, I guess - -class C(object): - def __init__(self, x): - self.x = x - - def __del__(self): - global x - x = self.x - -x = None -c = C([]) -del c - -import gc -gc.collect() - -print x diff --git a/test/tests/nonzero_patching.py b/test/tests/nonzero_patching.py deleted file mode 100644 index 4160c1562..000000000 --- a/test/tests/nonzero_patching.py +++ /dev/null @@ -1,11 +0,0 @@ -# run_args: -n -# statcheck: stats.get('slowpath_nonzero', 0) <= 10 - -def f(): - for i in xrange(-10, 10): - print i, - if i: - print "is truth-y" - else: - print "is false-y" -f() diff --git a/test/tests/osr_big.py b/test/tests/osr_big.py deleted file mode 100644 index d8935a9cb..000000000 --- a/test/tests/osr_big.py +++ /dev/null @@ -1,36 +0,0 @@ -# "big osr" in terms of lots of live variables needing to be passed through: - -def outer(quit): - if quit: - return - - a = 1 - b = 2 - c = 3 - d = 4 - e = 5 - f = 6 - g = 7 - h = 8 - i = 9 - l = [] - - n = 100000 - while n: - n = n - 1 - a = a + 1 - b = b + 1 - c = c + 1 - d = d + 1 - e = e + 1 - f = f + 1 - g = g + 1 - h = h + 1 - i = i + 1 - l.append(n) - print n, a, b, c, d, e, f, g, h, i, len(l) - -# Call it a few times to convince it to not be in the interpter: -for i in xrange(10): - outer(1) -outer(0) diff --git a/test/tests/osr_weird.py b/test/tests/osr_weird.py deleted file mode 100644 index 345a8dd3e..000000000 --- a/test/tests/osr_weird.py +++ /dev/null @@ -1,28 +0,0 @@ -# This is from another test that was supposed to test something else (longargs_stackusage), -# but with reduced loop count so that it's runnable and exposes the other issue. - -def f6(a1, a2, a3, a4, a5, a6, l1, l2, l3, l4, l5, l6, x1, x2, x3, x4, x5, x6): - return 1 - -def f(): - a = 1 - b = 2 - c = 3 - d = 4 - e = 5 - - n = 100000 - t = 0 - - l1 = [] - l2 = [] - l3 = [] - l4 = [] - l5 = [] - l6 = [] - while n: - t = t + f6(l1, l2, l3, l4, l5, l6, l1, l2, l3, l4, l5, l6, l1, l2, l3, l4, l5, l6) - n = n - 1 - - print a, b, c, d, e -f() diff --git a/test/tests/patching_under.py b/test/tests/patching_under.py deleted file mode 100644 index eff552454..000000000 --- a/test/tests/patching_under.py +++ /dev/null @@ -1,35 +0,0 @@ -# run_args: -n -# Trying to create an example of returning to a patchpoint that has been rewritten - -class C(object): - def f(self, n): - print "C()", n - f(n) -c = C() - -def f(n): - print "f()", n - if n == 0 or n == 1: - tocall = f - elif n == 2: - tocall = c.f - else: - return - tocall(n + 1) - print "done", n -f(0) -f(0) - -class D(object): - def __call__(self, n): - print "D.__call__()", n -def call_f(c, n): - c.f(n) -class C2(object): - def f(self, n): - print "f1", n - C2.f = D() - call_f(self, n) -c = C2() -call_f(c, 2) -call_f(c, 2) diff --git a/test/tests/polymorphic_ics.py b/test/tests/polymorphic_ics.py deleted file mode 100644 index fbc8399c6..000000000 --- a/test/tests/polymorphic_ics.py +++ /dev/null @@ -1,15 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_binop'] < 10 - -class O(object): - def __init__(self, n): - self.n = n - -def mul2(o): - return o.n * 2 - -oi = O(1) -of = O(1.0) -for i in xrange(1000): - print mul2(oi) - print mul2(of) diff --git a/test/tests/raytrace_small.py b/test/tests/raytrace_small.py deleted file mode 100644 index fd3af0ac5..000000000 --- a/test/tests/raytrace_small.py +++ /dev/null @@ -1,384 +0,0 @@ -# This file contains definitions for a simple raytracer. -# Copyright Callum and Tony Garnock-Jones, 2008. -# This file may be freely redistributed under the MIT license, -# http://www.opensource.org/licenses/mit-license.php - -import math - -EPSILON = 0.00001 -INF = 1.0e9 - -class Vector(object): - def __init__(self, initx, inity, initz): - self.x = initx - self.y = inity - self.z = initz - - def __str__(self): - return '(%s,%s,%s)' % (self.x, self.y, self.z) - - def __repr__(self): - return 'Vector(%s,%s,%s)' % (self.x, self.y, self.z) - - def magnitude(self): - return math.sqrt(self.dot(self)) - - def __add__(self, other): - return Vector(self.x + other.x, self.y + other.y, self.z + other.z) - - def __sub__(self, other): - return Vector(self.x - other.x, self.y - other.y, self.z - other.z) - - def scale(self, factor): - return Vector(factor * self.x, factor * self.y, factor * self.z) - - def dot(self, other): - return (self.x * other.x) + (self.y * other.y) + (self.z * other.z) - - def cross(self, other): - return Vector(self.y * other.z - self.z * other.y, - self.z * other.x - self.x * other.z, - self.x * other.y - self.y * other.x) - - def normalized(self): - return self.scale(1.0 / self.magnitude()) - - def negated(self): - return self.scale(-1) - - def __eq__(self, other): - return (self.x == other.x) and (self.y == other.y) and (self.z == other.z) - - def isVector(self): - return True - - def isPoint(self): - return False - - def reflectThrough(self, normal): - d = normal.scale(self.dot(normal)) - return self - d.scale(2) - -VZERO = Vector(0,0,0) -VRIGHT = Vector(1,0,0) -VUP = Vector(0,1,0) -VOUT = Vector(0,0,1) - -if not (VRIGHT.reflectThrough(VUP) == VRIGHT): - print 1/0 -if not (Vector(-1,-1,0).reflectThrough(VUP) == Vector(-1,1,0)): - print 1/0 - -class Point(object): - def __init__(self, initx, inity, initz): - self.x = initx - self.y = inity - self.z = initz - - def __str__(self): - return '(%s,%s,%s)' % (self.x, self.y, self.z) - - def __repr__(self): - return 'Point(%s,%s,%s)' % (self.x, self.y, self.z) - - def __add__(self, other): - return Point(self.x + other.x, self.y + other.y, self.z + other.z) - - def __sub__(self, other): - return Vector(self.x - other.x, self.y - other.y, self.z - other.z) - - def isVector(self): - return False - - def isPoint(self): - return True - -class Sphere(object): - def __init__(self, centre, radius): - self.centre = centre - self.radius = radius - - def __repr__(self): - return 'Sphere(%s,%s)' % (repr(self.centre), self.radius) - - def intersectionTime(self, ray): - cp = self.centre - ray.point - v = cp.dot(ray.vector) - discriminant = (self.radius * self.radius) - (cp.dot(cp) - v*v) - if discriminant < 0: - return INF + 1 - else: - return v - math.sqrt(discriminant) - - def normalAt(self, p): - return (p - self.centre).normalized() - -class Halfspace(object): - def __init__(self, point, normal): - self.point = point - self.normal = normal.normalized() - - def __repr__(self): - return 'Halfspace(%s,%s)' % (repr(self.point), repr(self.normal)) - - def intersectionTime(self, ray): - v = ray.vector.dot(self.normal) - if v: - return 1 / -v - else: - return INF + 1 - - def normalAt(self, p): - return self.normal - -class Ray(object): - def __init__(self, point, vector): - self.point = point - self.vector = vector.normalized() - - def __repr__(self): - return 'Ray(%s,%s)' % (repr(self.point), repr(self.vector)) - - def pointAtTime(self, t): - return self.point + self.vector.scale(t) - -PZERO = Point(0,0,0) - -a = Vector(3,4,12) -b = Vector(1,1,1) - -class PpmCanvas(object): - def __init__(self, width, height, filenameBase): - self.bytes = [0] * (width * height * 3) - for i in range(width * height): - self.bytes[i * 3 + 2] = 255 - self.width = width - self.height = height - self.filenameBase = filenameBase - - def plot(self, x, y, r, g, b): - i = ((self.height - y - 1) * self.width + x) * 3 - self.bytes[i ] = max(0, min(255, int(r * 255))) - self.bytes[i+1] = max(0, min(255, int(g * 255))) - self.bytes[i+2] = max(0, min(255, int(b * 255))) - - def save(self): - for c in self.bytes: - print c - # with open(self.filenameBase + '.ppm', 'wb') as f: - # f.write('P6 %d %d 255\n' % (self.width, self.height)) - # l = [] - # for c in self.bytes: - # l.append(chr(c)) - # f.write(''.join(l)) - -def firstIntersection(intersections): - result = intersections[0][0], INF+1, intersections[0][2] - for i in intersections: - candidateT = i[1] - if candidateT < INF and candidateT > -EPSILON: - if result[1] > INF or candidateT < result[1]: - result = i - return result - -class Scene(object): - def __init__(self): - self.objects = [] - self.lightPoints = [] - self.position = Point(0, 1.8, 10) - self.lookingAt = PZERO - self.fieldOfView = 45 - self.recursionDepth = 0 - - def lookAt(self, p): - self.lookingAt = p - - def addObject(self, on, oi, sc): - self.objects.append((on, oi, sc)) - - def addLight(self, p): - self.lightPoints.append(p) - - def render(self, canvas): - #print 'Computing field of view' - fovRadians = math.pi * (self.fieldOfView / 2.0) / 180.0 - halfWidth = math.tan(fovRadians) - halfHeight = 0.75 * halfWidth - width = halfWidth * 2 - height = halfHeight * 2 - pixelWidth = width / (canvas.width - 1) - pixelHeight = height / (canvas.height - 1) - - eye = Ray(self.position, self.lookingAt - self.position) - vpRight = eye.vector.cross(VUP).normalized() - vpUp = vpRight.cross(eye.vector).normalized() - - #print 'Looping over pixels' - previousfraction = 0.0 - for y in range(canvas.height): - currentfraction = 1.0 * y / canvas.height - if currentfraction - previousfraction > 0.05: - print '%d%% complete' % int(currentfraction * 100) - previousfraction = currentfraction - for x in range(canvas.width): - xcomp = vpRight.scale(x * pixelWidth - halfWidth) - ycomp = vpUp.scale(y * pixelHeight - halfHeight) - ray = Ray(eye.point, eye.vector + xcomp + ycomp) - colour = self.rayColour(ray) - canvas.plot(x,y,colour[0], colour[1], colour[2]) - - print 'Complete.' - canvas.save() - - def rayColour(self, ray): - if self.recursionDepth > 3: - return (0.0,0.0,0.0) - - self.recursionDepth = self.recursionDepth + 1 - intersections = [] - for on, oi, sc in self.objects: - intersections.append((on, oi(ray), sc)) - # intersections = [(on, oi(ray), sc) for (on, oi, sc) in self.objects] - i = firstIntersection(intersections) - if i[1] > INF: - self.recursionDepth = self.recursionDepth - 1 - return (0.0,0.0,0.0) ## the background colour - else: - (o, t, s) = i - p = ray.pointAtTime(t) - r = s(self, ray, p, o(p)) - self.recursionDepth = self.recursionDepth - 1 - return r - - def _lightIsVisible(self, l, p): - for (on, oi, sc) in self.objects: - t = oi(Ray(p,l - p)) - if t < INF and t > EPSILON: - return False - return True - - def visibleLights(self, p): - result = [] - for l in self.lightPoints: - if self._lightIsVisible(l, p): - result.append(l) - return result - -def addColours(a, scale, b): - return (a[0] + scale * b[0], - a[1] + scale * b[1], - a[2] + scale * b[2]) - -class SimpleSurface(object): - def __init__(self, baseColour): - self.baseColour = baseColour - self.specularCoefficient = 0.2 - self.lambertCoefficient = 0.6 - self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient - - def baseColourAt(self, p): - return self.baseColour - - def colourAt(self, scene, ray, p, normal): - b = self.baseColourAt(p) - - c = (0.0, 0.0, 0.0) - if self.specularCoefficient > 0: - reflectedRay = Ray(p, ray.vector.reflectThrough(normal)) - #print p, normal, ray.vector, reflectedRay.vector - reflectedColour = scene.rayColour(reflectedRay) - c = addColours(c, self.specularCoefficient, reflectedColour) - - if self.lambertCoefficient > 0: - lambertAmount = 0.0 - for lightPoint in scene.visibleLights(p): - contribution = (lightPoint - p).normalized().dot(normal) - if contribution > 0: - lambertAmount = lambertAmount + contribution - lambertAmount = min(1,lambertAmount) - c = addColours(c, self.lambertCoefficient * lambertAmount, b) - - if self.ambientCoefficient > 0: - c = addColours(c, self.ambientCoefficient, b) - - return c - -class CheckerboardSurface(object): - def __init__(self): - self.baseColour = (1.0, 1.0, 1.0) - self.specularCoefficient = 0.2 - self.lambertCoefficient = 0.6 - self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient - self.otherColour = (0.0, 0.0, 0.0) - self.checkSize = 1 - - def baseColourAt(self, p): - v = p - PZERO - v.scale(1.0 / self.checkSize) - if (int(abs(v.x) + 0.5) + \ - int(abs(v.y) + 0.5) + \ - int(abs(v.z) + 0.5)) \ - % 2: - return self.otherColour - else: - return self.baseColour - - def colourAt(self, scene, ray, p, normal): - b = self.baseColourAt(p) - - c = (0.0,0.0,0.0) - if self.specularCoefficient > 0: - reflectedRay = Ray(p, ray.vector.reflectThrough(normal)) - #print p, normal, ray.vector, reflectedRay.vector - reflectedColour = scene.rayColour(reflectedRay) - c = addColours(c, self.specularCoefficient, reflectedColour) - - if self.lambertCoefficient > 0: - lambertAmount = 0.0 - for lightPoint in scene.visibleLights(p): - contribution = (lightPoint - p).normalized().dot(normal) - if contribution > 0: - lambertAmount = lambertAmount + contribution - lambertAmount = min(1,lambertAmount) - c = addColours(c, self.lambertCoefficient * lambertAmount, b) - - if self.ambientCoefficient > 0: - c = addColours(c, self.ambientCoefficient, b) - - return c - -def _main(): - Canvas = PpmCanvas - c = Canvas(8,6,'test_raytrace_tiny') - # c = Canvas(80,60,'test_raytrace_small') - # c = Canvas(320,240,'test_raytrace') - #c = Canvas(640,480,'test_raytrace_big') - s = Scene() - s.addLight(Point(30, 30, 10)) - s.addLight(Point(-10, 100, 30)) - s.lookAt(Point(0, 2, 0)) - - obj = Sphere(Point(1,3,-10), 2) - surf = SimpleSurface((1.0,1.0,0.0)) - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - for y in range(6): - obj = Sphere(Point(-3 - y * 0.4, 2.3, -5), 0.4) - surf = SimpleSurface((y / 6.0, 1 - y / 6.0, 0.5)) - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - obj = Halfspace(Point(0,0,0), VUP) - surf = CheckerboardSurface() - s.addObject(obj.normalAt, obj.intersectionTime, surf.colourAt) - s.render(c) - -def main(n): - import time - times = [] - for i in range(n): - t1 = time.time() - _main() - t2 = time.time() - times.append(t2 - t1) - return times - -main(1) - diff --git a/test/tests/resurrection.py b/test/tests/resurrection.py deleted file mode 100644 index 130cdeae1..000000000 --- a/test/tests/resurrection.py +++ /dev/null @@ -1,24 +0,0 @@ -# Objects are allowed to resurrect themselves in their __del__ methods... -# Note: the behavior here will differ from cPython and maybe PyPy - -x = None -running = True - -class C(object): - def __init__(self): - self.n = 0 - def __del__(self): - if running: - global x - self.n += 1 - print "__del__ #%d" % self.n - x = self - -import gc - -x = C() -for i in xrange(100): - x = None - gc.collect() - # print x -running = False diff --git a/test/tests/return_in_class.py b/test/tests/return_in_class.py deleted file mode 100644 index 42c18b6f9..000000000 --- a/test/tests/return_in_class.py +++ /dev/null @@ -1,2 +0,0 @@ -class C(object): - return diff --git a/test/tests/return_outside_func.py b/test/tests/return_outside_func.py deleted file mode 100644 index a09c86384..000000000 --- a/test/tests/return_outside_func.py +++ /dev/null @@ -1 +0,0 @@ -return diff --git a/test/tests/scoping_classes.py b/test/tests/scoping_classes.py deleted file mode 100644 index ccbe6bd5a..000000000 --- a/test/tests/scoping_classes.py +++ /dev/null @@ -1,21 +0,0 @@ - -X = 0 -Y = 0 -def wrapper(): - X = 1 - Y = 1 - class C(object): - global Y - X = 2 - Y = 2 - def f(self): - # These references should skip all of the classdef directives, - # and hit the definitions in the wrapper() function - print X - print Y - return C - -wrapper()().f() - -print X -print Y # got changed in classdef for C diff --git a/test/tests/setattr_patching_under.py b/test/tests/setattr_patching_under.py deleted file mode 100644 index 104a5617f..000000000 --- a/test/tests/setattr_patching_under.py +++ /dev/null @@ -1,37 +0,0 @@ -class C(object): - pass - -def set(o, a): - o.x = a - -class D(object): - def __del__(self): - print "in __del__" - c = C() - c.a = 1 - c.b = 2 - c.c = 3 - c.d = 4 - c.e = 5 - c.f = 6 - c.g = 7 - c.h = 8 - set(c, 1) - print "done with __del__" - -c = C() - -# The first set() just adds the attribute -print 1 -set(c, 1) - -# The second set() rewrites the setattr to be a in-place set, and also adds the D object -print 2 -set(c, D()) - -# This third set() will remove the D() object, so by the time the set() finishes, -# the patchpoint could be rewritten due to the set() in the D.__del__ destructor -print 3 -set(c, 1) - -print 4 diff --git a/test/tests/setitem.py b/test/tests/setitem.py deleted file mode 100644 index bd020740b..000000000 --- a/test/tests/setitem.py +++ /dev/null @@ -1,20 +0,0 @@ -class C(object): - def __setitem__(self, k, v): - print k, v - self.k = k - self.v = v - return "hello" - -c = C() -c[1] = 2 -print c.k -print c.v - -def si(k, v): - print "bad si!" - o - -c.__setitem__ = si -c[3] = 4 - -1[2] = 3 diff --git a/test/tests/slice.py b/test/tests/slice.py deleted file mode 100644 index c8cc9ee35..000000000 --- a/test/tests/slice.py +++ /dev/null @@ -1,6 +0,0 @@ -class C(object): - def __getitem__(self, idx): - print idx -c = C() -c[1] -c[1:2] diff --git a/test/tests/sort_small.py b/test/tests/sort_small.py deleted file mode 100644 index 856bcd163..000000000 --- a/test/tests/sort_small.py +++ /dev/null @@ -1,20 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_getitem'] <= 20 -# statcheck: stats['slowpath_setitem'] <= 20 - -def sort(l): - n = len(l) - for i in xrange(n): - print i - for j in xrange(i): - if l[i] < l[j]: - l[i], l[j] = l[j], l[i] - return l - -l = [] -N = 500 -for i in xrange(N): - l.append(N - i) -sort(l) -print l - diff --git a/test/tests/speculation_test.py b/test/tests/speculation_test.py deleted file mode 100644 index b64380fd2..000000000 --- a/test/tests/speculation_test.py +++ /dev/null @@ -1,11 +0,0 @@ -# Not really that robust of a test, but checks to make sure that -# different constructs handle the PARTIAL state in irgen. - -def f(n): - return n - -def f2(): - (), [], f(1) - -for i in xrange(100000): - f2() diff --git a/test/tests/str_functions.py b/test/tests/str_functions.py deleted file mode 100644 index edfdd2982..000000000 --- a/test/tests/str_functions.py +++ /dev/null @@ -1,6 +0,0 @@ -print "-".join(["hello", "world"]) - -print repr(chr(0) + chr(180)) -print repr('"') -# print repr("'") // don't feel like handling this right now; this should print out (verbatim) "'", ie realize it can use double quotes -print repr("'\"") diff --git a/test/tests/string_interpolation.py b/test/tests/string_interpolation.py deleted file mode 100644 index 79f2ad5eb..000000000 --- a/test/tests/string_interpolation.py +++ /dev/null @@ -1,4 +0,0 @@ -print "%d" % 1 -print "%02d" % 2 -print "%f" % 1 -print "%s" % 2 diff --git a/test/tests/t.py b/test/tests/t.py deleted file mode 100644 index 3390bda43..000000000 --- a/test/tests/t.py +++ /dev/null @@ -1,7 +0,0 @@ -def f(): - return range(10) - -for i in xrange(1000000): - f() - -print "This will break" diff --git a/test/tests/t2.py b/test/tests/t2.py deleted file mode 100644 index 20c37d877..000000000 --- a/test/tests/t2.py +++ /dev/null @@ -1,8 +0,0 @@ -def f(c): - c.x = None - c.x = 1 - # return None - -class C(object): - pass -print f(C()) diff --git a/test/tests/time_test.py b/test/tests/time_test.py deleted file mode 100644 index 21525aaa8..000000000 --- a/test/tests/time_test.py +++ /dev/null @@ -1,2 +0,0 @@ -import time -print time diff --git a/test/tests/tuple_depth.py b/test/tests/tuple_depth.py deleted file mode 100644 index f057e19fa..000000000 --- a/test/tests/tuple_depth.py +++ /dev/null @@ -1,8 +0,0 @@ -# I was worried about using a recursive parser for obscenely-nested source code, -# but based off this example it looks like that's what cPython and pypy both use as well. - -# To save test-file space, just generate the expression and then eval() it: -N = 100000 -s = "(" * N + ")" * N -t = eval(s) -len(repr(t[0][0][0])) diff --git a/test/tests/tuple_iteration.py b/test/tests/tuple_iteration.py deleted file mode 100644 index f9f4e2334..000000000 --- a/test/tests/tuple_iteration.py +++ /dev/null @@ -1,9 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_unboxedlen'] < 10 - -d = {} -for i in xrange(1000): - d[i] = i ** 2 - -for k, v in sorted(d.items()): - print k, v diff --git a/test/tests/tuple_unpacking.py b/test/tests/tuple_unpacking.py deleted file mode 100644 index 4291e012e..000000000 --- a/test/tests/tuple_unpacking.py +++ /dev/null @@ -1,22 +0,0 @@ -def gcd(a, b): - if a > b: - a, b = b, a - - while a > 0: - a, b = b % a, a - return b - -for i in xrange(1, 10): - for j in xrange(1, 10): - print i, j, gcd(i, j) - -def sort(l): - n = len(l) - for i in xrange(n): - for j in xrange(i): - if l[j] > l[i]: - l[j], l[i] = l[i], l[j] - return l -print sort([1, 3, 5, 7, 2, 4, 9, 9, 4]) - -a, b, c = 1, diff --git a/test/tests/tuple_unpacking_invalid.py b/test/tests/tuple_unpacking_invalid.py deleted file mode 100644 index 5aff098e2..000000000 --- a/test/tests/tuple_unpacking_invalid.py +++ /dev/null @@ -1,2 +0,0 @@ -# Int not iterable: -a, b, c = 1 diff --git a/test/tests/tuples.py b/test/tests/tuples.py deleted file mode 100644 index 74755a0b5..000000000 --- a/test/tests/tuples.py +++ /dev/null @@ -1,66 +0,0 @@ -t = (1, "h") -print t, str(t), repr(t) -if 1: - t = (3,) -print t - -def f(): - t = (1, 3) - print t -f() - -print () -print (1,) -print (1, 2) -print (1, 2, 3) - -t = 1, 3 -print t - -print (2,) < (2,) -print (2,) < (2, 3) -print (3,) < (2, 3) - -print - -class T(object): - def __init__(self, n): - self.n = n - - def __lt__(self, rhs): - print "lt", self.n, rhs.n - return self.n < rhs.n - - def __le__(self, rhs): - print "le", self.n, rhs.n - return self - - def __gt__(self, rhs): - print "gt", self.n, rhs.n - return False - - def __ge__(self, rhs): - print "ge", self.n, rhs.n - return False - - def __eq__(self, rhs): - print "eq", self.n, rhs.n - return self.n == rhs.n - - def __repr__(self): - return "" - -def t(l, r): - print l < r - print l <= r - print l > r - print l >= r - print l == r - print l != r - -t(T(1), T(2)) -t(T(1), T(1)) -t((T(1),), (T(1),)) -t((T(1),), (T(2),)) -t((T(1),1), (T(2),)) -t((T(1),), (T(2),1)) diff --git a/test/tests/unaryops.py b/test/tests/unaryops.py deleted file mode 100644 index f9686aeb3..000000000 --- a/test/tests/unaryops.py +++ /dev/null @@ -1,8 +0,0 @@ -def f(x): - print x, not x, ~x, +x, -x - -f(0) -f(1) -f(-1) -f(True) -f(False) diff --git a/test/tests/with_exit.py b/test/tests/with_exit.py deleted file mode 100644 index 184e1de7f..000000000 --- a/test/tests/with_exit.py +++ /dev/null @@ -1,61 +0,0 @@ -# Make sure __exit__ gets called in various exit scenarios: - -class C(object): - def __enter__(self): - print "__enter__" - def __exit__(self, type, val, tb): - print "__exit__" - -def f(): - with C(): - pass - with C() as n: - pass - - n = 2 - while n: - print n - n = n - 1 - with C() as o: - continue - - n = 2 - while n: - print n - n = n - 1 - with C() as o: - with C() as o2: - continue - continue - - n = 2 - while n: - print n - n = n - 1 - with C() as o: - break - - n = 2 - while n: - print n - n = n - 1 - with C() as o: - return - -f() - -def f2(b): - n = 2 - while n: - print n - n = n - 1 - with C() as o: - with C() as o2: - if b: - return "b true" - else: - return "b false" - -print f2(False) -print f2(True) - diff --git a/test/tests/with_parsed.py b/test/tests/with_parsed.py deleted file mode 100644 index f1982b276..000000000 --- a/test/tests/with_parsed.py +++ /dev/null @@ -1,27 +0,0 @@ -# Simple test that doesn't actually examine with functionality, just ensures that it's -# minimally handled: - -class C(object): - def __init__(self, n): - self.n = n - - def __enter__(self): - print "__enter__", self.n - return self.n - - def __exit__(self, type, val, tb): - print "__exit__", type, val, tb - -def new_exit(self, type, val, tb): - print "new exit!", self, type, val, tb - -def bad_exit(type, val, tb): - print "bad exit!" - -c = C(1) -with c as n: - C.__exit__ = new_exit # this shouldn't have any effect - c.__exit__ = bad_exit - print n -print n - diff --git a/test/tests/xrange.py b/test/tests/xrange.py deleted file mode 100644 index f2fe9b009..000000000 --- a/test/tests/xrange.py +++ /dev/null @@ -1,5 +0,0 @@ -# run_args: -n -# statcheck: stats['slowpath_getclsattrint'] <= 20 - -for i in xrange(1000): - print i diff --git a/test/unittests/gc.cpp b/test/unittests/gc.cpp deleted file mode 100644 index c23f418af..000000000 --- a/test/unittests/gc.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include - -#include "gtest/gtest.h" - -#include "gc/gc_alloc.h" - -using namespace pyston; -using namespace pyston::gc; - -void testAlloc(int B) { - struct S { - int data[0]; - }; - - std::unique_ptr masks(new int[B/4]); - masks.get()[0] = 0; - for (int j = 1; j < B/4; j++) { - masks.get()[j] = (masks.get()[j-1] * 1103515245 + 12345) % (1 << 31); - } - - for (int l = 0; l < 10; l++) { - std::vector allocd; - std::unordered_set seen; - - const int N = l * 1000; - for (int i = 0; i < N; i++) { - S* t = static_cast(gc_alloc(B)); - - ASSERT_TRUE(t != NULL); - ASSERT_EQ(0, seen.count(t)); - - for (int j = 0; j < B/4; j++) { - t->data[j] = i ^ masks.get()[j]; - } - - allocd.push_back(t); - seen.insert(t); - } - - for (int i = 0; i < N; i++) { - for (int j = 0; j < B/4; j++) { - ASSERT_EQ(i ^ masks.get()[j], allocd[i]->data[j]); - } - gc_free(allocd[i]); - } - } -} - -TEST(gc, alloc16) { testAlloc(16); } -TEST(gc, alloc24) { testAlloc(24); } -TEST(gc, alloc32) { testAlloc(32); } -TEST(gc, alloc48) { testAlloc(48); } -TEST(gc, alloc64) { testAlloc(64); } -TEST(gc, alloc128) { testAlloc(128); } -TEST(gc, alloc258) { testAlloc(258); } -TEST(gc, alloc3584) { testAlloc(3584); } - -TEST(gc, largeallocs) { - int s1 = 1 << 20; - char* d1 = (char*)gc_alloc(s1); - memset(d1, 1, s1); - - int s2 = 2 << 20; - char* d2 = (char*)gc_alloc(s2); - memset(d2, 2, s2); - - int s3 = 4 << 20; - char* d3 = (char*)gc_alloc(s3); - memset(d3, 3, s3); - - for (int i = 0; i < s1; i++) { - ASSERT_EQ(1, d1[i]); - } - - for (int i = 0; i < s2; i++) { - ASSERT_EQ(2, d2[i]); - } - - for (int i = 0; i < s3; i++) { - ASSERT_EQ(3, d3[i]); - } -} - -TEST(gc, freeing) { - // Not sure this is enough to crash if it doesn't get freed: - for (int i = 0; i < 1000000; i++) { - void* a = gc_alloc(1024); - gc_free(a); - } -} - -TEST(gc, freeingLarge) { - for (int i = 0; i < 100000; i++) { - void* a = gc_alloc(1<<24); - gc_free(a); - } -} - diff --git a/tools/annotate.py b/tools/annotate.py deleted file mode 100644 index b3917b576..000000000 --- a/tools/annotate.py +++ /dev/null @@ -1,45 +0,0 @@ -import subprocess -import sys - -def get_objdump(func): - for l in open("perf_map/index.txt"): - addr, this_func = l.split() - if this_func == func: - # print ' '.join(["objdump", "-b", "binary", "-m", "i386", "-D", "perf_map/" + func, "--adjust-vma=0x%s" % addr]) - p = subprocess.Popen(["objdump", "-b", "binary", "-m", "i386:x86-64", "-D", "perf_map/" + func, "--adjust-vma=0x%s" % addr], stdout=subprocess.PIPE) - r = p.communicate()[0] - assert p.wait() == 0 - return r - - raise Exception("Couldn't find function %r to objdump" % func) - -if __name__ == "__main__": - # TODO: if it's not passed, maybe default to annotating the - # first function in the profile (the one in which the plurality of - # the time is spent)? - - func = sys.argv[1] - - objdump = get_objdump(func) - - p = subprocess.Popen(["perf", "annotate", "-v", func], stdout=subprocess.PIPE, stderr=open("/dev/null", "w")) - annotate = p.communicate()[0] - assert p.wait() == 0 - - counts = {} - for l in annotate.split('\n'): - if ':' not in l: - continue - addr, count = l.split(':') - addr = addr.strip() - if addr == "h->sum": - continue - - counts[addr] = int(count) - - for l in objdump.split('\n')[7:]: - addr = l.split(':')[0] - count = counts.pop(addr.strip(), 0) - print str(count).rjust(8), l - - assert not counts, counts diff --git a/tools/build_system/ld b/tools/build_system/ld deleted file mode 100755 index 4f644efdc..000000000 --- a/tools/build_system/ld +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -set -eu - -FLAGS= -RETRY= - -if which gold > /dev/null ; then - LD=gold - # FLAGS="--incremental --incremental-patch=10" - # RETRY=y -elif [ -f $HOME/llvm/binutils-build/gold/ld-new ]; then - LD=$HOME/llvm/binutils-build/gold/ld-new - # FLAGS="--incremental --incremental-patch=10" - # RETRY=y -else - echo "gold not available" - LD=ld -fi - -set +e - -# echo $LD $FLAGS "$@" -$LD $FLAGS "$@" -EXIT=$? -if [ $EXIT -ne 0 -a -n "$RETRY" ]; then - echo "retrying" - $LD $FLAGS "$@" - EXIT=$? -fi -exit $EXIT diff --git a/tools/cumulate.sh b/tools/cumulate.sh deleted file mode 100644 index ac023e1cf..000000000 --- a/tools/cumulate.sh +++ /dev/null @@ -1 +0,0 @@ -awk '{if ($0 ~ /%/) { s += $1; print s, "\t", $0 } }' diff --git a/tools/demangle.cpp b/tools/demangle.cpp deleted file mode 100644 index 31bce9fdd..000000000 --- a/tools/demangle.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include - -int main(int argc, char** argv) { - if (argc != 2) { - fprintf(stderr, "Usage: %s IDENTIFIER\n", argv[0]); - exit(1); - } - - int status; - char* demangled = abi::__cxa_demangle(argv[1], NULL, NULL, &status); - if (demangled) { - printf("%s\n", demangled); - } else { - fprintf(stderr, "Error: unable to demangle\n"); - exit(1); - } - return 0; -} diff --git a/tools/find_problem.py b/tools/find_problem.py deleted file mode 100644 index abefd0c34..000000000 --- a/tools/find_problem.py +++ /dev/null @@ -1,58 +0,0 @@ -import math -import os -import subprocess -import sys - -def test(rev, args): - subprocess.check_call(["make", "llvm_gitup", "LLVM_REVISION=%d" % rev]) - subprocess.check_call(["make", "llvm_release", "llvm_quick", "LLVM_REVISION=%d" % rev]) - code = subprocess.call(["make", "LLVM_REVISION=%d" % rev] + args) - return code == 0 - -def efficiency(rid): - p = 1.0 * (rid - good_rev) / (bad_rev - good_rev) - learnt = - (p * math.log(p) + (1-p) * math.log(1-p)) - - # k represents how much of the codebase an "average commit" causes to be rebuilt: - k = 0.10 - - effort = 1 - math.exp(- k * (1 + min(rid - good_rev, bad_rev - rid))) - assert effort > 0 - # print good_rev, rid, bad_rev, learnt, effort, learnt/effort - return learnt/effort - -if __name__ == "__main__": - good_rev, bad_rev = sys.argv[1:3] - good_rev = int(good_rev) - bad_rev = int(bad_rev) - - args = sys.argv[3:] - assert args - - # print "Confirming that %d works" % good_rev - # b = test(good_rev, args) - # assert b, "good_rev must be working" -# - # print "Confirming that %d is broken" % bad_rev - # b = test(bad_rev, args) - # assert not b, "bad_rev must not work" - - while bad_rev > good_rev + 1: - print "%d is good, %d is bad" % (good_rev, bad_rev) - open("find_problem.status", "w").write("%d %d\n" % (good_rev, bad_rev)) - middle = (good_rev + bad_rev + 1) / 2 - revs = range(good_rev+1, middle+1) - revs.sort(reverse=True, key=efficiency) - # print good_rev, bad_rev, (good_rev + bad_rev) / 2, revs[0] - next_rev = revs[0] - print "Testing revision %d (p=%.1f%%)" % (next_rev, 100.0 * (next_rev - good_rev) / (bad_rev - good_rev)) - b = test(next_rev, args) - - print "Revision", next_rev, "works" if b else "failed" - if b: - good_rev = next_rev - else: - bad_rev = next_rev - - open("find_problem.status", "w").write("%d %d\n" % (good_rev, bad_rev)) - print "Rev %d is good, rev %d is bad" % (good_rev, bad_rev) diff --git a/tools/git_svn_gotorev.py b/tools/git_svn_gotorev.py deleted file mode 100644 index 411579374..000000000 --- a/tools/git_svn_gotorev.py +++ /dev/null @@ -1,84 +0,0 @@ -# Similar to "git svn find-rev" but: -# - doesn't require git-svn to be installed -# - is faster -# - actually works - -import os -import subprocess -import sys - -def find_rev(svn_id, fetch_if_necessary=True): - p = subprocess.Popen(["git", "log", "origin/master"], cwd=repo, stdout=subprocess.PIPE) - - isfirst = True - commit = None - while True: - s = p.stdout.readline() - - if s.startswith("commit"): - commit = s.strip().split()[1] - elif s.startswith(" git-svn-id:"): - rid = int(s.split()[1].split('@')[1]) - if rid <= svn_rev: - break - isfirst = False - else: - raise Exception("???") - assert commit - - p.kill() - - if isfirst: - if fetch_if_necessary: - print "Need to fetch the repo" - subprocess.check_call(["git", "fetch"], cwd=repo) - print "Trying again" - return find_rev(svn_id, False) - else: - print "This is the newest one??" - else: - print "Don't need to fetch" - - print "Commit to go to is:", commit, rid - return commit, rid - -if __name__ == "__main__": - repo, svn_rev, patch_dir = sys.argv[1:] - svn_rev = int(svn_rev) - assert os.path.isdir(repo) - - commit, rid = find_rev(svn_rev) - - p = subprocess.Popen(["git", "show", "--format=short"], cwd=repo, stdout=subprocess.PIPE) - cur_commit = p.stdout.readline().strip().split()[1] - print "Currently:", cur_commit - p.kill() - # TODO: can't do this optimization now that we have patches to apply; - # maybe could try to determine that the patches are the same? - # if cur_commit == commit: - # print "Up to date" - # sys.exit(0) - - exitcode = subprocess.call(["git", "diff", "--exit-code"], cwd=repo, stdout=open("/dev/null")) - diffs = (exitcode != 0) - if diffs: - print >>sys.stderr, "Error: the llvm directory has modifications that would be lost!" - print >>sys.stderr, "Please stash or revert them before running this script." - sys.exit(1) - - subprocess.check_call(["git", "diff", "--dirstat", commit], cwd=repo) - subprocess.check_call(["git", "checkout", "-B", "tmp", commit], cwd=repo) - subprocess.check_call(["git", "checkout", "-B", "cur", commit], cwd=repo) - - if not os.path.exists(patch_dir): - patch_fns = [] - else: - patch_fns = sorted(os.listdir(patch_dir)) - for patch_fn in patch_fns: - if patch_fn.startswith('.'): - continue - patch_fn = os.path.abspath(os.path.join(patch_dir, patch_fn)) - subprocess.check_call(["git", "am", patch_fn], cwd=repo) - - if diffs: - subprocess.check_call(["git", "stash", "pop", "-q"], cwd=repo) diff --git a/tools/mcjitcache.cpp b/tools/mcjitcache.cpp deleted file mode 100644 index 19f399318..000000000 --- a/tools/mcjitcache.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include - -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/SystemUtils.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/Cloning.h" - -using namespace llvm; - -static cl::opt -InputFilename(cl::Positional, cl::desc(""), - cl::init("-"), cl::value_desc("filename")); - -static cl::opt -OutputFilename("o", cl::desc("Specify output filename"), - cl::value_desc("filename"), cl::init("-")); - -static cl::opt -Force("f", cl::desc("Enable binary output on terminals")); - -static cl::opt -Publicize("p", cl::desc("Make all private-linkage variables public")); - -class MyObjectCache : public llvm::ObjectCache { - private: - public: - MyObjectCache() { - } - - virtual void notifyObjectCompiled(const llvm::Module *M, const llvm::MemoryBuffer *Obj) { - std::string ErrStr; - llvm::raw_fd_ostream IRObjectFile(OutputFilename.c_str(), ErrStr, llvm::sys::fs::F_Binary); - if (!Force && CheckBitcodeOutputToConsole(IRObjectFile)) - exit(1); - IRObjectFile << Obj->getBuffer(); - } - - virtual llvm::MemoryBuffer* getObject(const llvm::Module* M) { - return NULL; - } - -}; - -int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - - LLVMContext &Context = getGlobalContext(); - llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, "mcjit pre-cacher"); - - SMDiagnostic Err; - - OwningPtr M; - M.reset(ParseIRFile(InputFilename, Err, Context)); - - if (M.get() == 0) { - Err.print(argv[0], errs()); - return 1; - } - - if (Publicize) { - for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) { - if (I->getLinkage() == GlobalVariable::PrivateLinkage) { - I->setLinkage(GlobalVariable::ExternalLinkage); - } - } - } - - Triple TheTriple(M->getTargetTriple()); - - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - - EngineBuilder eb(M.get()); - eb.setEngineKind(EngineKind::JIT); - eb.setUseMCJIT(true); - - TargetMachine *tm = eb.selectTarget(); - assert(tm); - ExecutionEngine *engine = eb.create(tm); - assert(engine); - - engine->setObjectCache(new MyObjectCache()); - engine->generateCodeForModule(M.get()); - - return 0; -} - diff --git a/tools/publicize.cpp b/tools/publicize.cpp deleted file mode 100644 index 52cdc1ecb..000000000 --- a/tools/publicize.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include - -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/SystemUtils.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/Cloning.h" - -using namespace llvm; - -static cl::opt -InputFilename(cl::Positional, cl::desc(""), - cl::init("-"), cl::value_desc("filename")); - -static cl::opt -OutputFilename("o", cl::desc("Specify output filename"), - cl::value_desc("filename"), cl::init("-")); - -static cl::opt -Force("f", cl::desc("Enable binary output on terminals")); - -// TODO should restructure this as a set of passes rather than a monolithic binary - - -// This function was originally gotten from http://llvm.org/svn/llvm-project/vmkit/branches/mcjit/lib/vmkit-prepare-code/adapt-linkage.cc -// It was released under the license here http://llvm.org/svn/llvm-project/vmkit/trunk/LICENSE.TXT -bool makeVisible(llvm::GlobalValue* gv) { - llvm::GlobalValue::LinkageTypes linkage = gv->getLinkage(); - bool changed = false; - - if (linkage == llvm::GlobalValue::LinkOnceODRLinkage) { - gv->setLinkage(llvm::GlobalValue::WeakODRLinkage); - changed = true; - } else if (linkage == llvm::GlobalValue::LinkOnceAnyLinkage) { - gv->setLinkage(llvm::GlobalValue::WeakAnyLinkage); - changed = true; - } else if (linkage == llvm::GlobalValue::PrivateLinkage) { - gv->setName(gv->getParent()->getModuleIdentifier() + gv->getName()); - gv->setLinkage(llvm::GlobalValue::ExternalLinkage); - changed = true; - } else if (linkage == llvm::GlobalValue::InternalLinkage) { - // Not sure if this is the right linkage here: - gv->setLinkage(llvm::GlobalValue::WeakODRLinkage); - changed = true; - } - - //llvm::GlobalValue::VisibilityTypes visibility = gv->getVisibility(); - //if (visibility == llvm::GlobalValue::HiddenVisibility) { - //gv->setVisibility(llvm::GlobalValue::ProtectedVisibility); - //changed = true; - //} - - return changed; -} - -bool isConstant(MDNode* parent_type, int offset) { - MDString *s = cast(parent_type->getOperand(0)); - - if (s->getString() == "_ZTSN6pyston19BoxedXrangeIteratorE") { - return (offset == 16); - } - - if (s->getString() == "_ZTSN6pyston8BoxedIntE") { - return (offset == 16); - } - - if (s->getString() == "_ZTSN6pyston10BoxedFloatE") { - return (offset == 16); - } - - if (s->getString() == "_ZTSN6pyston11BoxedXrangeE") { - return offset == 16 || offset == 24 || offset == 32; - } - - return false; -} - -bool updateTBAA(Function* f) { - bool changed = false; - - LLVMContext &c = f->getContext(); - - for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) { - MDNode *tbaa = it->getMetadata(LLVMContext::MD_tbaa); - if (!tbaa) - continue; - //tbaa->dump(); - - assert(tbaa->getNumOperands() == 3); - - if (!isConstant(llvm::cast(tbaa->getOperand(0)), llvm::cast(tbaa->getOperand(2))->getSExtValue())) { - continue; - } - - std::vector operands; - - for (int i = 0; i < tbaa->getNumOperands(); i++) { - operands.push_back(tbaa->getOperand(i)); - } - operands.push_back(ConstantInt::get(Type::getInt64Ty(c), 1)); - - MDNode *new_tbaa = MDNode::get(c, operands); - it->setMetadata(LLVMContext::MD_tbaa, new_tbaa); - //new_tbaa->dump(); - } - - return changed; -} - -int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - - LLVMContext &Context = getGlobalContext(); - llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, "mcjit pre-cacher"); - - SMDiagnostic Err; - - OwningPtr M; - M.reset(ParseIRFile(InputFilename, Err, Context)); - - if (M.get() == 0) { - Err.print(argv[0], errs()); - return 1; - } - - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { - makeVisible(I); - } - - for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) { - makeVisible(I); - } - - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { - updateTBAA(I); - } - - if (OutputFilename.empty()) - OutputFilename = "-"; - - std::string ErrorInfo; - tool_output_file out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None); - if (!ErrorInfo.empty()) { - errs() << ErrorInfo << '\n'; - return 1; - } - - WriteBitcodeToFile(M.get(), out.os()); - - out.keep(); - - return 0; -} - diff --git a/tools/tester.py b/tools/tester.py deleted file mode 100644 index 933cc43f5..000000000 --- a/tools/tester.py +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/bin/env python - -# -# This file is distributed under the MIT License; see LICENSE for details. -# - -import cPickle -import datetime -import functools -import getopt -import glob -import os -import Queue -import re -import resource -import signal -import subprocess -import sys -import tempfile -import threading -import time - -NUM_THREADS = 1 -IMAGE = "pyston_dbg" -KEEP_GOING = False -FN_JUST_SIZE = 20 -EXTRA_JIT_ARGS = [] -TIME_LIMIT = 2 - -def set_ulimits(): - # Guard the process from running too long with a hard rlimit. - # But first try to kill it after a second with a SIGALRM, though that's catchable/clearable by the program: - signal.alarm(TIME_LIMIT) - resource.setrlimit(resource.RLIMIT_CPU, (TIME_LIMIT + 1, TIME_LIMIT + 1)) - - MAX_MEM_MB = 100 - resource.setrlimit(resource.RLIMIT_AS, (MAX_MEM_MB * 1024 * 1024, MAX_MEM_MB * 1024 * 1024)) - -def get_expected_output(fn): - sys.stdout.flush() - assert fn.endswith(".py") - expected_fn = fn[:-3] + ".expected" - if os.path.exists(expected_fn): - return 0, open(expected_fn).read(), "" - - cache_fn = fn[:-3] + ".expected_cache" - if os.path.exists(cache_fn): - if os.stat(cache_fn).st_mtime > os.stat(fn).st_mtime: - try: - return cPickle.load(open(cache_fn)) - except EOFError: - pass - - # TODO don't suppress warnings globally: - p = subprocess.Popen(["python", "-Wignore", fn], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=open("/dev/null"), preexec_fn=set_ulimits) - out, err = p.communicate() - code = p.wait() - - r = code, out, err.strip().split('\n')[-1] - cPickle.dump(r, open(cache_fn, 'w')) - return r - -failed = [] -def run_test(fn, check_stats, run_memcheck): - r = fn.rjust(FN_JUST_SIZE) - - statchecks = [] - jit_args = ["-csr"] + EXTRA_JIT_ARGS - for l in open(fn): - if not l.startswith("#"): - break; - if l.startswith("# statcheck:"): - l = l[len("# statcheck:"):].strip() - statchecks.append(l) - if l.startswith("# run_args:"): - l = l[len("# run_args:"):].split() - jit_args += l - - run_args = ["./%s" % IMAGE] + jit_args + ["-q", fn] - start = time.time() - p = subprocess.Popen(run_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=open("/dev/null"), preexec_fn=set_ulimits) - out, err = p.communicate() - full_err = err - err = err.strip().split('\n')[-1] - - code = p.wait() - elapsed = time.time() - start - - stats = {} - if code == 0: - assert out.count("Stats:") == 1 - out, stats_str = out.split("Stats:") - for l in stats_str.strip().split('\n'): - k, v = l.split(':') - stats[k.strip()] = int(v) - - expected_code, expected_out, expected_err = get_expected_output(fn) - if code != expected_code: - color = 31 # red - - if code == 0: - err = "(Unexpected success)" - - if code == -signal.SIGALRM: - msg = "Timed out" - color = 33 # yellow - elif code == -signal.SIGKILL: - msg = "Killed!" - else: - msg = "Exited with code %d (expected code %d)" % (code, expected_code) - - if KEEP_GOING: - r += " \033[%dmFAILED\033[0m (%s)" % (color, msg) - failed.append(fn) - return r - else: - raise Exception("%s\n%s\n%s" % (msg, err, full_err)) - elif out != expected_out: - if KEEP_GOING: - r += " \033[31mFAILED\033[0m (bad output)" - failed.append(fn) - return r - exp_fd, exp_fn = tempfile.mkstemp() - out_fd, out_fn = tempfile.mkstemp() - os.fdopen(exp_fd, 'w').write(expected_out) - os.fdopen(out_fd, 'w').write(out) - p = subprocess.Popen(["diff", "-a", exp_fn, out_fn], stdout=subprocess.PIPE, preexec_fn=set_ulimits) - diff = p.stdout.read() - assert p.wait() in (0, 1) - raise Exception("Failed on %s:\n%s" % (fn, diff)) - elif err != expected_err: - raise Exception((err, expected_err)) - r += " Correct output (%5.1fms)" % (elapsed * 1000,) - - if check_stats: - for l in statchecks: - test = eval(l) - if not test: - if KEEP_GOING: - r += " \033[31mFailed statcheck\033[0m" - failed.append(fn) - return r - else: - m = re.match("""stats\[['"]([\w_]+)['"]]""", l) - if m: - statname = m.group(1) - raise Exception((l, statname, stats[statname])) - raise Exception((l, stats)) - else: - r += " (ignoring stats)" - - if run_memcheck: - if code == 0: - start = time.time() - p = subprocess.Popen(["valgrind", "--tool=memcheck", "--leak-check=no"] + run_args, stdout=open("/dev/null", 'w'), stderr=subprocess.PIPE, stdin=open("/dev/null")) - out, err = p.communicate() - assert p.wait() == 0 - if "Invalid read" not in err: - elapsed = (time.time() - start) - r += " Memcheck passed (%4.1fs)" % (elapsed,) - else: - if KEEP_GOING: - r += " \033[31mMEMCHECKS FAILED\033[0m" - failed.append(fn) - return r - else: - raise Exception(err) - else: - r += " (Skipping memchecks) " - - return r - -q = Queue.Queue() -cv = threading.Condition() -results = {} -quit = {} -def worker_thread(): - while not quit: - try: - job = q.get() - if job is None: - break - - results[job[0]] = run_test(*job) - with cv: - cv.notifyAll() - except: - import traceback - # traceback.print_exc() - results[job[0]] = None - quit[job[0]] = job[0] + ':\n' + traceback.format_exc() - with cv: - cv.notifyAll() - # os._exit(-1) - -def verify_include(_, dir, files): - for bn in files: - fn = os.path.join(dir, bn) - - if bn.endswith(".h") or bn.endswith(".cpp"): - s = open(fn).read(1024) - assert "Copyright (c) 2014 Dropbox, Inc." in s, fn - assert "Apache License, Version 2.0" in s, fn - - if not bn.endswith(".h"): - continue - - expected_guard = "PYSTON" + fn[1:-2].replace('_', '').replace('/', '_').upper() + "_H" - with open(fn) as f: - while True: - l = f.readline() - if l.startswith('//') or not l.strip(): - continue - break - gotten_guard = l.split()[1] - assert gotten_guard == expected_guard, (fn, gotten_guard, expected_guard) - -def fileSize(fn): - return os.stat(fn).st_size - # return len(list(open(fn))) - -if __name__ == "__main__": - os.path.walk('.', verify_include, None) - - run_memcheck = False - start = 1 - - opts, patterns = getopt.getopt(sys.argv[1:], "j:a:t:mRPk") - for (t, v) in opts: - if t == '-m': - run_memcheck = True - elif t == '-j': - NUM_THREADS = int(v) - assert NUM_THREADS > 0 - elif t == '-R': - IMAGE = "pyston" - elif t == '-P': - IMAGE = "pyston_prof" - elif t == '-k': - KEEP_GOING = True - elif t == '-a': - EXTRA_JIT_ARGS.append(v) - elif t == '-t': - TIME_LIMIT = int(v) - else: - raise Exception((t, v)) - - TEST_DIR = patterns[0] - patterns = patterns[1:] - - TOSKIP = ["%s/%s.py" % (TEST_DIR, i) for i in ( - "tuple_depth", - "longargs_stackusage", - )] - - IGNORE_STATS = ["%s/%d.py" % (TEST_DIR, i) for i in ( - )] + [ - ] - - def _addto(l, tests): - if isinstance(tests, str): - tests = [tests] - for t in tests: - l.append("%s/%s.py" % (TEST_DIR, t)) - skip = functools.partial(_addto, TOSKIP) - nostat = functools.partial(_addto, IGNORE_STATS) - - if '-O' in EXTRA_JIT_ARGS: - # OSR test, doesn't make sense with -O - skip(["30"]) - - if datetime.datetime.now() < datetime.datetime(2014,4,28): - nostat(["nondirectly_callable_ics"]) # WIP - skip(["finalization_cycles", "resurrection", "nonself_resurrection"]) # WIP - - if '-O' in EXTRA_JIT_ARGS: - # Have guard issues: - skip(["dict", "tuple_iteration"]) - - if datetime.datetime.now() < datetime.datetime(2014,4,28): - skip(["class_noctor", "non_function_ctors"]) # object.__new__ - skip(["setattr_patching_under"]) # requires __del__ - - if datetime.datetime.now() < datetime.datetime(2014,5,1): - # varargs - skip([57, 61]) - # arbitrary stuff in classes - skip([56, "classdef_arbitrary", "scoping_classes", "return_in_class"]) - # sequence comparisons - skip(["comparisons_more"]) - - if datetime.datetime.now() < datetime.datetime(2014,5,1): - # Metaclass tests - skip([46, 55]) - - if datetime.datetime.now() < datetime.datetime(2014,5,1): - # random tests that aren't too important right now: - skip([54, 65, 66, 69, 70, 72, "many_attrs_setattr", "for_iter", "none_not_settable", "math_more", "global_and_local", "metaclass_parent", "class_freeing_time", "xrange", "binops_subclass", "class_changing"]) - - if not patterns: - skip(["t", "t2"]) - - def tryParse(s): - if s.isdigit(): - return int(s) - return s - def key(name): - i = tryParse(name) - if i < start: - return i + 100000 - return i - - tests = sorted([t for t in glob.glob("%s/*.py" % TEST_DIR)], key=lambda t:key(t[6:-3])) - tests += [ - ] - big_tests = [ - ] - tests += big_tests - - for t in TOSKIP: - assert t in ("%s/t.py" % TEST_DIR, "%s/t2.py" % TEST_DIR) or t in tests, t - - if patterns: - filtered_tests = [] - for t in tests: - if any(re.match("%s/%s.*\.py" % (TEST_DIR, p), t) for p in patterns): - filtered_tests.append(t) - tests = filtered_tests - if not tests: - print >>sys.stderr, "No tests specified!" - sys.exit(1) - - FN_JUST_SIZE = max(20, 2 + max(map(len, tests))) - - print "Building...", - sys.stdout.flush() - subprocess.check_call(["make", "-j4", IMAGE], stdout=open("/dev/null", 'w'), stderr=subprocess.PIPE) - print "done" - - tests.sort(key=fileSize) - - for fn in tests: - if fn in TOSKIP: - continue - check_stats = fn not in IGNORE_STATS - q.put((fn, check_stats, run_memcheck)) - - threads = [] - for i in xrange(NUM_THREADS): - t = threading.Thread(target=worker_thread) - t.setDaemon(True) - t.start() - threads.append(t) - q.put(None) - - for fn in tests: - if fn in TOSKIP: - print fn.rjust(FN_JUST_SIZE), - print " Skipping" - continue - - with cv: - while fn not in results: - try: - cv.wait(1) - except KeyboardInterrupt: - print >>sys.stderr, "Interrupted" - sys.exit(1) - - if results[fn] is None: - assert quit - print quit.pop(fn).strip() - for fn, s in quit.items(): - print "(%s also failed)" % fn - sys.exit(1) - break - print results[fn] - - for t in threads: - t.join() - - if failed: - sys.exit(1)