mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Adds optional support of throwing NPE when calling method on null
instance
This commit is contained in:
parent
43acca8706
commit
b4347b4eb8
|
@ -138,11 +138,10 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
|
|||
writer.append("var cls = " + self + ".$data;").softNewLine();
|
||||
writer.append("var ctor = cls.$$constructor$$;").softNewLine();
|
||||
writer.append("if (!ctor) {").indent().softNewLine();
|
||||
/*writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine();
|
||||
writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine();
|
||||
writer.appendMethodBody(new MethodReference(InstantiationException.class.getName(), new MethodDescriptor(
|
||||
"<init>", ValueType.VOID))).append("(ex);").softNewLine();*/
|
||||
//writer.append("$rt_throw(ex);").softNewLine();
|
||||
writer.append("return null;").softNewLine();
|
||||
"<init>", ValueType.VOID))).append("(ex);").softNewLine();
|
||||
writer.append("$rt_throw(ex);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("var instance = new cls();").softNewLine();
|
||||
writer.append("ctor(instance);").softNewLine();
|
||||
|
@ -180,6 +179,10 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
|
|||
case "getDeclaringClass":
|
||||
graph.getResult().propagate("java.lang.Class");
|
||||
break;
|
||||
case "newInstance":
|
||||
checker.linkMethod(new MethodReference(InstantiationException.class.getName(), "<init>",
|
||||
ValueType.VOID), graph.getStack()).use();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ public class TClass<T> extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(ClassNativeGenerator.class)
|
||||
@PluggableDependency(ClassNativeGenerator.class)
|
||||
public native T newInstance() throws TInstantiationException, TIllegalAccessException;
|
||||
|
||||
@GeneratedBy(ClassNativeGenerator.class)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.javascript;
|
||||
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class NullPointerExceptionTransformer implements ClassHolderTransformer {
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
Program program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
transformBlock(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void transformBlock(BasicBlock block) {
|
||||
for (int i = 0; i < block.getInstructions().size(); ++i) {
|
||||
Instruction insn = block.getInstructions().get(i);
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction)insn;
|
||||
if (invoke.getType() != InvocationType.VIRTUAL) {
|
||||
continue;
|
||||
}
|
||||
InvokeInstruction checkInvoke = new InvokeInstruction();
|
||||
checkInvoke.setMethod(new MethodReference(RuntimeSupport.class.getName(), "requireNonNull",
|
||||
ValueType.object("java.lang.Object"), ValueType.VOID));
|
||||
checkInvoke.setType(InvocationType.SPECIAL);
|
||||
checkInvoke.getArguments().add(invoke.getInstance());
|
||||
block.getInstructions().add(i++, checkInvoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.javascript;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class RuntimeSupport {
|
||||
private RuntimeSupport() {
|
||||
}
|
||||
|
||||
public static void requireNonNull(Object obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,9 +90,9 @@
|
|||
<scanDependencies>true</scanDependencies>
|
||||
<outputDir>${project.build.directory}/javascript-tck</outputDir>
|
||||
<adapterClass>org.teavm.html4j.testing.KOTestAdapter</adapterClass>
|
||||
<!-- <wildcards>
|
||||
<param>net.java.html.js.tests.*Test</param>
|
||||
</wildcards> -->
|
||||
<transformers>
|
||||
<param>org.teavm.javascript.NullPointerExceptionTransformer</param>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package org.teavm.maven;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
@ -33,6 +35,7 @@ import org.apache.maven.project.MavenProject;
|
|||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.javascript.JavascriptBuilder;
|
||||
import org.teavm.javascript.JavascriptBuilderFactory;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
@ -77,6 +80,9 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
@Parameter(required = false)
|
||||
private int numThreads = 1;
|
||||
|
||||
@Parameter
|
||||
private String[] transformers;
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -109,6 +115,14 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
public String[] getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
public void setTransformers(String[] transformers) {
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException {
|
||||
Log log = getLog();
|
||||
|
@ -133,6 +147,9 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
builder.setMinifying(minifying);
|
||||
builder.setBytecodeLogging(bytecodeLogging);
|
||||
builder.installPlugins();
|
||||
for (ClassHolderTransformer transformer : instantiateTransformers(classLoader)) {
|
||||
builder.add(transformer);
|
||||
}
|
||||
builder.prepare();
|
||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf(
|
||||
ValueType.object("java.lang.String")), ValueType.VOID);
|
||||
|
@ -167,6 +184,41 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
}
|
||||
}
|
||||
|
||||
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
|
||||
throws MojoExecutionException {
|
||||
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
|
||||
if (transformers == null) {
|
||||
return transformerInstances;
|
||||
}
|
||||
for (String transformerName : transformers) {
|
||||
Class<?> transformerRawType;
|
||||
try {
|
||||
transformerRawType = Class.forName(transformerName, true, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
|
||||
}
|
||||
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
|
||||
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
|
||||
ClassHolderTransformer.class.getName());
|
||||
}
|
||||
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
|
||||
ClassHolderTransformer.class);
|
||||
Constructor<? extends ClassHolderTransformer> ctor;
|
||||
try {
|
||||
ctor = transformerType.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor");
|
||||
}
|
||||
try {
|
||||
ClassHolderTransformer transformer = ctor.newInstance();
|
||||
transformerInstances.add(transformer);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new MojoExecutionException("Error instantiating transformer " + transformerName, e);
|
||||
}
|
||||
}
|
||||
return transformerInstances;
|
||||
}
|
||||
|
||||
private ClassLoader prepareClassLoader() throws MojoExecutionException {
|
||||
try {
|
||||
Log log = getLog();
|
||||
|
|
|
@ -90,6 +90,11 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private String adapterClass = JUnitTestAdapter.class.getName();
|
||||
|
||||
@Parameter
|
||||
private String[] transformers;
|
||||
|
||||
private List<ClassHolderTransformer> transformerInstances;
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -122,6 +127,14 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
this.wildcards = wildcards;
|
||||
}
|
||||
|
||||
public String[] getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
public void setTransformers(String[] transformers) {
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||
Runnable finalizer = null;
|
||||
|
@ -148,6 +161,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
findTests(classHolder);
|
||||
}
|
||||
|
||||
transformerInstances = instantiateTransformers(classLoader);
|
||||
File allTestsFile = new File(outputDir, "tests/all.js");
|
||||
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
|
||||
allTestsWriter.write("doRunTests = function() {\n");
|
||||
|
@ -291,6 +305,9 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
JavascriptBuilder builder = builderFactory.create();
|
||||
builder.setMinifying(minifying);
|
||||
builder.installPlugins();
|
||||
for (ClassHolderTransformer transformer : transformerInstances) {
|
||||
builder.add(transformer);
|
||||
}
|
||||
builder.prepare();
|
||||
File file = new File(outputDir, targetName);
|
||||
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
|
||||
|
@ -453,4 +470,39 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
|
||||
throws MojoExecutionException {
|
||||
List<ClassHolderTransformer> transformerInstances = new ArrayList<>();
|
||||
if (transformers == null) {
|
||||
return transformerInstances;
|
||||
}
|
||||
for (String transformerName : transformers) {
|
||||
Class<?> transformerRawType;
|
||||
try {
|
||||
transformerRawType = Class.forName(transformerName, true, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
|
||||
}
|
||||
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
|
||||
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
|
||||
ClassHolderTransformer.class.getName());
|
||||
}
|
||||
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
|
||||
ClassHolderTransformer.class);
|
||||
Constructor<? extends ClassHolderTransformer> ctor;
|
||||
try {
|
||||
ctor = transformerType.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor");
|
||||
}
|
||||
try {
|
||||
ClassHolderTransformer transformer = ctor.newInstance();
|
||||
transformerInstances.add(transformer);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new MojoExecutionException("Error instantiating transformer " + transformerName, e);
|
||||
}
|
||||
}
|
||||
return transformerInstances;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user