Skip to content

Commit

Permalink
Refactor documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
cstancu committed Feb 7, 2019
1 parent e808c32 commit 0a00325
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 125 deletions.
3 changes: 2 additions & 1 deletion substratevm/C-API.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Substrate VM C API

Substrate VM provides an API for the C language for initializing isolates and attaching threads for use with the entry point feature that is demonstrated in the [README](README.md). The C API is available when Substrate VM is built as a shared library and its declarations are included in the header file that is generated during the build:
Substrate VM provides an API for the C language for initializing isolates and attaching threads for use with the entry point feature that is demonstrated in the [README](README.md).
The C API is available when Substrate VM is built as a shared library and its declarations are included in the header file that is generated during the build:

```c
/*
Expand Down
33 changes: 23 additions & 10 deletions substratevm/DYNAMIC_PROXY.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# Dynamic proxies on Substrate VM

Java dynamic proxies, implemented by `java.lang.reflect.Proxy`, provide a mechanism which enables object level access control by routing all method invocations through a `java.lang.reflect.InvocationHandler`. Dynamic proxy classes are generated from a list of interfaces.
Java dynamic proxies, implemented by `java.lang.reflect.Proxy`, provide a mechanism which enables object level access control by routing all method invocations through a `java.lang.reflect.InvocationHandler`.
Dynamic proxy classes are generated from a list of interfaces.

Substrate VM doesn't provide machinery for generating and interpreting bytecodes at run time. Therefore all dynamic proxy classes need to be generated at native image build time
Substrate VM doesn't provide machinery for generating and interpreting bytecodes at run time.
Therefore all dynamic proxy classes need to be generated at native image build time


# Automatic detection
Substrate VM employs a simple static analysis that detects calls to `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler)` and `java.lang.reflect.Proxy.getProxyClass(ClassLoader, Class<?>[])` and tries to determine the list of interfaces that define dynamic proxies automatically. Given the list of interfaces then Substrate VM generates the proxy classes at image build time and adds them to the native image heap. In addition to generating the dynamic proxy class the constructor of the generated class that takes a `java.lang.reflect.InvocationHandler` argument, i.e., the one reflectively invoked by `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler)`, is registered for reflection so that dynamic proxy instances can be allocated at run time.
Substrate VM employs a simple static analysis that detects calls to `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler)` and `java.lang.reflect.Proxy.getProxyClass(ClassLoader, Class<?>[])` and tries to determine the list of interfaces that define dynamic proxies automatically.
Given the list of interfaces then Substrate VM generates the proxy classes at image build time and adds them to the native image heap.
In addition to generating the dynamic proxy class the constructor of the generated class that takes a `java.lang.reflect.InvocationHandler` argument, i.e., the one reflectively invoked by `java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler)`, is registered for reflection so that dynamic proxy instances can be allocated at run time.

The analysis is limited to situations where the list of interfaces comes from a constant array or an array that is allocated in the same method. For example in the code snippets bellow the dynamic proxy interfaces can be determined automatically.
The analysis is limited to situations where the list of interfaces comes from a constant array or an array that is allocated in the same method.
For example in the code snippets bellow the dynamic proxy interfaces can be determined automatically.

### Static final array:

Expand All @@ -24,7 +29,8 @@ class ProxyFactory {
}
}
```
Note: The analysis operates on Graal graphs and not source code. Therefore the following ways to declare and populate an array are equivalent from the point of view of the analysis:
Note: The analysis operates on Graal graphs and not source code.
Therefore the following ways to declare and populate an array are equivalent from the point of view of the analysis:

```
private static final Class<?>[] interfacesArrayPreInitialized = new Class<?>[]{java.util.Comparator.class};
Expand All @@ -40,7 +46,9 @@ static {
interfacesArrayPostInitialized[0] = java.util.Comparator.class;
}
```
However, in Java there are no immutable arrays. Even if the array is declared as `static final` its contents can change later on. The simple analysis that we employ here doesn't track further changes to the array.
However, in Java there are no immutable arrays.
Even if the array is declared as `static final` its contents can change later on.
The simple analysis that we employ here doesn't track further changes to the array.

### New array:

Expand Down Expand Up @@ -70,10 +78,12 @@ interfaces[0] = Question.class;
Class<?>[] interfaces = {java.util.Comparator.class};
```

The static analysis covers code patterns most frequently used to define dynamic proxy classes. For the exceptional cases where the analysis cannot discover the interface array there is also a manual dynamic proxy configuration mechanism.
The static analysis covers code patterns most frequently used to define dynamic proxy classes.
For the exceptional cases where the analysis cannot discover the interface array there is also a manual dynamic proxy configuration mechanism.

# Manual configuration
Dynamic proxy classes can be generated at native image build time by specifying the list of interfaces that they implement. Substrate VM provides two options for this purpose: `-H:DynamicProxyConfigurationFiles=<comma-separated-config-files>` and `-H:DynamicProxyConfigurationResources=<comma-separated-config-resources>`.
Dynamic proxy classes can be generated at native image build time by specifying the list of interfaces that they implement.
Substrate VM provides two options for this purpose: `-H:DynamicProxyConfigurationFiles=<comma-separated-config-files>` and `-H:DynamicProxyConfigurationResources=<comma-separated-config-resources>`.

These options accept JSON files whose structure is an array of arrays of fully qualified interface names.

Expand All @@ -87,7 +97,8 @@ Example:
]
```

The `java.lang.reflect.Proxy` API also allows creation of a dynamic proxy that doesn't implement any user provided interfaces. Therefore the following is a valid configuration:
The `java.lang.reflect.Proxy` API also allows creation of a dynamic proxy that doesn't implement any user provided interfaces.
Therefore the following is a valid configuration:

```
[
Expand All @@ -99,7 +110,9 @@ In this case the generated dynamic proxy class only implements `java.lang.reflec

# Dynamic proxy classes in static initializers

Dynamic proxy classes and instances of dynamic proxy classes that are defined in static initializers can be accessed at runtime without any special handling. This is possible since the static initializers are executed at native image build time. For example this will work:
Dynamic proxy classes and instances of dynamic proxy classes that are defined in static initializers can be accessed at runtime without any special handling.
This is possible since the static initializers are executed at native image build time.
For example this will work:

```
private final static Comparator proxyInstance;
Expand Down
34 changes: 28 additions & 6 deletions substratevm/JCA-SECURITY-SERVICES.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
JCA Security Services on Substrate VM
-----------------------------

This section refers to the use of the services provided by the [Java Cryptography Architecture (JCA)](https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html) framework. The JCA framework relies on reflection to achieve algorithm independence and extensibility, therefore it requires a custom configuration on Substrate VM. Additionally, seed generators that use system files like `/dev/random` or `/dev/urandom` need to be re-initialized at runtime.
This section refers to the use of the services provided by the [Java Cryptography Architecture (JCA)](https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html) framework.
The JCA framework relies on reflection to achieve algorithm independence and extensibility, therefore it requires a custom configuration on Substrate VM.
Additionally, seed generators that use system files like `/dev/random` or `/dev/urandom` need to be re-initialized at runtime.

By default a native image is built with support for the `SecureRandom` and `MessageDigest` engines from the `SUN` provider. These are core security services needed by the VM itself. All the other Java security services (`Signature`, `Cipher`, `Mac`, `KeyPair`, `KeyGenerator`, `KeyFactory`, `KeyStore`, etc.) must be enabled adding the `--enable-all-security-services` option to the `native-image` command. The reason behind enabling only core security services by default is that you can start with a basic image and add more security services as you need them. This helps keeping the overall image size small.
By default a native image is built with support for the `SecureRandom` and `MessageDigest` engines from the `SUN` provider.
These are core security services needed by the VM itself.
All the other Java security services (`Signature`, `Cipher`, `Mac`, `KeyPair`, `KeyGenerator`, `KeyFactory`, `KeyStore`, etc.) must be enabled adding the `--enable-all-security-services` option to the `native-image` command.
The reason behind enabling only core security services by default is that you can start with a basic image and add more security services as you need them.
This helps keeping the overall image size small.

Note: The `--enable-all-security-services` option is enabled by default when `https` support is enabled. See the [documentation on URL protocols](URL-PROTOCOLS.md) for more details.
Note: The `--enable-all-security-services` option is enabled by default when `https` support is enabled.
See the [documentation on URL protocols](URL-PROTOCOLS.md) for more details.

### Provider registration

The image builder captures the list of providers and their preference order from the underlying JVM. The provider order is specified in the `java.security` file under `<java-home>/lib/security/java.security`. New security providers cannot be registered at run time, all providers must be statically configured during native image building.
The image builder captures the list of providers and their preference order from the underlying JVM.
The provider order is specified in the `java.security` file under `<java-home>/lib/security/java.security`.
New security providers cannot be registered at run time, all providers must be statically configured during native image building.

### Native implementations

Some security providers, like SunEC, are implemented in native code and accessed via JNI. When `--enable-all-security-services` is used then JNI support is enabled by default. If your app uses a provider implemented in a native library that library needs to be delivered together with the generated native image. For example the SunEC provider requires `libsunec.so` for its full implementation. This library is usually shipped as part of the JDK and can be found under `<JAVA_HOME>/jre/lib/<platform>/libsunec.so`. It is loaded at run time via `System.loadLibrary("sunec")`, the first time services from SunEC are accessed. To use this provider's services the `java.library.path` system property needs to be set accordingly to point to a location that contains `libsunec.so`. Note that if `java.library.path` is not set it defaults to the current working directory.
Some security providers, like SunEC, are implemented in native code and accessed via JNI.
When `--enable-all-security-services` is used then JNI support is enabled by default.
If your app uses a provider implemented in a native library that library needs to be delivered together with the generated native image.
For example the SunEC provider requires `libsunec.so` for its full implementation.
This library is usually shipped as part of the JDK and can be found under `<JAVA_HOME>/jre/lib/<platform>/libsunec.so`.
It is loaded at run time via `System.loadLibrary("sunec")`, the first time services from SunEC are accessed.
To use this provider's services the `java.library.path` system property needs to be set accordingly to point to a location that contains `libsunec.so`.
Note that if `java.library.path` is not set it defaults to the current working directory.

### Alternative to `--enable-all-security-services`

Registering *all* security services doesn't come for free. The additional code increases the native image size. If your application only requires a subset of the security services you can manually register the corresponding classes for reflection and push the initialization of some seed generators to runtime. However this requires deep knowledge of the JCA architecture. We are investigating the posibility to provide a finer grain declarative configuration of security services for future releases. If you want to take on this task youreslf you can start by reading the `com.oracle.svm.hosted.SecurityServicesFeature` class. This is where most of the code behind the `--enable-all-security-services` option is implemented.
Registering *all* security services doesn't come for free.
The additional code increases the native image size.
If your application only requires a subset of the security services you can manually register the corresponding classes for reflection and push the initialization of some seed generators to runtime.
However this requires deep knowledge of the JCA architecture.
We are investigating the posibility to provide a finer grain declarative configuration of security services for future releases.
If you want to take on this task youreslf you can start by reading the `com.oracle.svm.hosted.SecurityServicesFeature` class.
This is where most of the code behind the `--enable-all-security-services` option is implemented.
Loading

0 comments on commit 0a00325

Please sign in to comment.