diff a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
@@ -24,10 +24,11 @@
  */
 
 package com.sun.tools.javac.main;
 
 import java.io.*;
+import java.lang.module.Configuration;
 import java.nio.file.FileSystemNotFoundException;
 import java.nio.file.InvalidPathException;
 import java.nio.file.ReadOnlyFileSystemException;
 import java.util.Collection;
 import java.util.Comparator;
@@ -35,12 +36,14 @@
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.MissingResourceException;
+import java.util.Optional;
 import java.util.Queue;
 import java.util.ResourceBundle;
+import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.function.ToIntFunction;
 
 import javax.annotation.processing.Processor;
@@ -83,12 +86,10 @@
 import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
 import com.sun.tools.javac.util.Log.WriterKind;
 
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 
-import com.sun.tools.javac.code.Lint;
-import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
 
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.resources.CompilerProperties.Notes;
@@ -376,10 +377,12 @@
 
     private boolean enterDone;
 
     protected CompileStates compileStates;
 
+    private boolean hasCodeReflectionModule;
+
     /** Construct a new compiler using a shared context.
      */
     @SuppressWarnings("this-escape")
     public JavaCompiler(Context context) {
         this.context = context;
@@ -1052,10 +1055,19 @@
         return !shouldStop(CompileState.ATTR);
     }
 
     public List<JCCompilationUnit> initModules(List<JCCompilationUnit> roots) {
         modules.initModules(roots);
+
+        if (modules.modulesInitialized()) {
+            // This has to happen precisely here. At this point, we have all we need to
+            // determine whether jdk.incubator.module is part of the module graph
+            // but we have yet to trigger an ENTER event. This gives the code reflection plugin
+            // a window to check whether code reflection should be enabled for this compilation unit.
+            hasCodeReflectionModule = modules.getObservableModule(names.jdk_incubator_code) != null;
+        }
+
         if (roots.isEmpty()) {
             enterDone();
         }
         return roots;
     }
@@ -1604,18 +1616,26 @@
             }
 
             if (shouldStop(CompileState.TRANSTYPES))
                 return;
 
+            if (Feature.REFLECT_METHODS.allowedInSource(source)) {
+                Optional<CodeReflectionTransformer> reflectMethods = reflectMethods();
+                if (reflectMethods.isPresent()) {
+                    env.tree = reflectMethods.get().translateTopLevelClass(context, env.tree, localMake);
+                }
+            }
+
             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
             compileStates.put(env, CompileState.TRANSTYPES);
 
             if (shouldStop(CompileState.TRANSPATTERNS))
                 return;
 
             if (scanner.hasPatterns) {
-                env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
+                env.tree = TransPatterns.instance(context)
+                        .translateTopLevelClass(env, env.tree, localMake);
             }
 
             compileStates.put(env, CompileState.TRANSPATTERNS);
 
             if (shouldStop(CompileState.LOWER))
@@ -1659,10 +1679,43 @@
             log.useSource(prev);
         }
 
     }
 
+    Optional<CodeReflectionTransformer> reflectMethods() {
+        return CodeReflectionSupport.CODE_LAYER != null ?
+                ServiceLoader.load(CodeReflectionSupport.CODE_LAYER, CodeReflectionTransformer.class).findFirst() :
+                Optional.empty();
+    }
+
+    static class CodeReflectionSupport {
+        static final ModuleLayer CODE_LAYER;
+
+        static {
+            if (ModuleLayer.boot().findModule("jdk.incubator.code").isPresent()) {
+                // we are in an exploded build, so just use the boot layer
+                CODE_LAYER = ModuleLayer.boot();
+            } else if (java.lang.module.ModuleFinder.ofSystem().find("jdk.incubator.code").isPresent()) {
+                // the code module is installed, but not in the boot layer, create a new layer which contains it
+                ModuleLayer parent = ModuleLayer.boot();
+                Configuration cf = parent.configuration()
+                        .resolve(java.lang.module.ModuleFinder.of(), java.lang.module.ModuleFinder.ofSystem(), Set.of("jdk.incubator.code"));
+                ClassLoader scl = ClassLoader.getSystemClassLoader();
+                CODE_LAYER = parent.defineModulesWithOneLoader(cf, scl);
+                Module codeReflectionModule = CODE_LAYER.findModule("jdk.incubator.code").get();
+                Module jdkCompilerModule = JavaCompiler.class.getModule();
+                // We need to add exports all jdk.compiler packages so that the plugin can use them
+                for (String packageName : jdkCompilerModule.getPackages()) {
+                    jdkCompilerModule.addExports(packageName, codeReflectionModule);
+                }
+            } else {
+                // if we run in bootstrap mode, there might be no jdk.incubator.code
+                CODE_LAYER = null;
+            }
+        }
+    }
+
     /** Generates the source or class file for a list of classes.
      * The decision to generate a source file or a class file is
      * based upon the compiler's options.
      * Generation stops if an error occurs while writing files.
      */
@@ -1814,10 +1867,14 @@
 
     public boolean isEnterDone() {
         return enterDone;
     }
 
+    public boolean hasCodeReflectionModule() {
+        return hasCodeReflectionModule;
+    }
+
     private Name readModuleName(JavaFileObject fo) {
         return parseAndGetName(fo, t -> {
             JCModuleDecl md = t.getModuleDecl();
 
             return md != null ? TreeInfo.fullName(md.getName()) : null;
