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

View File

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

View File

@ -347,8 +347,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
}
emitResource(runtimeHeaderWriter, "runtime.h");
ClassGenerator classGenerator = new ClassGenerator(context, controller.getUnprocessedClassSource(),
tagRegistry, decompiler);
ClassGenerator classGenerator = new ClassGenerator(context, tagRegistry, decompiler);
IntrinsicFactoryContextImpl intrinsicFactoryContext = new IntrinsicFactoryContextImpl(
controller.getUnprocessedClassSource(), controller.getClassLoader(), controller.getServices(),
controller.getProperties());
@ -365,6 +364,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
copyResource("stringhash.c", buildTarget);
copyResource("references.c", buildTarget);
copyResource("date.c", buildTarget);
generateCallSites(buildTarget, context, classes.getClassNames());
generateStrings(buildTarget, context);
@ -637,6 +637,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
includes.includePath("stringhash.c");
includes.includePath("strings.c");
includes.includePath("callsites.c");
includes.includePath("references.c");
includes.includePath("date.c");
for (String className : classes.getClassNames()) {
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.ClassHolder;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldHolder;
import org.teavm.model.FieldReader;
@ -78,7 +77,6 @@ public class ClassGenerator {
));
private GenerationContext context;
private ClassReaderSource unprocessedClassSource;
private Decompiler decompiler;
private TagRegistry tagRegistry;
private CodeGenerator codeGenerator;
@ -91,10 +89,8 @@ public class ClassGenerator {
private IncludeManager includes;
private IncludeManager headerIncludes;
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource,
TagRegistry tagRegistry, Decompiler decompiler) {
public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler) {
this.context = context;
this.unprocessedClassSource = unprocessedClassSource;
this.tagRegistry = tagRegistry;
this.decompiler = decompiler;
}
@ -436,7 +432,7 @@ public class ClassGenerator {
String className = null;
if (type instanceof ValueType.Object) {
className = ((ValueType.Object) type).getClassName();
generateVirtualTableStructure(unprocessedClassSource.get(className));
generateVirtualTableStructure(className);
} else if (type instanceof ValueType.Array) {
className = "java.lang.Object";
}
@ -633,20 +629,17 @@ public class ClassGenerator {
codeWriter.println(".init = " + initFunction);
}
private void generateVirtualTableStructure(ClassReader cls) {
if (cls == null) {
return;
}
String name = context.getNames().forClassClass(cls.getName());
private void generateVirtualTableStructure(String className) {
String name = context.getNames().forClassClass(className);
headerWriter.print("typedef struct ").print(name).println(" {").indent();
headerWriter.println("TeaVM_Class parent;");
VirtualTable virtualTable = context.getVirtualTableProvider().lookup(cls.getName());
VirtualTable virtualTable = context.getVirtualTableProvider().lookup(className);
if (virtualTable != null) {
for (VirtualTableEntry entry : virtualTable.getEntries().values()) {
String methodName = context.getNames().forVirtualMethod(
new MethodReference(cls.getName(), entry.getMethod()));
new MethodReference(className, entry.getMethod()));
headerWriter.printType(entry.getMethod().getResultType())
.print(" (*").print(methodName).print(")(");
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

@ -276,3 +276,22 @@ extern TeaVM_Object* teavm_reference_get(TeaVM_Reference*);
extern TeaVM_Reference* teavm_reference_poll(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);