From e225e4720610c9856f08f5626015a039233d4b86 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Sat, 22 Oct 2016 08:10:21 -0400 Subject: [PATCH 01/13] Add unreleased section to CHANGELOG post 0.7.0 release prep --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d2339f866..9b2b4c3d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to the Pony compiler and standard library will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a CHANGELOG](http://keepachangelog.com/). +## [unreleased] - unreleased + +### Fixed + +### Added + +### Changed + ## [0.7.0] - 2016-10-22 ### Fixed From dcadf4ab59609cb033a19536dba26f19a5e96348 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Sun, 23 Oct 2016 11:07:13 -0400 Subject: [PATCH 02/13] Run tests sequentially See if this solves our flakey test problem. My theory is that we have failing tests because, we are running more tests and have more contention on the scheduler so we are more likely to hit timeouts. If flakey tests disappear when running sequentially then adding a facility to exclude certain groups from tests would work well. Something like: run all tests except X, Y, Z "groups" run X run Y run Z This could be jammed into existing label and exclusion group support but I think that address it head on via some new addition to PonyTest would make sense. This initial commit to test sequentiality is meant to: * Verify that it doesn't take too long to run all our tests in a sequential fashion * Verify that running sequentially fixes our problem If this commit doesn't increase CI times by too much, I'll merge it and we can observe if it starts fixing the flakey test issue. If it does, we can proceed from there. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bb5cf43309..2cd82ae176 100644 --- a/Makefile +++ b/Makefile @@ -636,10 +636,10 @@ test-ci: all @$(PONY_BUILD_DIR)/libponyc.tests @$(PONY_BUILD_DIR)/libponyrt.tests @$(PONY_BUILD_DIR)/ponyc -d -s --verify packages/stdlib - @./stdlib + @./stdlib --sequential @rm stdlib @$(PONY_BUILD_DIR)/ponyc --verify packages/stdlib - @./stdlib + @./stdlib --sequential @rm stdlib @PONYPATH=. $(PONY_BUILD_DIR)/ponyc -d -s examples @./examples1 From f2082f8fdf4ef0cba5e4462484801d6010512f27 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Sun, 23 Oct 2016 11:07:13 -0400 Subject: [PATCH 03/13] Run tests sequentially See if this solves our flakey test problem. My theory is that we have failing tests because, we are running more tests and have more contention on the scheduler so we are more likely to hit timeouts. If flakey tests disappear when running sequentially then adding a facility to exclude certain groups from tests would work well. Something like: run all tests except X, Y, Z "groups" run X run Y run Z This could be jammed into existing label and exclusion group support but I think that address it head on via some new addition to PonyTest would make sense. This initial commit to test sequentiality is meant to: * Verify that it doesn't take too long to run all our tests in a sequential fashion * Verify that running sequentially fixes our problem If this commit doesn't increase CI times by too much, I'll merge it and we can observe if it starts fixing the flakey test issue. If it does, we can proceed from there. --- .appveyor.yml | 4 ++-- Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0aa9300397..f3ee1b65e0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -129,10 +129,10 @@ test_script: - C:\projects\ponyc\build\%CONFIGURATION%\testrt.exe - CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\vcvars64.bat" - C:\projects\ponyc\build\%CONFIGURATION%\ponyc.exe -V 3 -o C:\projects\ponyc\ -d -s --verify packages/stdlib - - stdlib.exe + - stdlib.exe --sequential - del stdlib.exe - C:\projects\ponyc\build\%CONFIGURATION%\ponyc.exe -V 3 -o C:\projects\ponyc\ --verify packages/stdlib - - stdlib.exe + - stdlib.exe --sequential - del stdlib.exe - C:\projects\ponyc\build\%CONFIGURATION%\ponyc.exe -V 3 -o C:\projects\ponyc\ -d -s --verify examples - examples.exe diff --git a/Makefile b/Makefile index 2cd82ae176..fef25c5a8b 100644 --- a/Makefile +++ b/Makefile @@ -624,7 +624,7 @@ test: all @$(PONY_BUILD_DIR)/libponyc.tests @$(PONY_BUILD_DIR)/libponyrt.tests @$(PONY_BUILD_DIR)/ponyc -d -s --verify packages/stdlib - @./stdlib + @./stdlib --sequential @rm stdlib test-examples: all From 038d6e2ae50bf869efc2770ab95bdb6bfb757639 Mon Sep 17 00:00:00 2001 From: Benoit Vey Date: Tue, 25 Oct 2016 03:34:26 +0200 Subject: [PATCH 04/13] Add pony_send_next runtime function (#1361) This new function allows switching to a new message when tracing message contents before sending. The two following code snippets are equivalent. pony_gc_send(ctx); | pony_gc_send(ctx); pony_trace(ctx, obj); | pony_trace(ctx, obj); pony_send_done(); | pony_send_next(ctx); pony_sendp(ctx, to, mid, obj); | pony_trace(ctx, obj2); pony_gc_send(ctx); | pony_send_done(); pony_trace(ctx, obj2); | pony_sendp(ctx, to, mid, obj); pony_send_done(); | pony_sendp(ctx, to2, mid2, obj2); pony_sendp(ctx, to2, mid2, obj2); | Using pony_send_next can reduce the amount of GC acquire messages that must be sent. Using the function never results in more work being performed. An optimisation pass taking advantage of this function will be added to the compiler in the future. --- CHANGELOG.md | 2 ++ src/libponyrt/gc/trace.c | 6 ++++++ src/libponyrt/pony.h | 11 +++++++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b2b4c3d68..f2580b036b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to the Pony compiler and standard library will be documented ### Added +- Runtime function `pony_send_next`. This function can help optimise some message sending scenarios. + ### Changed ## [0.7.0] - 2016-10-22 diff --git a/src/libponyrt/gc/trace.c b/src/libponyrt/gc/trace.c index 1836f72f83..fa1ad1773f 100644 --- a/src/libponyrt/gc/trace.c +++ b/src/libponyrt/gc/trace.c @@ -85,6 +85,12 @@ void pony_release_done(pony_ctx_t* ctx) ponyint_gc_done(ponyint_actor_gc(ctx->current)); } +void pony_send_next(pony_ctx_t* ctx) +{ + ponyint_gc_handlestack(ctx); + ponyint_gc_done(ponyint_actor_gc(ctx->current)); +} + void pony_trace(pony_ctx_t* ctx, void* p) { ctx->trace_object(ctx, p, NULL, PONY_TRACE_OPAQUE); diff --git a/src/libponyrt/pony.h b/src/libponyrt/pony.h index 280afcef6d..25469f99d2 100644 --- a/src/libponyrt/pony.h +++ b/src/libponyrt/pony.h @@ -267,6 +267,17 @@ void pony_acquire_done(pony_ctx_t* ctx); */ void pony_release_done(pony_ctx_t* ctx); +/** Continue gc tracing with another message. + * + * When sending multiple messages following each other, you can use this + * function to trace the content of every message in one + * pony_gc_send/pony_send_done round instead of doing one pair of calls for each + * message. Call pony_send_next before tracing the content of a new message. + * Using this function can reduce the amount of gc-specific messages + * sent. + */ +void pony_send_next(pony_ctx_t* ctx); + /** Identifiers for reference capabilities when tracing. * * At runtime, we need to identify if the object is logically mutable, From e519c41426dd0111303081dc5b28f754bb49019a Mon Sep 17 00:00:00 2001 From: Benoit Vey Date: Tue, 25 Oct 2016 02:37:35 +0200 Subject: [PATCH 05/13] Link libponyrt correctly with --pic on Linux The normal version of libponyrt was linked even when compiling with --pic. Now, libponyrt-pic is linked when appropriate. Closes #1359. --- CHANGELOG.md | 2 ++ Makefile | 15 +++++++++++++++ src/libponyc/codegen/genexe.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2580b036b..37cf2d067a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to the Pony compiler and standard library will be documented ### Fixed +- Link the correct version of `libponyrt` when compiling with `--pic` on Linux (issue #1359) + ### Added - Runtime function `pony_send_next`. This function can help optimise some message sending scenarios. diff --git a/Makefile b/Makefile index fef25c5a8b..cf058f27cf 100644 --- a/Makefile +++ b/Makefile @@ -580,6 +580,9 @@ install: libponyc libponyrt ponyc @mkdir -p $(destdir)/lib @mkdir -p $(destdir)/include/pony/detail $(SILENT)cp $(PONY_BUILD_DIR)/libponyrt.a $(destdir)/lib +ifeq ($(OSTYPE),linux) + $(SILENT)cp $(PONY_BUILD_DIR)/libponyrt-pic.a $(destdir)/lib +endif ifneq ($(wildcard $(PONY_BUILD_DIR)/libponyrt.bc),) $(SILENT)cp $(PONY_BUILD_DIR)/libponyrt.bc $(destdir)/lib endif @@ -594,6 +597,9 @@ ifeq ($$(symlink),yes) @mkdir -p $(prefix)/include/pony/detail $(SILENT)ln $(symlink.flags) $(destdir)/bin/ponyc $(prefix)/bin/ponyc $(SILENT)ln $(symlink.flags) $(destdir)/lib/libponyrt.a $(prefix)/lib/libponyrt.a +ifeq ($(OSTYPE),linux) + $(SILENT)ln $(symlink.flags) $(destdir)/lib/libponyrt-pic.a $(prefix)/lib/libponyrt-pic.a +endif ifneq ($(wildcard $(destdir)/lib/libponyrt.bc),) $(SILENT)ln $(symlink.flags) $(destdir)/lib/libponyrt.bc $(prefix)/lib/libponyrt.bc endif @@ -610,6 +616,9 @@ uninstall: -$(SILENT)rm -rf $(destdir) 2>/dev/null ||: -$(SILENT)rm $(prefix)/bin/ponyc 2>/dev/null ||: -$(SILENT)rm $(prefix)/lib/libponyrt.a 2>/dev/null ||: +ifeq ($(OSTYPE),linux) + -$(SILENT)rm $(prefix)/lib/libponyrt-pic.a 2>/dev/null ||: +endif ifneq ($(wildcard $(prefix)/lib/libponyrt.bc),) -$(SILENT)rm $(prefix)/lib/libponyrt.bc 2>/dev/null ||: endif @@ -661,6 +670,9 @@ deploy: test @mkdir -p $(package)/usr/lib/pony/$(package_version)/lib $(SILENT)cp build/release/libponyc.a $(package)/usr/lib/pony/$(package_version)/lib $(SILENT)cp build/release/libponyrt.a $(package)/usr/lib/pony/$(package_version)/lib +ifeq ($(OSTYPE),linux) + $(SILENT)cp build/release/libponyrt-pic.a $(package)/usr/lib/pony/$(package_version)/lib +endif ifneq ($(wildcard build/release/libponyrt.bc),) $(SILENT)cp build/release/libponyrt.bc $(package)/usr/lib/pony/$(package_version)/lib endif @@ -668,6 +680,9 @@ endif $(SILENT)cp src/libponyrt/pony.h $(package)/usr/lib/pony/$(package_version)/include $(SILENT)cp src/common/pony/detail/atomics.h $(package)/usr/lib/pony/$(package_version)/include/pony/detail $(SILENT)ln -s /usr/lib/pony/$(package_version)/lib/libponyrt.a $(package)/usr/lib/libponyrt.a +ifeq ($(OSTYPE),linux) + $(SILENT)ln -s /usr/lib/pony/$(package_version)/lib/libponyrt-pic.a $(package)/usr/lib/libponyrt-pic.a +endif ifneq ($(wildcard /usr/lib/pony/$(package_version)/lib/libponyrt.bc),) $(SILENT)ln -s /usr/lib/pony/$(package_version)/lib/libponyrt.bc $(package)/usr/lib/libponyrt.bc endif diff --git a/src/libponyc/codegen/genexe.c b/src/libponyc/codegen/genexe.c index d04ab1509e..650409b549 100644 --- a/src/libponyc/codegen/genexe.c +++ b/src/libponyc/codegen/genexe.c @@ -207,6 +207,8 @@ static bool link_exe(compile_t* c, ast_t* program, const char* ponyrt = c->opt->runtimebc ? "" : #if defined(PLATFORM_IS_WINDOWS) "ponyrt.lib"; +#elif defined(PLATFORM_IS_LINUX) + c->opt->pic ? "-lponyrt-pic" : "-lponyrt"; #else "-lponyrt"; #endif From f1d0ff39493dd69ad5c05fb641b702956c612637 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Tue, 25 Oct 2016 11:25:00 -0400 Subject: [PATCH 06/13] Clarify lambda interface to map.upsert (#1363) The current example is unclear as to which value is the old value and which is the new value when setting up the lambda. By switching from addition to subtraction in the example, this becomes clear. This documentation could be improved further but this is a decent start towards resolving that possible confusion without having to look at the source code. --- packages/collections/map.pony | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/collections/map.pony b/packages/collections/map.pony index 5dbc6d6fcd..ef0709be5f 100644 --- a/packages/collections/map.pony +++ b/packages/collections/map.pony @@ -87,19 +87,19 @@ class HashMap[K, V, H: HashFunction[K] val] using the provided function. If the provided key has not been added to the map yet, it sets its value to the provided value. - As a simple example, say we had a map with U64 values and we wanted to + As a simple example, say we had a map with I64 values and we wanted to add 4 to the current value for key "test", which let's say is currently 2. We call - m.upsert("test", 4, lambda(x: U64, y: U64): U64 => x + y end) + m.upsert("test", 4, lambda(x: I64, y: I64): I64 => x - y end) - This changes the value associated with "test" to 6. + This changes the value associated with "test" to -2. If we have not yet added the key "new-key" to the map and we call - m.upsert("new-key", 4, lambda(x: U64, y: U64): U64 => x + y end) + m.upsert("new-key", 4, lambda(x: I64, y: I64): I64 => x - y end) - then "new-key" is added to the map with a value of 4. + then "new-key" is added to the map with a value of -4. Returns the value that we set the key to """ From 349af4ea32ee25bbc67fd119d36e164f98c0d49e Mon Sep 17 00:00:00 2001 From: Benoit Vey Date: Wed, 26 Oct 2016 04:32:43 +0200 Subject: [PATCH 07/13] Test against LLVM 3.8.1 instead of 3.8.0 in CI (#1366) --- .appveyor.yml | 2 +- .travis.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f3ee1b65e0..d4d9ce4a5d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,7 +10,7 @@ branches: environment: matrix: - llvm: 3.9.0 - - llvm: 3.8.0 + - llvm: 3.8.1 - llvm: 3.7.1 configuration: diff --git a/.travis.yml b/.travis.yml index 1dc206d50e..163300c6fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ matrix: packages: - g++-5 env: - - LLVM_VERSION="3.8.0" + - LLVM_VERSION="3.8.1" - LLVM_CONFIG="llvm-config-3.8" - config=debug - CC1=gcc-5 @@ -83,7 +83,7 @@ matrix: packages: - g++-5 env: - - LLVM_VERSION="3.8.0" + - LLVM_VERSION="3.8.1" - LLVM_CONFIG="llvm-config-3.8" - config=release - CC1=gcc-5 From 7c0b6e57802a8b78a0ca6b671886a22cc5ae6792 Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Wed, 26 Oct 2016 11:40:31 -0400 Subject: [PATCH 08/13] Fix broken `make clean` (#1367) dtrace_probes.h won't always be present. Use `-f` to remove if present and otherwise, don't error out. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cf058f27cf..074ce388d3 100644 --- a/Makefile +++ b/Makefile @@ -719,7 +719,7 @@ stats: clean: @rm -rf $(PONY_BUILD_DIR) - @rm src/common/dtrace_probes.h + @rm -f src/common/dtrace_probes.h -@rmdir build 2>/dev/null ||: @echo 'Repository cleaned ($(PONY_BUILD_DIR)).' From 1fa81ebdb8583c39f35de042669bf10f71ffbb83 Mon Sep 17 00:00:00 2001 From: Theo Butler Date: Wed, 26 Oct 2016 13:34:47 -0400 Subject: [PATCH 09/13] Update Dockerfile to use LLVM 3.9 (#1368) The Dockerfile was using the apt package llvm-dev which installed llvm 3.8.0. This change will Install the prebuilt binary of llvm 3.9.0 instead. --- Dockerfile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index eb80f87135..42a6728fba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,14 @@ FROM ubuntu:16.04 RUN apt-get update \ - && apt-get install -y make g++ git \ + && apt-get install -y make g++ git wget xz-utils \ zlib1g-dev libncurses5-dev libssl-dev \ - llvm-dev libpcre2-dev \ - && rm -rf /var/lib/apt/lists/* + libpcre2-dev \ + && rm -rf /var/lib/apt/lists/* \ + && wget http://llvm.org/releases/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz \ + && tar xf clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz \ + && cp -r clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04/* /usr/local \ + && rm -rf /clang* WORKDIR /src/ponyc COPY Makefile LICENSE VERSION /src/ponyc/ @@ -13,10 +17,11 @@ COPY lib /src/ponyc/lib COPY test /src/ponyc/test COPY packages /src/ponyc/packages -RUN make config=release install \ +RUN make \ + && make install \ && rm -rf /src/ponyc/build RUN mkdir /src/main -WORKDIR /src/main +WORKDIR /src/main CMD ponyc From 8711949f88423885011d96d41eeaf2428bc7b798 Mon Sep 17 00:00:00 2001 From: Fernando Ribeiro Date: Wed, 26 Oct 2016 19:39:54 -0200 Subject: [PATCH 10/13] Add AVX2 support requirement (#1369) Added a note about the binaries requiring AVX2 support. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58aa8f0b9e..447edab90c 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,6 @@ Or, for master builds: yum install ponyc-master ``` - ## Linux using a DEB package (via Bintray) For Ubuntu or Debian Linux, the `master` and `release` branches are packaged and availabe on Bintray ([pony-language/ponyc-debian](https://bintray.com/pony-language/ponyc-debian)). @@ -97,7 +96,6 @@ Or, for master builds: sudo apt-get install ponyc-master ``` - ## Windows using ZIP (via Bintray) For Windows, the `master` and `release` branches are packaged and availabe on Bintray ([pony-language/ponyc-win](https://bintray.com/pony-language/ponyc-win)): @@ -390,13 +388,16 @@ $ make LTO_PLUGIN=/usr/lib/LLVMgold.so Refer to your compiler documentation for the plugin to use in your case. - ## VirtualBox Pony binaries can trigger illegal instruction errors under VirtualBox 4.x, for at least the x86_64 platform and possibly others. Use VirtualBox 5.x to avoid possible problems. +## AVX2 Support + +The Pony prebuilt binaries trigger illegal instruction errors under CPUs without [AVX2](https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2) support. + ## Building Pony on Non-x86 platforms On ARM platforms, the default gcc architecture specification used in the Makefile of _native_ does not work correctly, and can even result in the gcc compiler crashing. You will have to override the compiler architecture specification on the _make_ command line. For example, on a RaspberryPi2 you would say: From 4dbf835289f76fc7737b19b0dc30a10e71ecec96 Mon Sep 17 00:00:00 2001 From: Benoit Vey Date: Thu, 27 Oct 2016 08:42:23 +0200 Subject: [PATCH 11/13] Rename FloatingPoint min_value to min_normalised (#1371) min_value was previously returning the smallest normalised positive number, which wasn't consistent with min_value on integers. min_value now returns the smallest negative number, and a min_normalised function returning the smallest normalised positive number has been added. Closes #1351. --- CHANGELOG.md | 3 +++ packages/builtin/float.pony | 24 ++++++++++++++++++------ packages/builtin/real.pony | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37cf2d067a..855dda5948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,12 @@ All notable changes to the Pony compiler and standard library will be documented ### Added - Runtime function `pony_send_next`. This function can help optimise some message sending scenarios. +- Floating point `min_normalised`. The function returns the smallest normalised positive number, as `min_value` used to do (issue #1351) ### Changed +- Floating point `min_value` now returns the smallest negative number instead of the smallest normalised positive number (issue #1351) + ## [0.7.0] - 2016-10-22 ### Fixed diff --git a/packages/builtin/float.pony b/packages/builtin/float.pony index c8f45f272e..e36c8bcd94 100644 --- a/packages/builtin/float.pony +++ b/packages/builtin/float.pony @@ -11,10 +11,9 @@ primitive F32 is FloatingPoint[F32] new min_value() => """ - Minimum positive value representable at full precision (ie a normalised - number). + Minimum negative value representable. """ - from_bits(0x00800000) + from_bits(0xFF7FFFFF) new max_value() => """ @@ -22,6 +21,13 @@ primitive F32 is FloatingPoint[F32] """ from_bits(0x7F7FFFFF) + new min_normalised() => + """ + Minimum positive value representable at full precision (ie a normalised + number). + """ + from_bits(0x00800000) + new epsilon() => """ Minimum positive value such that (1 + epsilon) != 1. @@ -173,10 +179,9 @@ primitive F64 is FloatingPoint[F64] new min_value() => """ - Minimum positive value representable at full precision (ie a normalised - number). + Minimum negative value representable. """ - from_bits(0x0010_0000_0000_0000) + from_bits(0xFFEF_FFFF_FFFF_FFFF) new max_value() => """ @@ -184,6 +189,13 @@ primitive F64 is FloatingPoint[F64] """ from_bits(0x7FEF_FFFF_FFFF_FFFF) + new min_normalised() => + """ + Minimum positive value representable at full precision (ie a normalised + number). + """ + from_bits(0x0010_0000_0000_0000) + new epsilon() => """ Minimum positive value such that (1 + epsilon) != 1. diff --git a/packages/builtin/real.pony b/packages/builtin/real.pony index 6fe409cff5..b2f89a764b 100644 --- a/packages/builtin/real.pony +++ b/packages/builtin/real.pony @@ -83,6 +83,7 @@ trait val _UnsignedInteger[A: _UnsignedInteger[A] val] is Integer[A] _ToString._u64(u64(), false) trait val FloatingPoint[A: FloatingPoint[A] val] is Real[A] + new val min_normalised() new val epsilon() fun tag radix(): U8 fun tag precision2(): U8 From f9591b2ed4ee95b5db181574c030da22531a13ad Mon Sep 17 00:00:00 2001 From: Benoit Vey Date: Thu, 27 Oct 2016 08:42:44 +0200 Subject: [PATCH 12/13] Trace message contents in the sender context (#1364) This change inlines message tracing and sending in caller functions. It will allow tracing the most precise object type possible, for performance. If the call is made through an interface and it cannot be proven that it is a message send, a virtual call is made. --- src/libponyc/codegen/gencall.c | 214 +++++++++++++++++++++++++++----- src/libponyc/codegen/gencall.h | 3 + src/libponyc/codegen/genfun.c | 166 +++++++++---------------- src/libponyc/codegen/genprim.c | 4 +- src/libponyc/codegen/gentrace.c | 125 +++++++++++++++---- src/libponyc/codegen/gentrace.h | 5 +- src/libponyc/codegen/gentype.c | 2 +- src/libponyc/reach/reach.h | 1 + 8 files changed, 350 insertions(+), 170 deletions(-) diff --git a/src/libponyc/codegen/gencall.c b/src/libponyc/codegen/gencall.c index f992b54a35..70e3d6f819 100644 --- a/src/libponyc/codegen/gencall.c +++ b/src/libponyc/codegen/gencall.c @@ -6,6 +6,7 @@ #include "genfun.h" #include "genname.h" #include "genopt.h" +#include "gentrace.h" #include "../pkg/platformfuns.h" #include "../type/cap.h" #include "../type/subtype.h" @@ -167,12 +168,8 @@ static bool special_case_call(compile_t* c, ast_t* ast, LLVMValueRef* value) } static LLVMValueRef dispatch_function(compile_t* c, reach_type_t* t, - ast_t* type, LLVMValueRef l_value, const char* method_name, ast_t* typeargs) + reach_method_t* m, LLVMValueRef l_value) { - token_id cap = cap_dispatch(type); - reach_method_t* m = reach_method(t, cap, method_name, typeargs); - assert(m != NULL); - switch(t->underlying) { case TK_UNIONTYPE: @@ -300,7 +297,9 @@ LLVMValueRef gen_funptr(compile_t* c, ast_t* ast) assert(t != NULL); const char* name = ast_name(method); - LLVMValueRef funptr = dispatch_function(c, t, type, value, name, typeargs); + token_id cap = cap_dispatch(type); + reach_method_t* m = reach_method(t, cap, name, typeargs); + LLVMValueRef funptr = dispatch_function(c, t, m, value); if(c->linkage != LLVMExternalLinkage) { @@ -329,6 +328,69 @@ LLVMValueRef gen_funptr(compile_t* c, ast_t* ast) return funptr; } +void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[], + ast_t* args_ast) +{ + // Allocate the message, setting its size and ID. + size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, m->msg_type); + LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0); + + LLVMValueRef msg_args[3]; + + msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); + msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); + LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); + LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); + + for(unsigned int i = 0; i < m->param_count; i++) + { + LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); + LLVMBuildStore(c->builder, args[i+1], arg_ptr); + } + + // Trace while populating the message contents. + ast_t* params = ast_childidx(m->r_fun, 3); + ast_t* param = ast_child(params); + ast_t* arg_ast = ast_child(args_ast); + bool need_trace = false; + + while(param != NULL) + { + if(gentrace_needed(c, ast_type(arg_ast), ast_type(param))) + { + need_trace = true; + break; + } + + param = ast_sibling(param); + arg_ast = ast_sibling(arg_ast); + } + + LLVMValueRef ctx = codegen_ctx(c); + + if(need_trace) + { + gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); + param = ast_child(params); + arg_ast = ast_child(args_ast); + + for(size_t i = 0; i < m->param_count; i++) + { + gentrace(c, ctx, args[i+1], ast_type(arg_ast), ast_type(param)); + param = ast_sibling(param); + arg_ast = ast_sibling(arg_ast); + } + + gencall_runtime(c, "pony_send_done", &ctx, 1, ""); + } + + // Send the message. + msg_args[0] = ctx; + msg_args[1] = LLVMBuildBitCast(c->builder, args[0], c->object_ptr, ""); + msg_args[2] = msg; + gencall_runtime(c, "pony_sendv", msg_args, 3, ""); +} + typedef struct call_tuple_indices_t { size_t* data; @@ -357,6 +419,57 @@ static size_t tuple_indices_pop(call_tuple_indices_t* ti) return ti->data[--ti->count]; } +static bool behaviour_in_every_subtype(reach_type_t* t, const char* method_name) +{ + switch(t->underlying) + { + case TK_CLASS: + case TK_STRUCT: + case TK_PRIMITIVE: + return false; + + case TK_ACTOR: + return true; + + default: {} + } + + size_t i = HASHMAP_BEGIN; + reach_type_t* sub = t; + do + { + reach_method_name_t* n = reach_method_name(sub, method_name); + + if(n == NULL) + continue; + + size_t j = HASHMAP_BEGIN; + // The kind of a method cannot vary within a type so we only need to check + // one reach method. + reach_method_t* m = reach_methods_next(&n->r_methods, &j); + + if(m == NULL) + continue; + + if(ast_id(m->r_fun) == TK_FUN) + return false; + + if(ast_id(m->r_fun) == TK_NEW) + { + switch(sub->underlying) + { + case TK_CLASS: + case TK_PRIMITIVE: + return false; + + default: {} + } + } + } while((sub = reach_type_cache_next(&t->subtypes, &i)) != NULL); + + return true; +} + LLVMValueRef gen_call(compile_t* c, ast_t* ast) { // Special case calls. @@ -500,8 +613,30 @@ LLVMValueRef gen_call(compile_t* c, ast_t* ast) } // Static or virtual dispatch. - LLVMValueRef func = dispatch_function(c, t, type, args[0], method_name, - typeargs); + token_id cap = cap_dispatch(type); + reach_method_t* m = reach_method(t, cap, method_name, typeargs); + LLVMValueRef func = dispatch_function(c, t, m, args[0]); + + bool is_message = false; + + if((ast_id(postfix) == TK_NEWBEREF) || (ast_id(postfix) == TK_BEREF)) + { + switch(t->underlying) + { + case TK_ACTOR: + is_message = true; + break; + + case TK_UNIONTYPE: + case TK_ISECTTYPE: + case TK_INTERFACE: + case TK_TRAIT: + is_message = behaviour_in_every_subtype(t, method_name); + break; + + default: {} + } + } // Cast the arguments to the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); @@ -511,33 +646,53 @@ LLVMValueRef gen_call(compile_t* c, ast_t* ast) arg = ast_child(positional); i = 1; - while(arg != NULL) - { - args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg));; - arg = ast_sibling(arg); - i++; - } - LLVMValueRef r = NULL; - if(func != NULL) + if(is_message) { - // If we can error out and we have an invoke target, generate an invoke - // instead of a call. - codegen_debugloc(c, ast); + // If we're sending a message, trace and send here instead of calling the + // sender to trace the most specific types possible. + while(arg != NULL) + { + args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); + arg = ast_sibling(arg); + i++; + } - if(ast_canerror(ast) && (c->frame->invoke_target != NULL)) - r = invoke_fun(c, func, args, i, "", true); - else - r = codegen_call(c, func, args, i); + token_id cap = cap_dispatch(type); + reach_method_t* m = reach_method(t, cap, method_name, typeargs); - if(is_new_call) + codegen_debugloc(c, ast); + gen_send_message(c, m, args, positional); + codegen_debugloc(c, NULL); + r = args[0]; + } else { + while(arg != NULL) { - LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); - LLVMSetMetadataStr(r, "pony.newcall", md); + args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg)); + arg = ast_sibling(arg); + i++; } - codegen_debugloc(c, NULL); + if(func != NULL) + { + // If we can error out and we have an invoke target, generate an invoke + // instead of a call. + codegen_debugloc(c, ast); + + if(ast_canerror(ast) && (c->frame->invoke_target != NULL)) + r = invoke_fun(c, func, args, i, "", true); + else + r = codegen_call(c, func, args, i); + + if(is_new_call) + { + LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); + LLVMSetMetadataStr(r, "pony.newcall", md); + } + + codegen_debugloc(c, NULL); + } } // Class constructors return void, expression result is the receiver. @@ -594,8 +749,9 @@ LLVMValueRef gen_pattern_eq(compile_t* c, ast_t* pattern, LLVMValueRef r_value) assert(t != NULL); // Static or virtual dispatch. - LLVMValueRef func = dispatch_function(c, t, pattern_type, l_value, - c->str_eq, NULL); + token_id cap = cap_dispatch(pattern_type); + reach_method_t* m = reach_method(t, cap, c->str_eq, NULL); + LLVMValueRef func = dispatch_function(c, t, m, l_value); if(func == NULL) return NULL; diff --git a/src/libponyc/codegen/gencall.h b/src/libponyc/codegen/gencall.h index 71865a0773..e1805f9ee9 100644 --- a/src/libponyc/codegen/gencall.h +++ b/src/libponyc/codegen/gencall.h @@ -6,6 +6,9 @@ PONY_EXTERN_C_BEGIN +void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[], + ast_t* args_ast); + LLVMValueRef gen_funptr(compile_t* c, ast_t* ast); LLVMValueRef gen_call(compile_t* c, ast_t* ast); diff --git a/src/libponyc/codegen/genfun.c b/src/libponyc/codegen/genfun.c index 175e9b3b45..b4f4395e5c 100644 --- a/src/libponyc/codegen/genfun.c +++ b/src/libponyc/codegen/genfun.c @@ -135,6 +135,7 @@ static void make_prototype(compile_t* c, reach_type_t* t, // Behaviours and actor constructors also have handler functions. bool handler = false; + bool only_needs_msg_type = false; switch(ast_id(m->r_fun)) { @@ -159,32 +160,52 @@ static void make_prototype(compile_t* c, reach_type_t* t, case TK_ACTOR: break; + case TK_UNIONTYPE: + case TK_ISECTTYPE: + case TK_INTERFACE: + case TK_TRAIT: + only_needs_msg_type = true; + break; + default: + assert(0); return; } - if(handler) + if(handler || only_needs_msg_type) { - // Generate the sender prototype. - const char* sender_name = genname_be(m->full_name); - m->func = codegen_addfun(c, sender_name, m->func_type); - genfun_param_attrs(c, t, m, m->func); - - // Change the return type to void for the handler. - size_t count = LLVMCountParamTypes(m->func_type); + size_t count = LLVMCountParamTypes(m->func_type) + 2; size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); - LLVMGetParamTypes(m->func_type, tparams); + LLVMGetParamTypes(m->func_type, &tparams[2]); - LLVMTypeRef handler_type = LLVMFunctionType(c->void_type, tparams, - (int)count, false); - ponyint_pool_free_size(buf_size, tparams); + if(!only_needs_msg_type) + { + // Generate the sender prototype. + const char* sender_name = genname_be(m->full_name); + m->func = codegen_addfun(c, sender_name, m->func_type); + genfun_param_attrs(c, t, m, m->func); + + // Change the return type to void for the handler. + LLVMTypeRef handler_type = LLVMFunctionType(c->void_type, &tparams[2], + (int)count - 2, false); + + // Generate the handler prototype. + m->func_handler = codegen_addfun(c, m->full_name, handler_type); + genfun_param_attrs(c, t, m, m->func_handler); + make_function_debug(c, t, m, m->func_handler); + } - // Generate the handler prototype. - m->func_handler = codegen_addfun(c, m->full_name, handler_type); - genfun_param_attrs(c, t, m, m->func_handler); - make_function_debug(c, t, m, m->func_handler); - } else { + // Generate the message type. + tparams[0] = c->i32; + tparams[1] = c->i32; + tparams[2] = c->void_ptr; + + m->msg_type = LLVMStructTypeInContext(c->context, tparams, (int)count, + false); + + ponyint_pool_free_size(buf_size, tparams); + } else if(!handler) { // Generate the function prototype. m->func = codegen_addfun(c, m->full_name, m->func_type); genfun_param_attrs(c, t, m, m->func); @@ -201,84 +222,6 @@ static void make_prototype(compile_t* c, reach_type_t* t, } } -static LLVMTypeRef send_message(compile_t* c, ast_t* params, LLVMValueRef to, - LLVMValueRef func, uint32_t index) -{ - // Get the parameter types. - LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); - int count = LLVMCountParamTypes(f_type) + 2; - - size_t buf_size = count * sizeof(LLVMTypeRef); - LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); - LLVMGetParamTypes(f_type, &f_params[2]); - - // The first one becomes the message size, the second the message ID. - f_params[0] = c->i32; - f_params[1] = c->i32; - f_params[2] = c->void_ptr; - LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count, - false); - LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); - ponyint_pool_free_size(buf_size, f_params); - - // Allocate the message, setting its size and ID. - size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type); - LLVMValueRef args[3]; - - args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); - args[1] = LLVMConstInt(c->i32, index, false); - LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, ""); - LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); - - for(int i = 3; i < count; i++) - { - LLVMValueRef arg = LLVMGetParam(func, i - 2); - LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, ""); - LLVMBuildStore(c->builder, arg, arg_ptr); - } - - // Trace while populating the message contents. - LLVMValueRef ctx = codegen_ctx(c); - - ast_t* param = ast_child(params); - bool need_trace = false; - - while(param != NULL) - { - if(gentrace_needed(ast_type(param))) - { - need_trace = true; - break; - } - - param = ast_sibling(param); - } - - if(need_trace) - { - gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); - param = ast_child(params); - - for(int i = 3; i < count; i++) - { - LLVMValueRef arg = LLVMGetParam(func, i - 2); - gentrace(c, ctx, arg, ast_type(param)); - param = ast_sibling(param); - } - - gencall_runtime(c, "pony_send_done", &ctx, 1, ""); - } - - // Send the message. - args[0] = ctx; - args[1] = LLVMBuildBitCast(c->builder, to, c->object_ptr, ""); - args[2] = msg; - gencall_runtime(c, "pony_sendv", args, 3, ""); - - // Return the type of the message. - return msg_type_ptr; -} - static void add_dispatch_case(compile_t* c, reach_type_t* t, ast_t* params, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { @@ -312,7 +255,7 @@ static void add_dispatch_case(compile_t* c, reach_type_t* t, ast_t* params, while(param != NULL) { - if(gentrace_needed(ast_type(param))) + if(gentrace_needed(c, ast_type(param), NULL)) { need_trace = true; break; @@ -328,7 +271,7 @@ static void add_dispatch_case(compile_t* c, reach_type_t* t, ast_t* params, for(int i = 1; i < count; i++) { - gentrace(c, ctx, args[i], ast_type(param)); + gentrace(c, ctx, args[i], ast_type(param), NULL); param = ast_sibling(param); } @@ -409,17 +352,21 @@ static bool genfun_be(compile_t* c, reach_type_t* t, reach_method_t* m) // Generate the sender. codegen_startfun(c, m->func, NULL, NULL); - LLVMValueRef this_ptr = LLVMGetParam(m->func, 0); + size_t buf_size = (m->param_count + 1) * sizeof(LLVMValueRef); + LLVMValueRef* param_vals = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); + LLVMGetParams(m->func, param_vals); // Send the arguments in a message to 'this'. - LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func, - m->vtable_index); + gen_send_message(c, m, param_vals, params); // Return 'this'. - LLVMBuildRet(c->builder, this_ptr); + LLVMBuildRet(c->builder, param_vals[0]); codegen_finishfun(c); + ponyint_pool_free_size(buf_size, param_vals); + // Add the dispatch case. + LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0); add_dispatch_case(c, t, params, m->vtable_index, m->func_handler, msg_type_ptr); @@ -478,22 +425,23 @@ static bool genfun_newbe(compile_t* c, reach_type_t* t, reach_method_t* m) LLVMBuildRetVoid(c->builder); codegen_finishfun(c); - // Generate the sender. + // Generate the sender. codegen_startfun(c, m->func, NULL, NULL); - LLVMValueRef this_ptr = LLVMGetParam(m->func, 0); + size_t buf_size = (m->param_count + 1) * sizeof(LLVMValueRef); + LLVMValueRef* param_vals = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); + LLVMGetParams(m->func, param_vals); // Send the arguments in a message to 'this'. - LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func, - m->vtable_index); + gen_send_message(c, m, param_vals, params); // Return 'this'. - codegen_debugloc(c, ast_childlast(body)); - LLVMBuildRet(c->builder, this_ptr); - codegen_debugloc(c, NULL); - + LLVMBuildRet(c->builder, param_vals[0]); codegen_finishfun(c); + ponyint_pool_free_size(buf_size, param_vals); + // Add the dispatch case. + LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0); add_dispatch_case(c, t, params, m->vtable_index, m->func_handler, msg_type_ptr); diff --git a/src/libponyc/codegen/genprim.c b/src/libponyc/codegen/genprim.c index 16d4805365..244de6cb74 100644 --- a/src/libponyc/codegen/genprim.c +++ b/src/libponyc/codegen/genprim.c @@ -669,7 +669,7 @@ static void trace_array_elements(compile_t* c, reach_type_t* t, ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); - if(!gentrace_needed(typearg)) + if(!gentrace_needed(c, typearg, NULL)) return; reach_type_t* t_elem = reach_type(c->reach, typearg); @@ -699,7 +699,7 @@ static void trace_array_elements(compile_t* c, reach_type_t* t, LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(c->builder, pointer, &phi, 1, ""); LLVMValueRef elem = LLVMBuildLoad(c->builder, elem_ptr, ""); - gentrace(c, ctx, elem, typearg); + gentrace(c, ctx, elem, typearg, NULL); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); diff --git a/src/libponyc/codegen/gentrace.c b/src/libponyc/codegen/gentrace.c index 3f2ac029cd..09d33c6b3f 100644 --- a/src/libponyc/codegen/gentrace.c +++ b/src/libponyc/codegen/gentrace.c @@ -369,7 +369,7 @@ static void trace_maybe(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, LLVMBuildCondBr(c->builder, test, is_true, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); - gentrace(c, ctx, object, elem); + gentrace(c, ctx, object, elem, NULL); LLVMBuildBr(c->builder, is_true); LLVMPositionBuilderAtEnd(c->builder, is_true); @@ -401,19 +401,35 @@ static void trace_unknown(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, } static void trace_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, - ast_t* type) + ast_t* src_type, ast_t* dst_type) { int i = 0; // We're a tuple, determined statically. - for(ast_t* child = ast_child(type); - child != NULL; - child = ast_sibling(child)) + if(dst_type != NULL) { - // Extract each element and trace it. - LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); - gentrace(c, ctx, elem, child); - i++; + ast_t* src_child = ast_child(src_type); + ast_t* dst_child = ast_child(dst_type); + while((src_child != NULL) && (dst_child != NULL)) + { + // Extract each element and trace it. + LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); + gentrace(c, ctx, elem, src_child, dst_child); + i++; + src_child = ast_sibling(src_child); + dst_child = ast_sibling(dst_child); + } + assert(src_child == NULL && dst_child == NULL); + } else { + ast_t* src_child = ast_child(src_type); + while(src_child != NULL) + { + // Extract each element and trace it. + LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); + gentrace(c, ctx, elem, src_child, NULL); + i++; + src_child = ast_sibling(src_child); + } } } @@ -567,7 +583,7 @@ static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx, if(ast_id(def) == TK_PRIMITIVE) return; - // If it's not possible to use match or as to extract this type from the + // If it's not possible to use match or to extract this type from the // original type, there's no need to trace as this type. if(tuple != NULL) { @@ -591,7 +607,7 @@ static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx, // Trace as this type. LLVMPositionBuilderAtEnd(c->builder, is_true); - gentrace(c, ctx, object, type); + gentrace(c, ctx, object, type, NULL); // If we have traced as mut or val, we're done with this element. Otherwise, // continue tracing this as if the match had been unsuccessful. @@ -643,26 +659,58 @@ static void trace_dynamic(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, } } -bool gentrace_needed(ast_t* type) +bool gentrace_needed(compile_t* c, ast_t* src_type, ast_t* dst_type) { - switch(trace_type(type)) + switch(trace_type(src_type)) { case TRACE_NONE: assert(0); return false; case TRACE_MACHINE_WORD: + { + if(dst_type == NULL) + return false; + + reach_type_t* dst_rtype = reach_type(c->reach, dst_type); + switch(dst_rtype->underlying) + { + case TK_UNIONTYPE: + case TK_ISECTTYPE: + case TK_INTERFACE: + case TK_TRAIT: + return true; + + default: + return false; + } + } + case TRACE_PRIMITIVE: return false; case TRACE_TUPLE: { - for(ast_t* child = ast_child(type); - child != NULL; - child = ast_sibling(child)) + if(dst_type != NULL) { - if(gentrace_needed(child)) - return true; + ast_t* src_child = ast_child(src_type); + ast_t* dst_child = ast_child(dst_type); + while((src_child != NULL) && (dst_child != NULL)) + { + if(gentrace_needed(c, src_child, dst_child)) + return true; + src_child = ast_sibling(src_child); + dst_child = ast_sibling(dst_child); + } + assert(src_child == NULL && dst_child == NULL); + } else { + ast_t* src_child = ast_child(src_type); + while(src_child != NULL) + { + if(gentrace_needed(c, src_child, NULL)) + return true; + src_child = ast_sibling(src_child); + } } return false; @@ -691,7 +739,7 @@ void gentrace_prototype(compile_t* c, reach_type_t* t) for(uint32_t i = 0; i < t->field_count; i++) { - if(gentrace_needed(t->fields[i].ast)) + if(gentrace_needed(c, t->fields[i].ast, NULL)) { need_trace = true; break; @@ -704,24 +752,44 @@ void gentrace_prototype(compile_t* c, reach_type_t* t) t->trace_fn = codegen_addfun(c, genname_trace(t->name), c->trace_type); } -void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) +void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, + ast_t* src_type, ast_t* dst_type) { - switch(trace_type(type)) + switch(trace_type(src_type)) { case TRACE_NONE: assert(0); return; case TRACE_MACHINE_WORD: + { + if(dst_type == NULL) + return; + + reach_type_t* dst_rtype = reach_type(c->reach, dst_type); + switch(dst_rtype->underlying) + { + case TK_UNIONTYPE: + case TK_ISECTTYPE: + case TK_INTERFACE: + case TK_TRAIT: + trace_known(c, ctx, value, src_type, PONY_TRACE_IMMUTABLE); + return; + + default: + return; + } + } + case TRACE_PRIMITIVE: return; case TRACE_MAYBE: - trace_maybe(c, ctx, value, type); + trace_maybe(c, ctx, value, src_type); return; case TRACE_VAL_KNOWN: - trace_known(c, ctx, value, type, PONY_TRACE_IMMUTABLE); + trace_known(c, ctx, value, src_type, PONY_TRACE_IMMUTABLE); return; case TRACE_VAL_UNKNOWN: @@ -729,7 +797,7 @@ void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) return; case TRACE_MUT_KNOWN: - trace_known(c, ctx, value, type, PONY_TRACE_MUTABLE); + trace_known(c, ctx, value, src_type, PONY_TRACE_MUTABLE); return; case TRACE_MUT_UNKNOWN: @@ -737,7 +805,7 @@ void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) return; case TRACE_TAG_KNOWN: - trace_known(c, ctx, value, type, PONY_TRACE_OPAQUE); + trace_known(c, ctx, value, src_type, PONY_TRACE_OPAQUE); return; case TRACE_TAG_UNKNOWN: @@ -747,14 +815,17 @@ void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) case TRACE_DYNAMIC: { LLVMBasicBlockRef next_block = codegen_block(c, ""); - trace_dynamic(c, ctx, value, type, type, NULL, next_block); + if(dst_type == NULL) + trace_dynamic(c, ctx, value, src_type, src_type, NULL, next_block); + else + trace_dynamic(c, ctx, value, dst_type, dst_type, NULL, next_block); LLVMBuildBr(c->builder, next_block); LLVMPositionBuilderAtEnd(c->builder, next_block); return; } case TRACE_TUPLE: - trace_tuple(c, ctx, value, type); + trace_tuple(c, ctx, value, src_type, dst_type); return; } } diff --git a/src/libponyc/codegen/gentrace.h b/src/libponyc/codegen/gentrace.h index 0054386040..b98d435b90 100644 --- a/src/libponyc/codegen/gentrace.h +++ b/src/libponyc/codegen/gentrace.h @@ -6,11 +6,12 @@ PONY_EXTERN_C_BEGIN -bool gentrace_needed(ast_t* type); +bool gentrace_needed(compile_t* c, ast_t* src_type, ast_t* dst_type); void gentrace_prototype(compile_t* c, reach_type_t* t); -void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type); +void gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, + ast_t* src_type, ast_t* dst_type); PONY_EXTERN_C_END diff --git a/src/libponyc/codegen/gentype.c b/src/libponyc/codegen/gentype.c index 93e8ef2b13..92a640cbf2 100644 --- a/src/libponyc/codegen/gentype.c +++ b/src/libponyc/codegen/gentype.c @@ -675,7 +675,7 @@ static bool make_trace(compile_t* c, reach_type_t* t) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); - gentrace(c, ctx, value, t->fields[i].ast); + gentrace(c, ctx, value, t->fields[i].ast, NULL); } else { // Call the trace function directly without marking the field. LLVMValueRef trace_fn = t->fields[i].type->trace_fn; diff --git a/src/libponyc/reach/reach.h b/src/libponyc/reach/reach.h index 15b3c17b23..daec164d8d 100644 --- a/src/libponyc/reach/reach.h +++ b/src/libponyc/reach/reach.h @@ -36,6 +36,7 @@ struct reach_method_t uint32_t vtable_index; LLVMTypeRef func_type; + LLVMTypeRef msg_type; LLVMValueRef func; LLVMValueRef func_handler; LLVMMetadataRef di_method; From 2612d73aab929df9095fa345a0edfc0f9c1da20f Mon Sep 17 00:00:00 2001 From: Sean T Allen Date: Thu, 27 Oct 2016 18:54:59 -0400 Subject: [PATCH 13/13] Prep for 0.8.0 release --- CHANGELOG.md | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 855dda5948..7809d96b1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Pony compiler and standard library will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a CHANGELOG](http://keepachangelog.com/). -## [unreleased] - unreleased +## [0.8.0] - 2016-10-27 ### Fixed diff --git a/VERSION b/VERSION index faef31a435..a3df0a6959 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.0 +0.8.0