Skip to content

Commit

Permalink
BEGIN_PUBLIC
Browse files Browse the repository at this point in the history
PR #18406: Teach ijar about dynamic constants.

Imported from GitHub PR #18406

END_PUBLIC

PiperOrigin-RevId: 540750474
Change-Id: If61bcaaf018b92a1bf87335c1075c28294932b1f
  • Loading branch information
benjaminp authored and copybara-github committed Jun 16, 2023
1 parent ae6b3a5 commit 69d2991
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 21 deletions.
70 changes: 49 additions & 21 deletions third_party/ijar/classfile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,23 @@ std::string ToString(const T& value) {

namespace devtools_ijar {

// See Table 4.3 in JVM Spec.
// See Table 4.4 in JVM 17 Spec.
enum CONSTANT {
CONSTANT_Class = 7,
CONSTANT_FieldRef = 9,
CONSTANT_Methodref = 10,
CONSTANT_Class = 7,
CONSTANT_FieldRef = 9,
CONSTANT_Methodref = 10,
CONSTANT_Interfacemethodref = 11,
CONSTANT_String = 8,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_NameAndType = 12,
CONSTANT_Utf8 = 1,
CONSTANT_MethodHandle = 15,
CONSTANT_MethodType = 16,
CONSTANT_InvokeDynamic = 18
CONSTANT_String = 8,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_NameAndType = 12,
CONSTANT_Utf8 = 1,
CONSTANT_MethodHandle = 15,
CONSTANT_MethodType = 16,
CONSTANT_Dynamic = 17,
CONSTANT_InvokeDynamic = 18
};

// See Tables 4.1, 4.4, 4.5 in JVM Spec.
Expand Down Expand Up @@ -390,12 +391,32 @@ struct Constant_MethodType : Constant
};

// See sec.4.4.10 of JVM spec.
struct Constant_InvokeDynamic : Constant
{
Constant_InvokeDynamic(u2 bootstrap_method_attr_index, u2 name_and_type_index) :
Constant(CONSTANT_InvokeDynamic),
bootstrap_method_attr_index_(bootstrap_method_attr_index),
name_and_type_index_(name_and_type_index) {}
struct Constant_Dynamic : Constant {
Constant_Dynamic(u2 bootstrap_method_attr_index, u2 name_and_type_index)
: Constant(CONSTANT_Dynamic),
bootstrap_method_attr_index_(bootstrap_method_attr_index),
name_and_type_index_(name_and_type_index) {}

void Write(u1 *&p) {
put_u1(p, tag_);
put_u2be(p, bootstrap_method_attr_index_);
put_u2be(p, name_and_type_index_);
}

std::string Display() {
return "Constant_Dynamic::" + ToString(bootstrap_method_attr_index_) +
"::" + constant(name_and_type_index_)->Display();
}

u2 bootstrap_method_attr_index_;
u2 name_and_type_index_;
};

struct Constant_InvokeDynamic : Constant {
Constant_InvokeDynamic(u2 bootstrap_method_attr_index, u2 name_and_type_index)
: Constant(CONSTANT_InvokeDynamic),
bootstrap_method_attr_index_(bootstrap_method_attr_index),
name_and_type_index_(name_and_type_index) {}

void Write(u1 *&p) {
put_u1(p, tag_);
Expand Down Expand Up @@ -1677,6 +1698,13 @@ bool ClassFile::ReadConstantPool(const u1 *&p) {
const_pool_in.push_back(new Constant_MethodType(descriptor_index));
break;
}
case CONSTANT_Dynamic: {
u2 bootstrap_method_attr = get_u2be(p);
u2 name_name_type_index = get_u2be(p);
const_pool_in.push_back(
new Constant_Dynamic(bootstrap_method_attr, name_name_type_index));
break;
}
case CONSTANT_InvokeDynamic: {
u2 bootstrap_method_attr = get_u2be(p);
u2 name_name_type_index = get_u2be(p);
Expand All @@ -1685,7 +1713,7 @@ bool ClassFile::ReadConstantPool(const u1 *&p) {
break;
}
default: {
fprintf(stderr, "Unknown constant: %02x. Passing class through.\n",
fprintf(stderr, "Unknown constant: %hhu. Passing class through.\n",
tag);
return false;
}
Expand Down
16 changes: 16 additions & 0 deletions third_party/ijar/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ sh_test(
# Intentionally bad test JAR: file count in central directory
# wrong.
"libwrongcentraldir.jar",
":dynamic_constant.jar",
"@bazel_tools//tools/jdk:current_java_runtime",
],
shard_count = 5,
Expand Down Expand Up @@ -204,6 +205,21 @@ genrule(
tools = ["gen_source_debug_extension"],
)

java_binary(
name = "gen_dynamic_constant",
srcs = ["GenDynamicConstant.java"],
main_class = "test.GenDynamicConstant",
deps = ["//third_party:asm"],
)

genrule(
name = "gen_dynamic_constant_jar",
srcs = [],
outs = ["dynamic_constant.jar"],
cmd = "$(location :gen_dynamic_constant) $@",
tools = [":gen_dynamic_constant"],
)

java_library(
name = "local_and_anonymous_lib",
srcs = ["LocalAndAnonymous.java"],
Expand Down
76 changes: 76 additions & 0 deletions third_party/ijar/test/GenDynamicConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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 test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.invoke.ConstantBootstraps;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public class GenDynamicConstant {
public static void main(String[] args) throws IOException {
try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(args[0]))) {
jos.putNextEntry(new ZipEntry("dynamicconstant/Test.class"));
jos.write(dump());
}
}

public static byte[] dump() {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;

cw.visit(
Opcodes.V16,
Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
"dynamicconstant/Test",
null,
"java/lang/Object",
null);

cw.visitEnd();

var desc = Type.INT_TYPE.getDescriptor();
var get =
cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "get", "()" + desc, null, null);
get.visitInsn(Opcodes.ICONST_5);
get.visitInsn(Opcodes.IRETURN);
get.visitMaxs(1, 0);
get.visitEnd();
var invokeHandle =
new Handle(
Opcodes.H_INVOKESTATIC,
Type.getInternalName(ConstantBootstraps.class),
"invoke",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
false);
var handle =
new Handle(Opcodes.H_INVOKESTATIC, "dynamicconstant/Test", "get", "()" + desc, false);
var run =
cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()" + desc, null, null);
run.visitLdcInsn(new ConstantDynamic("const", desc, invokeHandle, handle));
run.visitInsn(Opcodes.IRETURN);
run.visitMaxs(1, 0);
run.visitEnd();

return cw.toByteArray();
}
}
9 changes: 9 additions & 0 deletions third_party/ijar/test/ijar_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ CENTRAL_DIR_LARGEST_REGULAR=$IJAR_SRCDIR/test/largest_regular.jar
CENTRAL_DIR_SMALLEST_ZIP64=$IJAR_SRCDIR/test/smallest_zip64.jar
CENTRAL_DIR_ZIP64=$IJAR_SRCDIR/test/definitely_zip64.jar
KEEP_FOR_COMPILE=$IJAR_SRCDIR/test/keep_for_compile_lib.jar
DYNAMICCONSTANT_JAR=$IJAR_SRCDIR/test/dynamic_constant.jar
DYNAMICCONSTANT_IJAR=$TEST_TMPDIR/dynamic_constant_interface.jar

#### Setup

Expand Down Expand Up @@ -522,6 +524,13 @@ function test_method_parameters_attribute() {
expect_log "MethodParameters" "MethodParameters not preserved!"
}

function test_dynamic_constant() {
$IJAR $DYNAMICCONSTANT_JAR $DYNAMICCONSTANT_IJAR || fail "ijar failed"

lines=$($JAVAP -c -private -classpath $DYNAMICCONSTANT_IJAR dynamicconstant.Test | grep -c Code: || true)
check_eq 0 $lines "Interface jar should have no method bodies!"
}

function test_nestmates_attribute() {
# Check that Java 11 NestMates attributes are preserved
$IJAR $NESTMATES_JAR $NESTMATES_IJAR || fail "ijar failed"
Expand Down

0 comments on commit 69d2991

Please sign in to comment.