diff options
author | 2015-11-09 14:09:18 +0000 | |
---|---|---|
committer | 2015-11-10 10:22:20 +0000 | |
commit | a9dd72a7eda6dadf9448e68d4462aaebab429b89 (patch) | |
tree | 0dc61e89eee882a681a593632ea3b19ec91dd935 /src | |
parent | 7976797b234466c4519822fa302fafa68f3835d0 (diff) |
Compile dot and not expressions to byte code.
--
MOS_MIGRATED_REVID=107378197
Diffstat (limited to 'src')
4 files changed, 99 insertions, 2 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java index e8482a7020..84805e9724 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java @@ -16,7 +16,15 @@ package com.google.devtools.build.lib.syntax; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.syntax.FuncallExpression.MethodDescriptor; +import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils; +import com.google.devtools.build.lib.syntax.compiler.DebugInfo; +import com.google.devtools.build.lib.syntax.compiler.VariableScope; +import net.bytebuddy.implementation.bytecode.ByteCodeAppender; +import net.bytebuddy.implementation.bytecode.Duplication; +import net.bytebuddy.implementation.bytecode.constant.TextConstant; + +import java.util.ArrayList; import java.util.List; /** @@ -52,14 +60,22 @@ public final class DotExpression extends Expression { Object objValue = obj.eval(env); String name = field.getName(); Object result = eval(objValue, name, getLocation(), env); + return checkResult(objValue, result, name, getLocation()); + } + + /** + * Throws the correct error message if the result is null depending on the objValue. + */ + public static Object checkResult(Object objValue, Object result, String name, Location loc) + throws EvalException { if (result == null) { if (objValue instanceof ClassObject) { String customErrorMessage = ((ClassObject) objValue).errorMessage(name); if (customErrorMessage != null) { - throw new EvalException(getLocation(), customErrorMessage); + throw new EvalException(loc, customErrorMessage); } } - throw new EvalException(getLocation(), Printer.format("Object of type '%s' has no field %r", + throw new EvalException(loc, Printer.format("Object of type '%s' has no field %r", EvalUtils.getDataTypeName(objValue), name)); } return result; @@ -96,6 +112,7 @@ public final class DotExpression extends Expression { return FuncallExpression.callMethod(method, name, objValue, new Object[] {}, loc, env); } } + return null; } @@ -108,4 +125,26 @@ public final class DotExpression extends Expression { void validate(ValidationEnvironment env) throws EvalException { obj.validate(env); } + + @Override + ByteCodeAppender compile(VariableScope scope, DebugInfo debugInfo) throws EvalException { + List<ByteCodeAppender> code = new ArrayList<>(); + code.add(obj.compile(scope, debugInfo)); + TextConstant name = new TextConstant(field.getName()); + ByteCodeUtils.append( + code, + Duplication.SINGLE, + name, + debugInfo.add(this).loadLocation, + scope.loadEnvironment(), + ByteCodeUtils.invoke(DotExpression.class, "eval", Object.class, String.class, + Location.class, Environment.class), + // at this point we have the value of obj and the result of eval on the stack + name, + debugInfo.add(this).loadLocation, + ByteCodeUtils.invoke(DotExpression.class, "checkResult", Object.class, Object.class, + String.class, Location.class) + ); + return ByteCodeUtils.compoundAppender(code); + } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/NotExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/NotExpression.java index 72aca2ba9b..75b93e7553 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/NotExpression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/NotExpression.java @@ -13,6 +13,13 @@ // limitations under the License. package com.google.devtools.build.lib.syntax; +import com.google.devtools.build.lib.syntax.compiler.ByteCodeMethodCalls; +import com.google.devtools.build.lib.syntax.compiler.ByteCodeUtils; +import com.google.devtools.build.lib.syntax.compiler.DebugInfo; +import com.google.devtools.build.lib.syntax.compiler.VariableScope; + +import net.bytebuddy.implementation.bytecode.ByteCodeAppender; + /** * As syntax node for the not boolean operation. */ @@ -47,4 +54,16 @@ public class NotExpression extends Expression { void validate(ValidationEnvironment env) throws EvalException { expression.validate(env); } + + @Override + ByteCodeAppender compile(VariableScope scope, DebugInfo debugInfo) throws EvalException { + // since there is no byte code logical negation + // compile expression and convert to boolean then negate and convert back to Boolean + return new ByteCodeAppender.Compound( + expression.compile(scope, debugInfo), + new ByteCodeAppender.Simple( + EvalUtils.toBoolean, + ByteCodeUtils.intLogicalNegation(), + ByteCodeMethodCalls.BCBoolean.valueOf)); + } } diff --git a/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeMethodCalls.java b/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeMethodCalls.java index a699a17d46..8fe0346d33 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeMethodCalls.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeMethodCalls.java @@ -28,6 +28,14 @@ import net.bytebuddy.implementation.bytecode.StackManipulation; public class ByteCodeMethodCalls { /** + * Byte code invocations for {@link Boolean}. + */ + public static class BCBoolean { + public static final StackManipulation valueOf = + ByteCodeUtils.invoke(Boolean.class, "valueOf", boolean.class); + } + + /** * Byte code invocations for {@link ImmutableList}. */ public static class BCImmutableList { diff --git a/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeUtils.java index 832d4e3e51..4e7abf863b 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeUtils.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeUtils.java @@ -13,6 +13,8 @@ // limitations under the License. package com.google.devtools.build.lib.syntax.compiler; +import com.google.devtools.build.lib.syntax.compiler.Jump.PrimitiveComparison; + import net.bytebuddy.description.method.MethodDescription.ForLoadedMethod; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.generic.GenericTypeDescription; @@ -20,6 +22,7 @@ import net.bytebuddy.implementation.bytecode.ByteCodeAppender; import net.bytebuddy.implementation.bytecode.ByteCodeAppender.Compound; import net.bytebuddy.implementation.bytecode.Removal; import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.implementation.bytecode.constant.IntegerConstant; import net.bytebuddy.implementation.bytecode.member.FieldAccess; import net.bytebuddy.implementation.bytecode.member.MethodInvocation; @@ -70,6 +73,34 @@ public class ByteCodeUtils { } /** + * Build a {@link StackManipulation} that logically negates an integer on the stack. + * + * <p>Java byte code does not have an instruction for this, so this produces a conditional jump + * which puts 0/1 on the stack. + */ + public static StackManipulation intLogicalNegation() { + return intToPrimitiveBoolean(PrimitiveComparison.NOT_EQUAL); + } + + /** + * Build a {@link StackManipulation} that converts an integer to 0/1 depending on a comparison + * with 0. + */ + public static StackManipulation intToPrimitiveBoolean(PrimitiveComparison operator) { + LabelAdder afterLabel = new LabelAdder(); + LabelAdder putFalseLabel = new LabelAdder(); + return new StackManipulation.Compound( + Jump.ifIntOperandToZero(operator).to(putFalseLabel), + // otherwise put "false" on the stack and jump to end + IntegerConstant.ONE, + Jump.to(afterLabel.getLabel()), + // add label for "else" and put "true" on the stack + putFalseLabel, + IntegerConstant.ZERO, + afterLabel); + } + + /** * Builds a {@link StackManipulation} that invokes the method identified via reflection on the * given class, method and parameter types. */ |