Repair Class.getEnumConstants()

This commit is contained in:
konsoletyper 2015-02-26 23:28:01 +03:00
parent eba560d373
commit a9ff14b599
12 changed files with 187 additions and 66 deletions

View File

@ -403,7 +403,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append("],").ws();
int flags = 0;
if (cls.getModifiers().contains(NodeModifier.ENUM)) {
flags &= 1;
flags |= 1;
}
writer.append(flags).append(',').ws();
MethodHolder clinit = classSource.get(cls.getName()).getMethod(

View File

@ -328,23 +328,6 @@ function $rt_assertNotNaN(value) {
}
return value;
}
function $rt_methodStubs(data) {
for (var i = 0; i < data.length; i += 2) {
var clinit = data[i + 0];
var names = data[i + 1];
if (!(names instanceof Array)) {
names = [names];
}
for (var j = 0; j < names.length; j = (j + 1) | 0) {
window[names[j]] = (function(name, clinit) {
return function() {
clinit();
return window[name].apply(window, arguments);
}
})(names[j], clinit);
}
}
}
var $rt_stdoutBuffer = "";
function $rt_putStdout(ch) {
if (ch == 0xA) {
@ -420,35 +403,6 @@ function $rt_metadata(data) {
}
}
}
function $rt_virtualMethods(cls) {
for (var i = 1; i < arguments.length; i += 2) {
var name = arguments[i];
var func = arguments[i + 1];
if (typeof name === 'string') {
cls.prototype[name] = func;
} else {
for (var j = 0; j < name.length; ++j) {
cls.prototype[name[j]] = func;
}
}
}
}
function $rt_virtualMethods(data) {
for (var i = 0; i < data.length; i += 2) {
var cls = data[i + 0];
var methods = data[i + 1];
for (var j = 0; j < methods.length; j += 2) {
var name = methods[j + 0];
var func = methods[j + 1];
if (typeof name === 'string') {
name = [name];
}
for (var k = 0; k < name.length; ++k) {
cls.prototype[name[k]] = func;
}
}
}
}
function $rt_asyncResult(value) {
return function() {
return value;

View File

@ -20,6 +20,7 @@ import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.InjectedBy;
import org.teavm.jso.JS;
import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.StaticFieldResource;
import org.teavm.platform.plugin.PlatformGenerator;
/**
@ -90,6 +91,10 @@ public final class Platform {
@InjectedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
public static native Object objectFromResource(StaticFieldResource resource);
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
public static native Enum<?>[] getEnumConstants(PlatformClass cls);
@GeneratedBy(PlatformGenerator.class)

View File

@ -17,6 +17,7 @@ package org.teavm.platform.metadata;
import java.util.Properties;
import org.teavm.common.ServiceRepository;
import org.teavm.model.FieldReference;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.platform.Platform;
import org.teavm.vm.TeaVM;
@ -55,6 +56,12 @@ public interface MetadataGeneratorContext extends ServiceRepository {
*/
ClassResource createClassResource(String className);
/**
* Creates a new resource that represents static field. Client code then may use
* {@link Platform#objectFromResource(StaticFieldResource)} to get actual field value.
*/
StaticFieldResource createFieldResource(FieldReference field);
/**
* Creates a new resource array.
*/

View File

@ -0,0 +1,23 @@
/*
* Copyright 2015 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.platform.metadata;
/**
*
* @author Alexey Andreev
*/
public interface StaticFieldResource extends Resource {
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2015 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.platform.plugin;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.model.FieldReference;
import org.teavm.platform.metadata.StaticFieldResource;
/**
*
* @author Alexey Andreev
*/
class BuildTimeStaticFieldResource implements StaticFieldResource, ResourceWriter {
private FieldReference field;
public BuildTimeStaticFieldResource(FieldReference field) {
this.field = field;
}
public FieldReference getField() {
return field;
}
@Override
public void write(SourceWriter writer) throws IOException {
writer.appendField(field);
}
}

View File

@ -18,6 +18,7 @@ package org.teavm.platform.plugin;
import java.lang.reflect.Proxy;
import java.util.Properties;
import org.teavm.common.ServiceRepository;
import org.teavm.model.FieldReference;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.platform.metadata.*;
@ -72,6 +73,11 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
return new BuildTimeClassResource(className);
}
@Override
public StaticFieldResource createFieldResource(FieldReference field) {
return new BuildTimeStaticFieldResource(field);
}
@Override
public <T extends Resource> ResourceMap<T> createResourceMap() {
return new BuildTimeResourceMap<>();

View File

@ -16,11 +16,7 @@
package org.teavm.platform.plugin;
import org.teavm.dependency.*;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.ValueType;
import org.teavm.model.*;
import org.teavm.platform.Platform;
/**
@ -29,7 +25,6 @@ import org.teavm.platform.Platform;
*/
public class EnumDependencySupport implements DependencyListener {
private DependencyNode allEnums;
private boolean unlocked;
@Override
public void started(DependencyAgent agent) {
@ -43,21 +38,25 @@ public class EnumDependencySupport implements DependencyListener {
return;
}
allEnums.propagate(agent.getType(className));
if (unlocked) {
MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName()))));
if (method != null) {
agent.linkMethod(method.getReference(), location).use();
}
}
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) {
if (method.getReference().getClassName().equals(Platform.class.getName()) &&
method.getReference().getName().equals("getEnumConstants")) {
unlocked = true;
allEnums.connect(method.getResult().getArrayItem());
final MethodReference ref = method.getReference();
allEnums.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
ClassReader cls = agent.getClassSource().get(type.getName());
MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName()))));
if (method != null) {
agent.linkMethod(method.getReference(), new CallLocation(ref)).use();
}
}
});
method.getResult().propagate(agent.getType("[java.lang.Enum"));
for (String cls : agent.getAchievableClasses()) {
classAchieved(agent, cls, location);

View File

@ -0,0 +1,54 @@
/*
* Copyright 2015 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.platform.plugin;
import org.teavm.dependency.*;
import org.teavm.model.CallLocation;
import org.teavm.platform.Platform;
/**
*
* @author Alexey Andreev
*/
public class PlatformDependencyListener implements DependencyListener {
private DependencyNode allClasses;
@Override
public void started(DependencyAgent agent) {
allClasses = agent.createNode();
}
@Override
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
allClasses.propagate(agent.getType(className));
}
@Override
public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) {
if (!method.getReference().getClassName().equals(Platform.class.getName())) {
return;
}
switch (method.getReference().getName()) {
case "objectFromResource":
allClasses.connect(method.getResult());
break;
}
}
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
}
}

View File

@ -26,6 +26,7 @@ import org.teavm.javascript.spi.Injector;
import org.teavm.javascript.spi.InjectorContext;
import org.teavm.model.*;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformClass;
import org.teavm.platform.PlatformRunnable;
/**
@ -58,12 +59,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
switch (methodRef.getName()) {
case "asJavaClass":
case "classFromResource":
case "objectFromResource":
context.writeExpr(context.getArgument(0));
return;
case "getEnumConstants":
context.writeExpr(context.getArgument(0));
context.getWriter().append(".values()");
break;
}
}
@ -85,6 +83,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
case "schedule":
generateSchedule(context, writer, true);
break;
case "getEnumConstants":
generateEnumConstants(context, writer);
break;
}
}
@ -203,4 +204,30 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
writer.outdent().append("},").ws().append(timeout ? context.getParameterName(2) : "0")
.append(");").softNewLine();
}
private void generateEnumConstants(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("var c").ws().append("=").ws().append("'$$enumConstants$$';").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(clsName))));
if (method != null) {
writer.appendClass(clsName).append("[c]").ws().append("=").ws();
writer.appendMethodBody(method.getReference());
writer.append(";").softNewLine();
}
}
String selfName = writer.getNaming().getFullNameFor(new MethodReference(Platform.class, "getEnumConstants",
PlatformClass.class, Enum[].class));
writer.append(selfName).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine().indent();
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
writer.append("return null;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return cls[c]();").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("return ").append(selfName).append("(").append(context.getParameterName(1))
.append(");").softNewLine();
}
}

View File

@ -33,5 +33,6 @@ public class PlatformPlugin implements TeaVMPlugin {
host.add(new NewInstanceDependencySupport());
host.add(new ClassLookupDependencySupport());
host.add(new EnumDependencySupport());
host.add(new PlatformDependencyListener());
}
}

View File

@ -36,6 +36,9 @@ class ResourceAccessorDependencyListener implements DependencyListener {
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
if (!method.getReference().getClassName().equals(ResourceAccessor.class.getName())) {
return;
}
switch (method.getReference().getName()) {
case "castToString":
method.getResult().propagate(agent.getType("java.lang.String"));