painless: Make field stores not box; use GeneratorAdapter.invokeDynmaic for consistency with other method calls

This commit is contained in:
Uwe Schindler 2016-05-15 10:30:11 +02:00
parent c183e4b6eb
commit 604bcd9320
6 changed files with 67 additions and 16 deletions

View File

@ -0,0 +1,39 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.painless.node;
import org.elasticsearch.painless.Definition.Type;
/**
* The superclass for all LDef* (link) nodes that store or return a DEF. (Internal only.)
*/
abstract class ADefLink extends ALink {
/**
* The type of the original type that was pushed on stack, set by {@link EChain} during analyze.
* This value is only used for writing the 'store' bytecode, otherwise ignored.
*/
Type storeValueType = null;
ADefLink(final int line, final String location, final int size) {
super(line, location, size);
}
}

View File

@ -222,8 +222,17 @@ public final class EChain extends AExpression {
private void analyzeWrite(final CompilerSettings settings, final Definition definition, final Variables variables) {
final ALink last = links.get(links.size() - 1);
expression.expected = last.after;
expression.analyze(settings, definition, variables);
// If the store node is a DEF node, we remove the cast to DEF from the expression
// and promote the real type to it:
if (last instanceof ADefLink) {
final ADefLink lastDef = (ADefLink) last;
expression.analyze(settings, definition, variables);
lastDef.storeValueType = expression.expected = expression.actual;
} else {
// otherwise we adapt the type of the expression to the store type
expression.expected = last.after;
expression.analyze(settings, definition, variables);
}
expression = expression.cast(settings, definition, variables);
statement = true;

View File

@ -59,9 +59,6 @@ public final class LCall extends ALink {
method = statik ? struct.functions.get(name) : struct.methods.get(name);
if (method != null) {
final Definition.Type[] types = new Definition.Type[method.arguments.size()];
method.arguments.toArray(types);
if (method.arguments.size() != arguments.size()) {
throw new IllegalArgumentException(error("When calling [" + name + "] on type [" + struct.name + "]" +
" expected [" + method.arguments.size() + "] arguments, but found [" + arguments.size() + "]."));
@ -70,7 +67,7 @@ public final class LCall extends ALink {
for (int argument = 0; argument < arguments.size(); ++argument) {
final AExpression expression = arguments.get(argument);
expression.expected = types[argument];
expression.expected = method.arguments.get(argument);
expression.analyze(settings, definition, variables);
arguments.set(argument, expression.cast(settings, definition, variables));
}

View File

@ -31,7 +31,7 @@ import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
/**
* Represents an array load/store or shortcut on a def type. (Internal only.)
*/
final class LDefArray extends ALink {
final class LDefArray extends ADefLink {
AExpression index;
@ -61,13 +61,16 @@ final class LDefArray extends ALink {
@Override
void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
final String desc = Type.getMethodDescriptor(after.type, definition.defType.type, index.actual.type);
adapter.visitInvokeDynamicInsn("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_LOAD);
adapter.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_LOAD);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
if (storeValueType == null) {
throw new IllegalStateException(error("Illegal tree structure."));
}
final String desc = Type.getMethodDescriptor(definition.voidType.type, definition.defType.type,
index.actual.type, definition.defType.type);
adapter.visitInvokeDynamicInsn("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_STORE);
index.actual.type, storeValueType.type);
adapter.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_STORE);
}
}

View File

@ -32,7 +32,7 @@ import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
/**
* Represents a method call made on a def type. (Internal only.)
*/
final class LDefCall extends ALink {
final class LDefCall extends ADefLink {
final String name;
final List<AExpression> arguments;
@ -84,7 +84,7 @@ final class LDefCall extends ALink {
// return value
signature.append(after.type.getDescriptor());
adapter.visitInvokeDynamicInsn(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.METHOD_CALL);
adapter.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.METHOD_CALL);
}
@Override

View File

@ -31,7 +31,7 @@ import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
/**
* Represents a field load/store or shortcut on a def type. (Internal only.)
*/
final class LDefField extends ALink {
final class LDefField extends ADefLink {
final String value;
@ -57,12 +57,15 @@ final class LDefField extends ALink {
@Override
void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
final String desc = Type.getMethodDescriptor(after.type, definition.defType.type);
adapter.visitInvokeDynamicInsn(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.LOAD);
adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.LOAD);
}
@Override
void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
final String desc = Type.getMethodDescriptor(definition.voidType.type, definition.defType.type, definition.defType.type);
adapter.visitInvokeDynamicInsn(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.STORE);
if (storeValueType == null) {
throw new IllegalStateException(error("Illegal tree structure."));
}
final String desc = Type.getMethodDescriptor(definition.voidType.type, definition.defType.type, storeValueType.type);
adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.STORE);
}
}