aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Florian Weikert <fwe@google.com>2015-11-09 14:09:18 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-11-10 10:22:20 +0000
commita9dd72a7eda6dadf9448e68d4462aaebab429b89 (patch)
tree0dc61e89eee882a681a593632ea3b19ec91dd935 /src
parent7976797b234466c4519822fa302fafa68f3835d0 (diff)
Compile dot and not expressions to byte code.
-- MOS_MIGRATED_REVID=107378197
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/DotExpression.java43
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/NotExpression.java19
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeMethodCalls.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/compiler/ByteCodeUtils.java31
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.
*/