Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor methods of Managed_Resource #3460

Merged
merged 8 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
- [Implemented `compute` method on `Vector` for statistics calculations.][3442]
- [Promote get and put to be methods of Ref type rather than of Ref
module][3457]
- [Promote with, take, finalize to be methods of Managed_Resource
instance][3460]

[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
Expand Down Expand Up @@ -186,6 +188,7 @@
[3430]: https://github.com/enso-org/enso/pull/3430
[3442]: https://github.com/enso-org/enso/pull/3442
[3457]: https://github.com/enso-org/enso/pull/3457
[3460]: https://github.com/enso-org/enso/pull/3460

#### Enso Compiler

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ type Managed_Resource
function once it is no longer in use.

Arguments:
- resource: The resource to be managed automatically.
- function: The action to be executed on resource to clean it up when
it is no longer in use.
register : Any -> (Any -> Nothing) -> Managed_Resource
Expand All @@ -46,32 +45,24 @@ type Managed_Resource

Forces finalization of a managed resource using the registered finalizer,
even if the resource is still reachable.

Arguments:
- resource: The resource that should be finalized.
finalize : Managed_Resource -> Nothing
finalize resource = @Builtin_Method "Managed_Resource.finalize"
finalize : Nothing
finalize = @Builtin_Method "Managed_Resource.finalize"

## ADVANCED

Executes the provided action on the resource managed by the managed
resource object.

Arguments:
- resource: The managed resource on which to run the action.
- action: The action that will be applied to the resource managed by
resource.
with : Managed_Resource -> (Any -> Any) -> Any
with resource ~action = @Builtin_Method "Managed_Resource.with"
with : (Any -> Any) -> Any
with ~action = @Builtin_Method "Managed_Resource.with"

## ADVANCED

Takes the value held by the managed resource and unregisters the
finalization step for this resource, effectively removing it from the
managed resources system.

Arguments:
- resource: The managed resource from which to acquire the underlying
resource.
take : Managed_Resource -> Any
take resource = @Builtin_Method "Managed_Resource.take"
take = @Builtin_Method "Managed_Resource.take"
14 changes: 7 additions & 7 deletions distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ type Output_Stream
out_stream.write_bytes "hello".utf_8
out_stream.close
write_bytes : Vector.Vector -> Nothing ! File_Error
write_bytes contents = Managed_Resource.with this.stream_resource java_stream->
write_bytes contents = this.stream_resource . with java_stream->
here.handle_java_exceptions this.file <|
java_stream.write contents.to_array
java_stream.flush
Expand All @@ -752,7 +752,7 @@ type Output_Stream
out_stream = file.new_output_stream [Option.Create]
out_stream.close
close : Nothing
close = Managed_Resource.finalize this.stream_resource
close = this.stream_resource . finalize

## An input stream, allowing for interactive reading of contents from an open
file.
Expand Down Expand Up @@ -786,7 +786,7 @@ type Input_Stream
in_stream.close
bytes
read_all_bytes : Vector.Vector ! File_Error
read_all_bytes = Managed_Resource.with this.stream_resource java_stream->
read_all_bytes = this.stream_resource . with java_stream->
here.handle_java_exceptions this.file <|
Vector.Vector java_stream.readAllBytes

Expand Down Expand Up @@ -816,7 +816,7 @@ type Input_Stream
in_stream.close
bytes
read_n_bytes : Integer -> Vector.Vector ! File_Error
read_n_bytes n = Managed_Resource.with this.stream_resource java_stream->
read_n_bytes n = this.stream_resource . with java_stream->
here.handle_java_exceptions this.file <|
bytes = java_stream.readNBytes n
Vector.Vector bytes
Expand All @@ -841,7 +841,7 @@ type Input_Stream
in_stream.close
bytes
read_byte : Integer ! File_Error
read_byte = Managed_Resource.with this.stream_resource java_stream->
read_byte = this.stream_resource . with java_stream->
here.handle_java_exceptions this.file <|
java_stream.read

Expand All @@ -864,7 +864,7 @@ type Input_Stream
in_stream = file.new_input_stream [Option.Read]
in_stream.close
close : Nothing
close = Managed_Resource.finalize this.stream_resource
close = this.stream_resource . finalize

## PRIVATE

Expand All @@ -876,7 +876,7 @@ type Input_Stream
Useful when integrating with polyglot functions requiring an
`InputStream` as an argument.
with_java_stream : (Java_Input_Stream -> Any) -> Any
with_java_stream f = Managed_Resource.with this.stream_resource f
with_java_stream f = this.stream_resource . with f


## PRIVATE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type Connection
The connection is not usable afterwards.
close : Nothing
close =
Managed_Resource.finalize this.connection_resource
this.connection_resource . finalize

## ADVANCED

Expand Down Expand Up @@ -109,7 +109,7 @@ type Connection
information to any thrown SQL errors.
with_prepared_statement : Text | Sql.Statement -> (PreparedStatement -> Any) -> Any
with_prepared_statement query action =
prepare template holes = Managed_Resource.with this.connection_resource java_connection->
prepare template holes = this.connection_resource . with java_connection->
stmt = java_connection.prepareStatement template
Panic.catch Any (here.set_statement_values stmt holes) caught_panic->
stmt.close
Expand Down Expand Up @@ -182,7 +182,7 @@ type Connection
db_types = pairs.map p-> p.second.sql_type
insert_query = this.dialect.generate_sql <| IR.Insert name pairs
insert_template = insert_query.prepare.first
Managed_Resource.with this.connection_resource java_connection->
this.connection_resource . with java_connection->
default_autocommit = java_connection.getAutoCommit
java_connection.setAutoCommit False
Resource.bracket Nothing (_ -> java_connection.setAutoCommit default_autocommit) _->
Expand Down
9 changes: 4 additions & 5 deletions docs/semantics/managed-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,17 @@ call.
> `Managed_Resource.register` call.

To perform operations on the underlying resource, use the
`Managed_Resource.with resource action` method, where `resource` is the object
returned from the call to `Managed_Resource.register`, and `action` is a
`<managed-resource>.with action` method, where `<managed-resource>` is the
object returned from the call to `Managed_Resource.register`, and `action` is a
function taking the underlying object as its only argument. It is important that
the object passed to `action` is not stored and is not used past the return of
`action`. This means in particular that it is unsafe to give another thread a
reference to that object, if the thread remains alive past the return of
`action`. If such an operation is necessary, the other thread should call `with`
itself, using a reference to the original manged resource.

A managed resource can be closed manually, using
`Managed_Resource.close resource`. The underlying object is then finalized
immediately.
A managed resource can be closed manually, using `<managed-resource>.close`. The
underlying object is then finalized immediately.

The finalization of a resource can be aborted using
`Managed_Resource.take resource`. This call will abort any automatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ static FinalizeNode build() {
return FinalizeNodeGen.create();
}

abstract Object execute(Object _this, ManagedResource resource);
abstract Object execute(Object _this);

@Specialization
Object doClose(Object _this, ManagedResource resource) {
Object doClose(ManagedResource _this) {
Context context = Context.get(this);
context.getResourceManager().close(resource);
context.getResourceManager().close(_this);
return context.getBuiltins().nothing().newInstance();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ static TakeNode build() {
return TakeNodeGen.create();
}

abstract Object execute(Object _this, ManagedResource resource);
abstract Object execute(Object _this);

@Specialization
Object doTake(Object _this, ManagedResource resource) {
Context.get(this).getResourceManager().take(resource);
return resource.getResource();
Object doTake(ManagedResource _this) {
Context.get(this).getResourceManager().take(_this);
return _this.getResource();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,17 @@ static WithNode build() {
}

abstract Stateful execute(
@MonadicState Object state,
VirtualFrame frame,
Object _this,
ManagedResource resource,
Object action);
@MonadicState Object state, VirtualFrame frame, Object _this, Object action);

@Specialization
Stateful doWith(
Object state, VirtualFrame frame, Object _this, ManagedResource resource, Object action) {
Stateful doWith(Object state, VirtualFrame frame, ManagedResource _this, Object action) {
ResourceManager resourceManager = Context.get(this).getResourceManager();
resourceManager.park(resource);
resourceManager.park(_this);
try {
return invokeCallableNode.execute(
action, frame, state, new Object[] {resource.getResource()});
action, frame, state, new Object[] {_this.getResource()});
} finally {
resourceManager.unpark(resource);
resourceManager.unpark(_this);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package org.enso.interpreter.runtime.data;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.library.dispatch.MethodDispatchLibrary;

import java.lang.ref.PhantomReference;

/** A runtime representation of a managed resource. */
@ExportLibrary(MethodDispatchLibrary.class)
public class ManagedResource implements TruffleObject {
private final Object resource;
private PhantomReference<ManagedResource> phantomReference;
Expand Down Expand Up @@ -37,4 +47,51 @@ public PhantomReference<ManagedResource> getPhantomReference() {
public void setPhantomReference(PhantomReference<ManagedResource> phantomReference) {
this.phantomReference = phantomReference;
}

@ExportMessage
boolean hasFunctionalDispatch() {
return true;
}

@ExportMessage
static class GetFunctionalDispatch {

static final int CACHE_SIZE = 10;

@CompilerDirectives.TruffleBoundary
static Function doResolve(UnresolvedSymbol symbol) {
Context context = getContext();
return symbol.resolveFor(
context.getBuiltins().managedResource(), context.getBuiltins().any());
}

static Context getContext() {
return Context.get(null);
}

@Specialization(
guards = {
"!getContext().isInlineCachingDisabled()",
"cachedSymbol == symbol",
"function != null"
},
limit = "CACHE_SIZE")
static Function resolveCached(
ManagedResource _this,
UnresolvedSymbol symbol,
@Cached("symbol") UnresolvedSymbol cachedSymbol,
@Cached("doResolve(cachedSymbol)") Function function) {
return function;
}

@Specialization(replaces = "resolveCached")
static Function resolve(ManagedResource _this, UnresolvedSymbol symbol)
throws MethodDispatchLibrary.NoSuchMethodException {
Function function = doResolve(symbol);
if (function == null) {
throw new MethodDispatchLibrary.NoSuchMethodException();
}
return function;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class RuntimeManagementTest extends InterpreterTest {
|create_resource i =
| c = Mock_File i
| r = Managed_Resource.register c here.free_resource
| Managed_Resource.with r f-> IO.println ("Accessing: " + f.to_text)
| r . with f-> IO.println ("Accessing: " + f.to_text)
|
|main =
| here.create_resource 0
Expand Down Expand Up @@ -127,8 +127,8 @@ class RuntimeManagementTest extends InterpreterTest {
|create_resource i =
| c = Mock_File i
| r = Managed_Resource.register c here.free_resource
| Managed_Resource.with r f-> IO.println ("Accessing: " + f.to_text)
| if i % 2 == 0 then Managed_Resource.finalize r else Nothing
| r . with f-> IO.println ("Accessing: " + f.to_text)
| if i % 2 == 0 then r.finalize else Nothing
|
|main =
| here.create_resource 0
Expand Down Expand Up @@ -168,8 +168,8 @@ class RuntimeManagementTest extends InterpreterTest {
|create_resource i =
| c = Mock_File i
| r = Managed_Resource.register c here.free_resource
| Managed_Resource.with r f-> IO.println ("Accessing: " + f.to_text)
| if i % 2 == 0 then Managed_Resource.take r else Nothing
| r . with f-> IO.println ("Accessing: " + f.to_text)
| if i % 2 == 0 then r.take else Nothing
|
|main =
| here.create_resource 0
Expand Down