Skip to content

Commit ae89a8a

Browse files
committed
Disallow private and package-private fields in JSObject subclasses
This was the original intent. This way, not state is split between the JS and Java mirror. It is also the less confusing behavior, allowing private, fields, but not exposing them to JS, could be unexpected
1 parent dabeec4 commit ae89a8a

File tree

6 files changed

+40
-8
lines changed

6 files changed

+40
-8
lines changed

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private boolean canBeJavaScriptCall(AnalysisMethod method) {
125125

126126
@Override
127127
public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
128-
if (ClassWithMirrorLowerer.isJSObjectSubtype(((AnalysisType) field.getDeclaringClass()).getJavaClass())) {
128+
if (ClassWithMirrorLowerer.isFieldRepresentedInJavaScript(field)) {
129129
genJSObjectFieldAccess(b, object, field, null);
130130
return true;
131131
}
@@ -134,7 +134,7 @@ public boolean handleLoadField(GraphBuilderContext b, ValueNode object, Resolved
134134

135135
@Override
136136
public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
137-
if (ClassWithMirrorLowerer.isJSObjectSubtype(((AnalysisType) field.getDeclaringClass()).getJavaClass())) {
137+
if (ClassWithMirrorLowerer.isFieldRepresentedInJavaScript(field)) {
138138
genJSObjectFieldAccess(b, object, field, value);
139139
return true;
140140
}

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassLowerer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import java.util.function.Consumer;
3737
import java.util.function.Function;
3838

39-
import org.graalvm.webimage.api.JSObject;
4039
import org.graalvm.webimage.api.JSResource;
4140

4241
import com.oracle.svm.hosted.meta.HostedField;
@@ -133,8 +132,8 @@ private void lowerClassHeader() {
133132
* we only collect the instance fields declared by this type, inherited fields are resolved
134133
* via a super call
135134
*/
136-
if (!JSObject.class.isAssignableFrom(type.getJavaClass())) {
137-
for (HostedField field : type.getInstanceFields(false)) {
135+
for (HostedField field : type.getInstanceFields(false)) {
136+
if (!ClassWithMirrorLowerer.isFieldRepresentedInJavaScript(field)) {
138137
genFieldInitialization(codeGenTool, masm, field);
139138
}
140139
}

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassWithMirrorLowerer.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626

2727
import static com.oracle.svm.hosted.webimage.codegen.RuntimeConstants.RUNTIME_SYMBOL;
2828

29+
import java.util.ArrayList;
2930
import java.util.HashSet;
31+
import java.util.List;
3032
import java.util.Map;
3133
import java.util.function.Consumer;
3234

@@ -35,6 +37,7 @@
3537
import org.graalvm.webimage.api.JS;
3638
import org.graalvm.webimage.api.JSObject;
3739

40+
import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider;
3841
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
3942
import com.oracle.svm.hosted.meta.HostedClass;
4043
import com.oracle.svm.hosted.meta.HostedField;
@@ -55,6 +58,7 @@
5558
import jdk.graal.compiler.hightiercodegen.CodeBuffer;
5659
import jdk.graal.compiler.nodes.StructuredGraph;
5760
import jdk.graal.compiler.options.OptionValues;
61+
import jdk.vm.ci.meta.ResolvedJavaField;
5862
import jdk.vm.ci.meta.ResolvedJavaMethod;
5963
import jdk.vm.ci.meta.Signature;
6064

@@ -189,6 +193,17 @@ public ClassWithMirrorLowerer(OptionValues options, DebugContext debug, JSCodeGe
189193
this.externClassDescriptor = null;
190194
}
191195

196+
/**
197+
* Public and protected fields in {@link JSObject} subclasses are represented in the JavaScript
198+
* mirror.
199+
* <p>
200+
* Accesses to those fields must be intercepted. The fields also do not appear in the Java
201+
* object.
202+
*/
203+
public static boolean isFieldRepresentedInJavaScript(ResolvedJavaField field) {
204+
return !field.isStatic() && isJSObjectSubtype(OriginalClassProvider.getJavaClass(field.getDeclaringClass()));
205+
}
206+
192207
/**
193208
* An imported Javascript class needs extern file for Closure compiler if the source code is not
194209
* included.
@@ -205,6 +220,18 @@ public static boolean isJSObjectSubtype(Class<?> cls) {
205220
return JSObject.class.isAssignableFrom(cls);
206221
}
207222

223+
public static List<HostedField> getOwnFieldOnJSSide(HostedType type) {
224+
List<HostedField> fields = new ArrayList<>();
225+
226+
for (HostedField instanceField : type.getInstanceFields(false)) {
227+
if (isFieldRepresentedInJavaScript(instanceField)) {
228+
fields.add(instanceField);
229+
}
230+
}
231+
232+
return fields;
233+
}
234+
208235
@Override
209236
public void lower(WebImageTypeControl typeControl) {
210237
if (needExternDeclaration()) {
@@ -228,7 +255,7 @@ protected void lowerPreamble(JSCodeGenTool tool) {
228255

229256
if (needExternDeclaration()) {
230257
// We need to mark the fields in the externs file.
231-
for (HostedField field : type.getInstanceFields(false)) {
258+
for (HostedField field : getOwnFieldOnJSSide(type)) {
232259
externClassDescriptor.addProperty(field.getName());
233260
}
234261
}
@@ -302,7 +329,7 @@ private void genJavaScriptMirrorConstructor(JSCodeGenTool tool, JSCodeBuffer buf
302329
}
303330

304331
// Initialize properties.
305-
for (HostedField field : type.getInstanceFields(false)) {
332+
for (HostedField field : getOwnFieldOnJSSide(type)) {
306333
tool.genResolvedVarDeclThisPrefix(field.getName());
307334
genDefaultValue(tool, buffer, field);
308335
tool.genResolvedVarDeclPostfix(null);

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSObjectAccessMethodSupport.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ private AnalysisMethod lookup(AnalysisMetaAccess aMetaAccess, AnalysisField fiel
7272
GraalError.guarantee(JSObject.class.isAssignableFrom(field.getDeclaringClass().getJavaClass()), "Field must be in JSObject class: %s", field);
7373
GraalError.guarantee(!field.isStatic(), "Field must not be static: %s", field);
7474
UserError.guarantee(!field.isFinal(), "Instance fields in subclasses of %s must not be final: %s", JSObject.class.getSimpleName(), field.format("%H.%n"));
75+
UserError.guarantee(field.isPublic() || field.isProtected(), "Only public and protected instance fields in subclasses of %s are allowed: %s", JSObject.class.getSimpleName(),
76+
field.format("%H.%n"));
7577
JSObjectAccessMethod accessMethod = accessMethods.computeIfAbsent(
7678
new AccessorDescription(field, isLoad),
7779
key -> createAccessMethod(aMetaAccess, field, isLoad));

web-image/src/com.oracle.svm.webimage.jtt/src/com/oracle/svm/webimage/jtt/api/JSObjectSubclassTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
public class JSObjectSubclassTest {
3232
public static final String[] OUTPUT = {
33+
// jsObjectSubclass
3334
"Declared(made in Java)",
3435
"made in Java",
3536
"Declared(made in JavaScript)",
@@ -56,12 +57,15 @@ public class JSObjectSubclassTest {
5657
"inner imported in Java",
5758
"InnerImported(inner exported from JavaScript)",
5859
"inner exported from JavaScript",
60+
// exportedReturningObject
5961
"non-exported subclass",
6062
"non-exported",
6163
"non-exported subclass",
6264
"non-exported",
65+
// heapGeneratedObjects
6366
"5",
6467
"8",
68+
// nonInstantiatedImported
6569
"7.0",
6670
};
6771

web-image/src/com.oracle.svm.webimage.jtt/src/com/oracle/svm/webimage/jtt/api/JavaDocExamplesTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class Rectangle extends JSObject {
189189

190190
@JS.Export
191191
class Randomizer extends JSObject {
192-
private Random rng = new Random(719513L);
192+
protected Random rng = new Random(719513L);
193193

194194
public byte[] randomBytes(int length) {
195195
byte[] bytes = new byte[length];

0 commit comments

Comments
 (0)