JS: add null check in strict mode

This commit is contained in:
Alexey Andreev 2019-10-04 18:44:05 +03:00
parent bffb50f0cd
commit 6f50eefaf9
9 changed files with 111 additions and 21 deletions

View File

@ -55,10 +55,10 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "newEmptyInstance":
context.getWriter().append("new ");
context.getWriter().append("new (");
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
context.getWriter().append('.').appendField(platformClassField);
context.getWriter().append("()");
context.getWriter().append(")");
break;
}
}

View File

@ -109,10 +109,11 @@ import org.teavm.model.lowlevel.Characteristics;
import org.teavm.model.lowlevel.ClassInitializerEliminator;
import org.teavm.model.lowlevel.ClassInitializerTransformer;
import org.teavm.model.lowlevel.ExportDependencyListener;
import org.teavm.model.lowlevel.NullCheckInsertion;
import org.teavm.model.lowlevel.LowLevelNullCheckFilter;
import org.teavm.model.lowlevel.NullCheckTransformation;
import org.teavm.model.lowlevel.ShadowStackTransformer;
import org.teavm.model.transformation.ClassPatch;
import org.teavm.model.transformation.NullCheckInsertion;
import org.teavm.model.util.AsyncMethodFinder;
import org.teavm.runtime.Allocator;
import org.teavm.runtime.CallSite;
@ -220,7 +221,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
classInitializerEliminator = new ClassInitializerEliminator(controller.getUnprocessedClassSource());
classInitializerTransformer = new ClassInitializerTransformer();
shadowStackTransformer = new ShadowStackTransformer(characteristics, !longjmpUsed);
nullCheckInsertion = new NullCheckInsertion(characteristics);
nullCheckInsertion = new NullCheckInsertion(new LowLevelNullCheckFilter(characteristics));
nullCheckTransformation = new NullCheckTransformation();
controller.addVirtualMethods(VIRTUAL_METHODS::contains);

View File

@ -95,7 +95,9 @@ import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.lowlevel.BoundCheckInsertion;
import org.teavm.model.transformation.BoundCheckInsertion;
import org.teavm.model.transformation.NullCheckFilter;
import org.teavm.model.transformation.NullCheckInsertion;
import org.teavm.model.util.AsyncMethodFinder;
import org.teavm.model.util.ProgramUtils;
import org.teavm.vm.BuildTarget;
@ -128,6 +130,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
private int topLevelNameLimit = 10000;
private AstDependencyExtractor dependencyExtractor = new AstDependencyExtractor();
private boolean strict;
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
private NullCheckInsertion nullCheckInsertion = new NullCheckInsertion(NullCheckFilter.EMPTY);
@Override
public List<ClassHolderTransformer> getTransformers() {
@ -339,7 +343,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
@Override
public void beforeOptimizations(Program program, MethodReader method) {
if (strict) {
new BoundCheckInsertion().transformProgram(program, method.getReference());
boundCheckInsertion.transformProgram(program, method.getReference());
nullCheckInsertion.transformProgram(program, method.getReference());
}
}

View File

@ -30,6 +30,7 @@ public enum Precedence {
ADDITION,
MULTIPLICATION,
UNARY,
NEW,
FUNCTION_CALL,
MEMBER_ACCESS,
GROUPING;

View File

@ -1113,6 +1113,11 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (injector != null) {
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
} else {
Precedence outerPrecedence = precedence;
if (outerPrecedence.ordinal() > Precedence.FUNCTION_CALL.ordinal()) {
writer.append('(');
}
if (expr.getType() == InvocationType.DYNAMIC) {
precedence = Precedence.MEMBER_ACCESS;
expr.getArguments().get(0).acceptVisitor(this);
@ -1184,6 +1189,10 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (shouldEraseCallSite) {
lastCallSite = null;
}
if (outerPrecedence.ordinal() > Precedence.FUNCTION_CALL.ordinal()) {
writer.append(')');
}
}
if (expr.getLocation() != null) {
popLocation();
@ -1224,14 +1233,14 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
}
Precedence outerPrecedence = precedence;
if (outerPrecedence.ordinal() > Precedence.FUNCTION_CALL.ordinal()) {
if (outerPrecedence.ordinal() > Precedence.NEW.ordinal()) {
writer.append('(');
}
precedence = Precedence.FUNCTION_CALL;
precedence = Precedence.NEW;
writer.append("new ").appendClass(expr.getConstructedClass());
if (outerPrecedence.ordinal() > Precedence.FUNCTION_CALL.ordinal()) {
if (outerPrecedence.ordinal() > Precedence.NEW.ordinal()) {
writer.append(')');
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2019 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.model.lowlevel;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
import org.teavm.model.transformation.NullCheckFilter;
public class LowLevelNullCheckFilter implements NullCheckFilter {
private Characteristics characteristics;
public LowLevelNullCheckFilter(Characteristics characteristics) {
this.characteristics = characteristics;
}
@Override
public boolean apply(FieldReference field) {
return !characteristics.isStructure(field.getClassName());
}
@Override
public boolean apply(MethodReference method) {
return characteristics.isManaged(method.getClassName()) && characteristics.isManaged(method);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 konsoletyper.
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.lowlevel;
package org.teavm.model.transformation;
import com.carrotsearch.hppc.IntArrayList;
import com.carrotsearch.hppc.IntHashSet;

View File

@ -0,0 +1,37 @@
/*
* Copyright 2019 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.model.transformation;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
public interface NullCheckFilter {
boolean apply(FieldReference field);
boolean apply(MethodReference method);
NullCheckFilter EMPTY = new NullCheckFilter() {
@Override
public boolean apply(FieldReference field) {
return true;
}
@Override
public boolean apply(MethodReference method) {
return true;
}
};
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2018 Alexey Andreev.
* Copyright 2019 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.lowlevel;
package org.teavm.model.transformation;
import com.carrotsearch.hppc.IntHashSet;
import com.carrotsearch.hppc.IntSet;
@ -39,14 +39,14 @@ import org.teavm.model.util.DominatorWalkerCallback;
import org.teavm.model.util.PhiUpdater;
public class NullCheckInsertion {
private Characteristics characteristics;
private NullCheckFilter filter;
public NullCheckInsertion(Characteristics characteristics) {
this.characteristics = characteristics;
public NullCheckInsertion(NullCheckFilter filter) {
this.filter = filter;
}
public void transformProgram(Program program, MethodReference methodReference) {
if (!characteristics.isManaged(methodReference) || program.basicBlockCount() == 0) {
if (!filter.apply(methodReference) || program.basicBlockCount() == 0) {
return;
}
@ -99,14 +99,14 @@ public class NullCheckInsertion {
@Override
public void visit(GetFieldInstruction insn) {
if (!characteristics.isStructure(insn.getField().getClassName())) {
if (filter.apply(insn.getField())) {
addGuard(insn, GetFieldInstruction::getInstance, GetFieldInstruction::setInstance);
}
}
@Override
public void visit(PutFieldInstruction insn) {
if (!characteristics.isStructure(insn.getField().getClassName())) {
if (filter.apply(insn.getField())) {
addGuard(insn, PutFieldInstruction::getInstance, PutFieldInstruction::setInstance);
}
}
@ -123,8 +123,7 @@ public class NullCheckInsertion {
@Override
public void visit(InvokeInstruction insn) {
if (!characteristics.isStructure(insn.getMethod().getClassName())
&& characteristics.isManaged(insn.getMethod())) {
if (filter.apply(insn.getMethod())) {
addGuard(insn, InvokeInstruction::getInstance, InvokeInstruction::setInstance);
}
}