C: support methods of Date class

This commit is contained in:
Alexey Andreev 2019-05-21 15:17:58 +03:00
parent bb9ca77349
commit 7f875aa568
6 changed files with 325 additions and 30 deletions

View File

@ -18,9 +18,7 @@ package org.teavm.classlib.java.lang.reflect;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.teavm.dependency.AbstractDependencyListener; import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent; import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyNode; import org.teavm.dependency.DependencyNode;
@ -44,7 +42,6 @@ import org.teavm.platform.PlatformAnnotationProvider;
import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformClass;
public class AnnotationDependencyListener extends AbstractDependencyListener { public class AnnotationDependencyListener extends AbstractDependencyListener {
private Set<MethodReference> reachedMethods = new HashSet<>();
private static final MethodReference GET_ANNOTATIONS_METHOD = new MethodReference( private static final MethodReference GET_ANNOTATIONS_METHOD = new MethodReference(
Platform.class, "getAnnotations", PlatformClass.class, Annotation[].class); Platform.class, "getAnnotations", PlatformClass.class, Annotation[].class);
private static final String ANNOTATIONS_READER_SUFFIX = "$$__annotations__$$"; private static final String ANNOTATIONS_READER_SUFFIX = "$$__annotations__$$";
@ -120,10 +117,6 @@ public class AnnotationDependencyListener extends AbstractDependencyListener {
@Override @Override
public void methodReached(DependencyAgent agent, MethodDependency method) { public void methodReached(DependencyAgent agent, MethodDependency method) {
if (!reachedMethods.add(method.getReference())) {
return;
}
ValueType type = method.getMethod().getResultType(); ValueType type = method.getMethod().getResultType();
while (type instanceof ValueType.Array) { while (type instanceof ValueType.Array) {
type = ((ValueType.Array) type).getItemType(); type = ((ValueType.Array) type).getItemType();

View File

@ -19,11 +19,23 @@ import java.util.TimeZone;
import org.teavm.classlib.PlatformDetector; import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.java.lang.TComparable; import org.teavm.classlib.java.lang.TComparable;
import org.teavm.classlib.java.lang.TSystem; import org.teavm.classlib.java.lang.TSystem;
import org.teavm.interop.Import;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.core.JSDate; import org.teavm.jso.core.JSDate;
public class TDate implements TComparable<TDate> { public class TDate implements TComparable<TDate> {
private long value; private long value;
static {
if (PlatformDetector.isLowLevel()) {
initLowLevel();
}
}
@Import(name = "teavm_date_init")
@NoSideEffects
private static native void initLowLevel();
public TDate() { public TDate() {
value = TSystem.currentTimeMillis(); value = TSystem.currentTimeMillis();
} }
@ -44,10 +56,18 @@ public class TDate implements TComparable<TDate> {
@Deprecated @Deprecated
public TDate(int year, int month, int date, int hrs, int min, int sec) { public TDate(int year, int month, int date, int hrs, int min, int sec) {
this((long) JSDate.create(year, month, date, hrs, min, sec).getTime()); this(PlatformDetector.isLowLevel()
setYear(year); ? initDateLowLevel(year, month, date, hrs, min, sec)
: (long) JSDate.create(year, month, date, hrs, min, sec).getTime());
if (!PlatformDetector.isLowLevel()) {
setYear(year);
}
} }
@Import(name = "teavm_date_create")
@NoSideEffects
private static native long initDateLowLevel(int year, int month, int date, int hrs, int min, int sec);
public TDate(String s) { public TDate(String s) {
this(parse(s)); this(parse(s));
} }
@ -59,11 +79,23 @@ public class TDate implements TComparable<TDate> {
@Deprecated @Deprecated
public static long UTC(int year, int month, int date, int hrs, int min, int sec) { public static long UTC(int year, int month, int date, int hrs, int min, int sec) {
return (long) JSDate.UTC(year, month, date, hrs, min, sec); if (PlatformDetector.isLowLevel()) {
return initUtcDateLowLevel(year, month, date, hrs, min, sec);
} else {
return (long) JSDate.UTC(year, month, date, hrs, min, sec);
}
} }
@Import(name = "teavm_date_createUtc")
@NoSideEffects
private static native long initUtcDateLowLevel(int year, int month, int date, int hrs, int min, int sec);
@Deprecated @Deprecated
public static long parse(String s) { public static long parse(String s) {
if (PlatformDetector.isLowLevel()) {
return parseLowLevel(s);
}
double value = JSDate.parse(s); double value = JSDate.parse(s);
if (Double.isNaN(value)) { if (Double.isNaN(value)) {
throw new IllegalArgumentException("Can't parse date: " + s); throw new IllegalArgumentException("Can't parse date: " + s);
@ -71,83 +103,183 @@ public class TDate implements TComparable<TDate> {
return (long) value; return (long) value;
} }
@Import(name = "teavm_date_parse")
@NoSideEffects
private static native long parseLowLevel(String s);
@Deprecated @Deprecated
public int getYear() { public int getYear() {
if (PlatformDetector.isLowLevel()) {
return getYearLowLevel(value);
}
return JSDate.create(value).getFullYear() - 1900; return JSDate.create(value).getFullYear() - 1900;
} }
@Import(name = "teavm_date_getYear")
@NoSideEffects
private static native int getYearLowLevel(long date);
@Deprecated @Deprecated
public void setYear(int year) { public void setYear(int year) {
if (PlatformDetector.isLowLevel()) {
value = setYearLowLevel(value, year);
return;
}
JSDate date = JSDate.create(value); JSDate date = JSDate.create(value);
date.setFullYear(year + 1900); date.setFullYear(year + 1900);
this.value = (long) date.getTime(); value = (long) date.getTime();
} }
@Import(name = "teavm_date_setYear")
@NoSideEffects
private static native long setYearLowLevel(long date, int year);
@Deprecated @Deprecated
public int getMonth() { public int getMonth() {
if (PlatformDetector.isLowLevel()) {
return getMonthLowLevel(value);
}
return JSDate.create(value).getMonth(); return JSDate.create(value).getMonth();
} }
@Import(name = "teavm_date_getMonth")
@NoSideEffects
private static native int getMonthLowLevel(long date);
@Deprecated @Deprecated
public void setMonth(int month) { public void setMonth(int month) {
if (PlatformDetector.isLowLevel()) {
value = setMonthLowLevel(value, month);
return;
}
JSDate date = JSDate.create(value); JSDate date = JSDate.create(value);
date.setMonth(month); date.setMonth(month);
this.value = (long) date.getTime(); value = (long) date.getTime();
} }
@Import(name = "teavm_date_setMonth")
@NoSideEffects
private static native long setMonthLowLevel(long date, int month);
@Deprecated @Deprecated
public int getDate() { public int getDate() {
if (PlatformDetector.isLowLevel()) {
return getDateLowLevel(value);
}
return JSDate.create(value).getDate(); return JSDate.create(value).getDate();
} }
@Import(name = "teavm_date_getDate")
@NoSideEffects
private static native int getDateLowLevel(long date);
@Deprecated @Deprecated
public void setDate(int date) { public void setDate(int date) {
if (PlatformDetector.isLowLevel()) {
value = setDateLowLevel(value, date);
return;
}
JSDate d = JSDate.create(value); JSDate d = JSDate.create(value);
d.setDate(date); d.setDate(date);
this.value = (long) d.getTime(); this.value = (long) d.getTime();
} }
@Import(name = "teavm_date_setDate")
@NoSideEffects
private static native int setDateLowLevel(long target, int date);
@Deprecated @Deprecated
public int getDay() { public int getDay() {
if (PlatformDetector.isLowLevel()) {
return getDayLowLevel(value);
}
return JSDate.create(value).getDay(); return JSDate.create(value).getDay();
} }
@Import(name = "teavm_date_getDay")
public static native int getDayLowLevel(long date);
@Deprecated @Deprecated
public int getHours() { public int getHours() {
if (PlatformDetector.isLowLevel()) {
return getHoursLowLevel(value);
}
return JSDate.create(value).getHours(); return JSDate.create(value).getHours();
} }
@Import(name = "teavm_date_getHours")
@NoSideEffects
private static native int getHoursLowLevel(long date);
@Deprecated @Deprecated
public void setHours(int hours) { public void setHours(int hours) {
if (PlatformDetector.isLowLevel()) {
value = setHoursLowLevel(value, hours);
return;
}
JSDate date = JSDate.create(value); JSDate date = JSDate.create(value);
date.setHours(hours); date.setHours(hours);
this.value = (long) date.getTime(); value = (long) date.getTime();
} }
@Import(name = "teavm_date_setHours")
@NoSideEffects
private static native int setHoursLowLevel(long date, int hours);
@Deprecated @Deprecated
public int getMinutes() { public int getMinutes() {
if (PlatformDetector.isLowLevel()) {
return getMinutesLowLevel(value);
}
return JSDate.create(value).getMinutes(); return JSDate.create(value).getMinutes();
} }
@Import(name = "teavm_date_getMinutes")
@NoSideEffects
private static native int getMinutesLowLevel(long date);
@Deprecated @Deprecated
public void setMinutes(int minutes) { public void setMinutes(int minutes) {
if (PlatformDetector.isLowLevel()) {
value = setMinutesLowLevel(value, minutes);
return;
}
JSDate date = JSDate.create(value); JSDate date = JSDate.create(value);
date.setMinutes(minutes); date.setMinutes(minutes);
this.value = (long) date.getTime(); this.value = (long) date.getTime();
} }
@Import(name = "teavm_date_setMinutes")
@NoSideEffects
private static native int setMinutesLowLevel(long date, int minutes);
@Deprecated @Deprecated
public int getSeconds() { public int getSeconds() {
if (PlatformDetector.isLowLevel()) {
return getSecondsLowLevel(value);
}
return JSDate.create(value).getSeconds(); return JSDate.create(value).getSeconds();
} }
@Import(name = "teavm_date_getSeconds")
@NoSideEffects
private static native int getSecondsLowLevel(long date);
@Deprecated @Deprecated
public void setSeconds(int seconds) { public void setSeconds(int seconds) {
if (PlatformDetector.isLowLevel()) {
value = setSecondsLowLevel(value, seconds);
return;
}
JSDate date = JSDate.create(value); JSDate date = JSDate.create(value);
date.setSeconds(seconds); date.setSeconds(seconds);
this.value = (long) date.getTime(); this.value = (long) date.getTime();
} }
@Import(name = "teavm_date_setSeconds")
@NoSideEffects
private static native int setSecondsLowLevel(long date, int seconds);
public long getTime() { public long getTime() {
return value; return value;
} }
@ -186,12 +318,16 @@ public class TDate implements TComparable<TDate> {
@Override @Override
public String toString() { public String toString() {
if (PlatformDetector.isLowLevel()) { if (PlatformDetector.isLowLevel()) {
return ""; return toStringLowLevel(value);
} else { } else {
return JSDate.create(value).stringValue(); return JSDate.create(value).stringValue();
} }
} }
@Import(name = "teavm_date_format")
@NoSideEffects
private static native String toStringLowLevel(long date);
@Deprecated @Deprecated
public String toLocaleString() { public String toLocaleString() {
return JSDate.create(value).toLocaleFormat("%c"); return JSDate.create(value).toLocaleFormat("%c");

View File

@ -347,8 +347,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
} }
emitResource(runtimeHeaderWriter, "runtime.h"); emitResource(runtimeHeaderWriter, "runtime.h");
ClassGenerator classGenerator = new ClassGenerator(context, controller.getUnprocessedClassSource(), ClassGenerator classGenerator = new ClassGenerator(context, tagRegistry, decompiler);
tagRegistry, decompiler);
IntrinsicFactoryContextImpl intrinsicFactoryContext = new IntrinsicFactoryContextImpl( IntrinsicFactoryContextImpl intrinsicFactoryContext = new IntrinsicFactoryContextImpl(
controller.getUnprocessedClassSource(), controller.getClassLoader(), controller.getServices(), controller.getUnprocessedClassSource(), controller.getClassLoader(), controller.getServices(),
controller.getProperties()); controller.getProperties());
@ -365,6 +364,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget); OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
copyResource("stringhash.c", buildTarget); copyResource("stringhash.c", buildTarget);
copyResource("references.c", buildTarget); copyResource("references.c", buildTarget);
copyResource("date.c", buildTarget);
generateCallSites(buildTarget, context, classes.getClassNames()); generateCallSites(buildTarget, context, classes.getClassNames());
generateStrings(buildTarget, context); generateStrings(buildTarget, context);
@ -637,6 +637,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
includes.includePath("stringhash.c"); includes.includePath("stringhash.c");
includes.includePath("strings.c"); includes.includePath("strings.c");
includes.includePath("callsites.c"); includes.includePath("callsites.c");
includes.includePath("references.c");
includes.includePath("date.c");
for (String className : classes.getClassNames()) { for (String className : classes.getClassNames()) {
includes.includePath(ClassGenerator.fileName(className) + ".c"); includes.includePath(ClassGenerator.fileName(className) + ".c");

View File

@ -38,7 +38,6 @@ import org.teavm.model.AnnotationHolder;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.FieldHolder; import org.teavm.model.FieldHolder;
import org.teavm.model.FieldReader; import org.teavm.model.FieldReader;
@ -78,7 +77,6 @@ public class ClassGenerator {
)); ));
private GenerationContext context; private GenerationContext context;
private ClassReaderSource unprocessedClassSource;
private Decompiler decompiler; private Decompiler decompiler;
private TagRegistry tagRegistry; private TagRegistry tagRegistry;
private CodeGenerator codeGenerator; private CodeGenerator codeGenerator;
@ -91,10 +89,8 @@ public class ClassGenerator {
private IncludeManager includes; private IncludeManager includes;
private IncludeManager headerIncludes; private IncludeManager headerIncludes;
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource, public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler) {
TagRegistry tagRegistry, Decompiler decompiler) {
this.context = context; this.context = context;
this.unprocessedClassSource = unprocessedClassSource;
this.tagRegistry = tagRegistry; this.tagRegistry = tagRegistry;
this.decompiler = decompiler; this.decompiler = decompiler;
} }
@ -436,7 +432,7 @@ public class ClassGenerator {
String className = null; String className = null;
if (type instanceof ValueType.Object) { if (type instanceof ValueType.Object) {
className = ((ValueType.Object) type).getClassName(); className = ((ValueType.Object) type).getClassName();
generateVirtualTableStructure(unprocessedClassSource.get(className)); generateVirtualTableStructure(className);
} else if (type instanceof ValueType.Array) { } else if (type instanceof ValueType.Array) {
className = "java.lang.Object"; className = "java.lang.Object";
} }
@ -633,20 +629,17 @@ public class ClassGenerator {
codeWriter.println(".init = " + initFunction); codeWriter.println(".init = " + initFunction);
} }
private void generateVirtualTableStructure(ClassReader cls) { private void generateVirtualTableStructure(String className) {
if (cls == null) { String name = context.getNames().forClassClass(className);
return;
}
String name = context.getNames().forClassClass(cls.getName());
headerWriter.print("typedef struct ").print(name).println(" {").indent(); headerWriter.print("typedef struct ").print(name).println(" {").indent();
headerWriter.println("TeaVM_Class parent;"); headerWriter.println("TeaVM_Class parent;");
VirtualTable virtualTable = context.getVirtualTableProvider().lookup(cls.getName()); VirtualTable virtualTable = context.getVirtualTableProvider().lookup(className);
if (virtualTable != null) { if (virtualTable != null) {
for (VirtualTableEntry entry : virtualTable.getEntries().values()) { for (VirtualTableEntry entry : virtualTable.getEntries().values()) {
String methodName = context.getNames().forVirtualMethod( String methodName = context.getNames().forVirtualMethod(
new MethodReference(cls.getName(), entry.getMethod())); new MethodReference(className, entry.getMethod()));
headerWriter.printType(entry.getMethod().getResultType()) headerWriter.printType(entry.getMethod().getResultType())
.print(" (*").print(methodName).print(")("); .print(" (*").print(methodName).print(")(");
codeGenerator.generateMethodParameters(headerWriter, entry.getMethod(), false, false); codeGenerator.generateMethodParameters(headerWriter, entry.getMethod(), false, false);

View File

@ -0,0 +1,152 @@
#include "runtime.h"
#define _XOPEN_SOURCE
#define __USE_XOPEN
#define _GNU_SOURCE
#include <time.h>
static time_t teavm_epochStart;
static struct tm teavm_epochStartTm;
static char teavm_date_formatBuffer[512];
static char* teavm_date_defaultFormat = "%a %b %d %H:%M:%S %Z %Y";
void teavm_date_init() {
struct tm epochStart = {
.tm_year = 70,
.tm_mon = 0,
.tm_mday = 1,
.tm_hour = 0,
.tm_min = 0,
.tm_sec = 0,
.tm_isdst = -1
};
teavm_epochStart = timegm(&epochStart);
localtime_r(&teavm_epochStart, &teavm_epochStartTm);
}
inline static int64_t teavm_date_timestamp(struct tm *t) {
time_t result = mktime(t);
return (int64_t) (1000 * difftime(result, teavm_epochStart));
}
inline static struct tm* teavm_date_decompose(int64_t timestamp, struct tm *t) {
*t = teavm_epochStartTm;
t->tm_sec += timestamp / 1000;
mktime(t);
return t;
}
int64_t teavm_date_create(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second) {
struct tm t = {
.tm_year = year,
.tm_mon = month,
.tm_mday = day,
.tm_hour = hour,
.tm_min = minute,
.tm_sec = second,
.tm_isdst = -1
};
return teavm_date_timestamp(&t);
}
int64_t teavm_date_createUtc(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second) {
struct tm t = {
.tm_year = year,
.tm_mon = month,
.tm_mday = day,
.tm_hour = hour,
.tm_min = minute,
.tm_sec = second,
.tm_isdst = -1
};
time_t result = timegm(&t);
return (int64_t) (1000 * difftime(result, teavm_epochStart));
}
int64_t teavm_date_parse(char* s) {
struct tm t;
strptime(s, teavm_date_defaultFormat, &t);
time_t result = mktime(&t);
return (int64_t) (1000 * difftime(result, teavm_epochStart));
}
int32_t teavm_date_getYear(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_year;
}
int64_t teavm_date_setYear(int64_t time, int32_t year) {
struct tm t;
teavm_date_decompose(time, &t)->tm_year = year;
return teavm_date_timestamp(&t);
}
int32_t teavm_date_getMonth(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_mon;
}
int64_t teavm_date_setMonth(int64_t time, int32_t month) {
struct tm t;
teavm_date_decompose(time, &t)->tm_mon = month;
return teavm_date_timestamp(&t);
}
int32_t teavm_date_getDate(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_mday;
}
int64_t teavm_date_setDate(int64_t time, int32_t date) {
struct tm t;
teavm_date_decompose(time, &t)->tm_mday = date;
return teavm_date_timestamp(&t);
}
int32_t teavm_date_getDay(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_wday;
}
int32_t teavm_date_getHours(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_hour;
}
int64_t teavm_date_setHours(int64_t time, int32_t hours) {
struct tm t;
teavm_date_decompose(time, &t)->tm_hour = hours;
return teavm_date_timestamp(&t);
}
int32_t teavm_date_getMinutes(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_min;
}
int64_t teavm_date_setMinutes(int64_t time, int32_t minutes) {
struct tm t;
teavm_date_decompose(time, &t)->tm_min = minutes;
return teavm_date_timestamp(&t);
}
int32_t teavm_date_getSeconds(int64_t time) {
struct tm t;
return (int32_t) teavm_date_decompose(time, &t)->tm_sec;
}
int64_t teavm_date_setSeconds(int64_t time, int32_t seconds) {
struct tm t;
teavm_date_decompose(time, &t)->tm_sec = seconds;
return teavm_date_timestamp(&t);
}
char* teavm_date_format(int64_t time) {
struct tm t;
t = teavm_epochStartTm;
t.tm_sec += time / 1000;
mktime(&t);
strftime(teavm_date_formatBuffer, 512, teavm_date_defaultFormat, &t);
return teavm_date_formatBuffer;
}

View File

@ -275,4 +275,23 @@ extern TeaVM_Object* teavm_reference_get(TeaVM_Reference*);
extern TeaVM_Reference* teavm_reference_poll(TeaVM_ReferenceQueue*); extern TeaVM_Reference* teavm_reference_poll(TeaVM_ReferenceQueue*);
extern void teavm_reference_init(TeaVM_Reference*, TeaVM_Object*, TeaVM_ReferenceQueue*); extern void teavm_reference_init(TeaVM_Reference*, TeaVM_Object*, TeaVM_ReferenceQueue*);
extern void teavm_date_init();
extern int64_t teavm_date_create(int32_t,int32_t,int32_t,int32_t,int32_t,int32_t);
extern int64_t teavm_date_createUtc(int32_t,int32_t,int32_t,int32_t,int32_t,int32_t);
extern int64_t teavm_date_parse(char* s);
extern int32_t teavm_date_getYear(int64_t);
extern int64_t teavm_date_setYear(int64_t,int32_t);
extern int32_t teavm_date_getMonth(int64_t);
extern int64_t teavm_date_setMonth(int64_t,int32_t);
extern int32_t teavm_date_getDate(int64_t);
extern int64_t teavm_date_setDate(int64_t,int32_t);
extern int32_t teavm_date_getDay(int64_t);
extern int32_t teavm_date_getHours(int64_t);
extern int64_t teavm_date_setHours(int64_t,int32_t);
extern int32_t teavm_date_getMinutes(int64_t);
extern int64_t teavm_date_setMinutes(int64_t,int32_t);
extern int32_t teavm_date_getSeconds(int64_t);
extern int64_t teavm_date_setSeconds(int64_t,int32_t);
extern char* teavm_date_format(int64_t);