Skip to content

Commit

Permalink
feat(graalvm): synthetic modules
Browse files Browse the repository at this point in the history
feat(graalvm-js): add new `graalvm-js` module for graaljs integration
feat(graalvm-js): initial structure and api for elide's import router
feat(graalvm-js): implement commonjs module loading support
feat(graalvm-js): implement esm module loading support
feat(graalvm-ts): move js realm patcher to `graalvm-js` module
feat(graalvm-ts): use new delegated module facilities
feat(graalvm): initialize javascript when plugin is added
feat(graalvm): enable `node:assert` for injection
feat(graalvm): enable `node:path` for injection
feat(graalvm): enable `node:zlib` for injection
feat(graalvm): enable `node:os` for injection
chore: reintroduce graalvm/graaljs modules and pins
chore: mark js realm patcher as deprecated
test: add test scripts for node paths

Signed-off-by: Sam Gammon <sam@elide.dev>
  • Loading branch information
sgammon committed Feb 24, 2025
1 parent 64d9c28 commit d06cae3
Show file tree
Hide file tree
Showing 55 changed files with 2,017 additions and 310 deletions.
10 changes: 9 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,12 @@
path = third_party/madler/zlib
url = git@github.com:madler/zlib.git
ignore = dirty

shallow = true
[submodule "graalvm"]
path = third_party/oracle/graalvm/graal
url = git@github.com:oracle/graal.git
shallow = true
[submodule "graaljs"]
path = third_party/oracle/graalvm/graaljs
url = git@github.com:elide-dev/graaljs.git
shallow = true
12 changes: 12 additions & 0 deletions packages/cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -1963,3 +1963,15 @@ listOf(
}
}
}

val (jsGroup, jsName) = libs.graalvm.js.language.get().let {
it.group to it.name
}
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("${jsGroup}:${jsName}")).apply {
using(project(":packages:graalvm-js"))
because("Uses Elide's patched version of GraalJs")
}
}
}
59 changes: 44 additions & 15 deletions packages/engine/api/engine.api
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,50 @@ public final class elide/runtime/gvm/cfg/LanguageDefaults {
public final fun getDEFAULT_TIMEZONE ()Ljava/time/ZoneId;
}

public abstract interface class elide/runtime/gvm/loader/ModuleFactory {
public abstract fun load (Lelide/runtime/gvm/loader/ModuleInfo;)Ljava/lang/Object;
}

public final class elide/runtime/gvm/loader/ModuleInfo : java/lang/Record, java/lang/Comparable {
public static final field Companion Lelide/runtime/gvm/loader/ModuleInfo$Companion;
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun compareTo (Lelide/runtime/gvm/loader/ModuleInfo;)I
public synthetic fun compareTo (Ljava/lang/Object;)I
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/util/List;
public final fun dependencies ()Ljava/util/List;
public fun equals (Ljava/lang/Object;)Z
public static final fun find (Ljava/lang/String;)Lelide/runtime/gvm/loader/ModuleInfo;
public fun hashCode ()I
public final fun name ()Ljava/lang/String;
public static final fun of (Ljava/lang/String;[Ljava/lang/String;)Lelide/runtime/gvm/loader/ModuleInfo;
public fun toString ()Ljava/lang/String;
}

public final class elide/runtime/gvm/loader/ModuleInfo$Companion {
public final fun find (Ljava/lang/String;)Lelide/runtime/gvm/loader/ModuleInfo;
public final fun getAllModuleInfos ()Ljava/util/Map;
public final fun of (Ljava/lang/String;[Ljava/lang/String;)Lelide/runtime/gvm/loader/ModuleInfo;
}

public abstract interface class elide/runtime/gvm/loader/ModuleRegistrar {
public abstract fun deferred (Lelide/runtime/gvm/loader/ModuleInfo;Lelide/runtime/gvm/loader/ModuleFactory;)V
public abstract fun register (Lelide/runtime/gvm/loader/ModuleInfo;Ljava/lang/Object;)V
}

public final class elide/runtime/gvm/loader/ModuleRegistry : elide/runtime/gvm/loader/ModuleRegistrar, elide/runtime/gvm/loader/ModuleResolver {
public static final field INSTANCE Lelide/runtime/gvm/loader/ModuleRegistry;
public fun contains (Lelide/runtime/gvm/loader/ModuleInfo;)Z
public fun deferred (Lelide/runtime/gvm/loader/ModuleInfo;Lelide/runtime/gvm/loader/ModuleFactory;)V
public fun load (Lelide/runtime/gvm/loader/ModuleInfo;)Ljava/lang/Object;
public fun register (Lelide/runtime/gvm/loader/ModuleInfo;Ljava/lang/Object;)V
}

public abstract interface class elide/runtime/gvm/loader/ModuleResolver {
public abstract fun contains (Lelide/runtime/gvm/loader/ModuleInfo;)Z
public abstract fun load (Lelide/runtime/gvm/loader/ModuleInfo;)Ljava/lang/Object;
}

public abstract class elide/runtime/plugins/AbstractLanguageConfig {
public static final field Companion Lelide/runtime/plugins/AbstractLanguageConfig$Companion;
public fun <init> ()V
Expand Down Expand Up @@ -467,21 +511,6 @@ public final class elide/runtime/plugins/AbstractLanguagePlugin$LanguagePluginMa
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

public abstract class elide/runtime/plugins/api/NativePlugin : elide/runtime/plugins/api/NativePluginAPI {
protected fun <init> (Ljava/lang/String;)V
protected fun apply ([Ljava/lang/String;)V
public fun context (Lorg/graalvm/polyglot/Engine;Lorg/graalvm/polyglot/Context$Builder;[Ljava/lang/String;)V
public fun getPluginId ()Ljava/lang/String;
public fun init ()V
public static fun initialize (Lelide/runtime/plugins/api/NativePlugin;)Lorg/graalvm/polyglot/Context$Builder;
}

public abstract interface class elide/runtime/plugins/api/NativePluginAPI {
public abstract fun context (Lorg/graalvm/polyglot/Engine;Lorg/graalvm/polyglot/Context$Builder;[Ljava/lang/String;)V
public abstract fun getPluginId ()Ljava/lang/String;
public abstract fun init ()V
}

public final class elide/runtime/plugins/bindings/Bindings {
public static final field Plugin Lelide/runtime/plugins/bindings/Bindings$Plugin;
public synthetic fun <init> (Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@
* 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.
*/
package elide.runtime.ruby;
@file:OptIn(DelicateElideApi::class)

import elide.runtime.plugins.api.NativePlugin;
package elide.runtime.gvm.loader

/** TBD. */
public class ElideRubyLanguage extends NativePlugin {
private static final String ELIDE_RUBY = "ruby";
import elide.runtime.core.DelicateElideApi

ElideRubyLanguage() {
super(ELIDE_RUBY);
}
/**
* ## Module Factory
*
* A factory which creates an instance of a synthesized module; loaded from a [ModuleResolver].
*/
public fun interface ModuleFactory {
/**
* Load a module from a [ModuleInfo].
*
* @param module The module to load.
* @return The loaded module.
*/
public fun load(module: ModuleInfo): Any
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 Elide Technologies, Inc.
*
* Licensed under the MIT license (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://opensource.org/license/mit/
*
* 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.
*/
package elide.runtime.gvm.loader

import java.util.concurrent.ConcurrentSkipListMap

/**
* Assigned string name/ID for a code module.
*/
public typealias ModuleId = String

/**
* ## Module Info
*
* Describes information about a code module of some kind; the module is addressed by a simple [name].
*
* @property name The name of the module.
* @property dependencies The list of module names that this module depends on.
*/
@ConsistentCopyVisibility
@JvmRecord public data class ModuleInfo private constructor (
public val name: ModuleId,
public val dependencies: List<ModuleId> = emptyList(),
) : Comparable<ModuleInfo> {
override fun compareTo(other: ModuleInfo): Int = name.compareTo(other.name)

public companion object {
public val allModuleInfos: MutableMap<ModuleId, ModuleInfo> = ConcurrentSkipListMap<ModuleId, ModuleInfo>()

// Register a module info record.
@JvmStatic private fun register(name: String, vararg deps: String): ModuleInfo {
assert(name !in allModuleInfos) { "Module $name already registered" }
return ModuleInfo(
name = name,
dependencies = deps.toList(),
).also {
allModuleInfos[name] = it
}
}

// Obtain a module info record, registering if needed.
@JvmStatic public fun of(name: String, vararg deps: String): ModuleInfo = allModuleInfos.computeIfAbsent(name) {
register(
name = name,
deps = deps,
)
}

// Obtain a module info record, or return `null` if not found.
@JvmStatic public fun find(name: String): ModuleInfo? = allModuleInfos[name]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Elide Technologies, Inc.
*
* Licensed under the MIT license (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://opensource.org/license/mit/
*
* 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.
*/
package elide.runtime.gvm.loader

/**
* ## Module Registry
*/
public interface ModuleRegistrar {
/**
* Register a module with the module registry.
*
* @param module The module to register.
* @param impl An instance of the registered module.
*/
public fun register(module: ModuleInfo, impl: Any)

/**
* Register a module with the module registry.
*
* @param module The module to register.
* @param producer The factory to create the module.
*/
public fun deferred(module: ModuleInfo, producer: ModuleFactory)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 Elide Technologies, Inc.
*
* Licensed under the MIT license (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://opensource.org/license/mit/
*
* 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.
*/

package elide.runtime.gvm.loader

/**
* ## Module Registry
*/
public object ModuleRegistry : ModuleRegistrar, ModuleResolver {
private val registered = sortedMapOf<ModuleInfo, Any>()
private val factories = sortedMapOf<ModuleInfo, ModuleFactory>()

override fun register(module: ModuleInfo, impl: Any) {
assert(module !in registered) { "Module already registered: $module" }
assert(module !in factories) { "Module already registered as factory: $module" }
factories[module] = ModuleFactory { _ -> impl }
}

override fun deferred(module: ModuleInfo, producer: ModuleFactory) {
factories[module] = producer
}

override operator fun contains(mod: ModuleInfo): Boolean = mod in factories

override fun load(info: ModuleInfo): Any = when (info) {
in registered -> registered[info]!!
in factories -> factories[info]!!.let { fac ->
fac.load(info).also {
registered[info] = it
}
}
else -> error("Module not registered: $info")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@
* 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.
*/
package elide.runtime.plugins.api;
package elide.runtime.gvm.loader

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;

/** TBD. */
public interface NativePluginAPI {
public String getPluginId();

public void context(Engine engine, Context.Builder builder, String[] args);
/**
* ## Module Resolver
*/
public interface ModuleResolver {
/**
* Resolve a module by request.
*/
public operator fun contains(mod: ModuleInfo): Boolean

public void init();
/**
* Load a module from its [ModuleInfo].
*
* @param info The module info.
* @return The module implementation; expected to be a polyglot value or proxy-type object.
*/
public fun load(info: ModuleInfo): Any
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import elide.runtime.core.PolyglotContext
*/
@DelicateElideApi public abstract class AbstractLanguageConfig {
public companion object {
private const val EXPERIMENTAL_SECURE_INTERNALS = true
private const val EXPERIMENTAL_SECURE_INTERNALS = false
}

/** Mutable counterpart to [intrinsicBindings]. */
Expand Down
Loading

0 comments on commit d06cae3

Please sign in to comment.