Skip to content

Commit

Permalink
Merge branch 'main' of github.com:brucehuke/Wasmnizer-ts into main
Browse files Browse the repository at this point in the history
  • Loading branch information
huke committed Dec 25, 2023
2 parents 598940c + b042839 commit f9ae25c
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 70 deletions.
2 changes: 1 addition & 1 deletion doc/developer-guide/basic_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ As shown in the graph above, the fundamental processing principles for different
- `user defined interface` is widely used in TypeScript, treating it as dynamic will largely influence the performance, so we introduced `meta` to apply static compilation
- `builtin objects` are objects provided by JavaScript runtime, TypeScript defines them as interface for type checking purpose.

- Implementing these built-in objects demands a significant amount of effort, so we treat them as `any` by default, this allows us to immediately use the standard library implementation already available in external environment. (see [fallback](../fallback.md))
- Implementing these built-in objects demands a significant amount of effort, so we treat them as `any` by default, this allows us to immediately use the standard library implementation already available in external environment. (see [fallback](./fallback.md))

- Simultaneously, we are working on static compilation solutions for selected built-in objects (e.g. `String`, `Array`) to improve performance. The priority of static compilation for these objects is determined based on their actual usage frequency.

Expand Down
146 changes: 131 additions & 15 deletions runtime-library/libdyntype/dynamic-simple/dyn-value/class/date.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,160 @@
#include "dyn_class.h"
#include <time.h>

/**
* @brief char* to time_t
*
* @param str year-month-day hour:minute:second, like
* "2023-12-23 15:58:12"
* @param t time_t addr
* @return int 0: success
*/
int
strtotime(const char *str, time_t *t)
{

int year, month, day, hour, minute, second;
struct tm tm_;

if (sscanf(str, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute,
&second)
!= 6) {
return -1;
}
if (hour < 0 || hour > 23) {
return -1;
}
tm_.tm_hour = hour;

if (minute < 0 || minute > 59) {
return -1;
}
tm_.tm_min = minute;

if (second < 0 || second > 59) {
return -1;
}
tm_.tm_sec = second;

tm_.tm_year = year - 1900;
tm_.tm_mon = month - 1;
tm_.tm_mday = day;
tm_.tm_isdst = 0;
*t = mktime(&tm_);

if (*t == -1)
return -1;

return 0;
}

/* Constructor (new Date()) */
DynValue *date_constructor(int argc, DynValue *argv[])
DynValue *
date_constructor(int argc, DynValue *argv[])
{
DyntypeObject *dyn_obj =
(DyntypeObject *)wasm_runtime_malloc(sizeof(DyntypeObject));
DyntypeDate *dyn_obj =
(DyntypeDate *)wasm_runtime_malloc(sizeof(DyntypeDate));
if (!dyn_obj) {
return NULL;
}

if (!init_dyn_object(dyn_obj, DynClassDate)) {
if (!init_dyn_object((DyntypeObject *)dyn_obj, DynClassDate)) {
wasm_runtime_free(dyn_obj);
return NULL;
}

if (argc == 0) {
dyn_obj->time = time(NULL);
}
else if (argc == 1 && argv[0]->class_id == DynClassString) {
DyntypeString *str = (DyntypeString *)argv[0];
if (strtotime(str->data, &dyn_obj->time) != 0) {
return NULL;
}
}
return (DynValue *)dyn_obj;
}

DynValue *date_get_full_year(DynValue *this_val, int argc, DynValue *argv[])
DynValue *
date_get_full_year(DynValue *this_val, int argc, DynValue *argv[])
{
/* TODO */
return dyn_value_new_undefined();
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));

return dyn_value_new_number((double)(1900 + timeval->tm_year));
}

DynValue *
date_get_month(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_mon));
}

DynValue *
date_get_date(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_mday));
}

DynValue *
date_get_day(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_wday));
}

DynValue *
date_get_hours(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_hour));
}

DynValue *
date_get_minutes(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_min));
}

DynValue *
date_get_seconds(DynValue *this_val, int argc, DynValue *argv[])
{
DyntypeDate *dyn_obj = (DyntypeDate *)this_val;
struct tm *timeval = localtime(&(dyn_obj->time));
return dyn_value_new_number((double)(timeval->tm_sec));
}

/* Date.prototype.xxx */
ClassMethod date_instance_methods[] = {
{ "getFullYear", date_get_full_year }
ClassMethod date_instance_methods[] = {
{ "getFullYear", date_get_full_year },
{ "getMonth", date_get_month },
{ "getDate", date_get_date },
{ "getDay", date_get_day },
{ "getHours", date_get_hours },
{ "getMinutes", date_get_minutes },
{ "getSeconds", date_get_seconds },
};

DynValue *date_now(DynValue *this_val, int argc, DynValue *argv[])
DynValue *
date_now(DynValue *this_val, int argc, DynValue *argv[])
{
// get unix timestamp
time_t now = time(NULL);
return dyn_value_new_number((double)now);
struct timeval start;
gettimeofday(&start, NULL);
return dyn_value_new_number(
(double)(start.tv_sec * 1000 + start.tv_usec / 1000));
}

/* Date.xxx */
ClassMethod date_class_methods[] = {
{ "now", date_now }
};
ClassMethod date_class_methods[] = { { "now", date_now } };

ClassMeta date_class_meta = {
.constructor = date_constructor,
Expand All @@ -53,6 +168,7 @@ ClassMeta date_class_meta = {
.inst_methods = date_instance_methods,
.class_method_num = sizeof(date_class_methods) / sizeof(ClassMethod),
.class_methods = date_class_methods,
.name = "Date"
};

/* Date, never free this object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ find_class_constructor(const char *name)
if (!meta)
continue;

assert(meta->name != NULL);

if (!strcmp(meta->name, name))
return meta->constructor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ClassMeta object_class_meta = {
.parent_class_id = DynClassNone,
.class_method_num = sizeof(object_class_methods) / sizeof(ClassMethod),
.class_methods = object_class_methods,
.name = "Object"
};

/* Object, never free this object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ ClassMeta string_class_meta = {
.parent_class_id = DynClassObject,
.inst_method_num = sizeof(string_inst_methods) / sizeof(ClassMethod),
.inst_methods = string_inst_methods,
.name = "String"
};
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ typedef struct DyntypeExtref {
int32_t ref;
} DyntypeExtref;

typedef struct DyntypeDate {
DyntypeObject base;
time_t time;
} DyntypeDate;

DynValue *
dyn_value_new_number(double value);

Expand Down
4 changes: 2 additions & 2 deletions src/backend/binaryen/wasm_expr_gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1950,12 +1950,12 @@ export class WASMExpressionGen {
index--;
}
/** it occupies two slots */
if (members[i].hasGetter && members[i].hasSetter) {
if (members[i].hasGetter || members[i].hasSetter) {
index++;
}
}

if (isSetter && member.hasGetter) {
if (isSetter) {
index++;
}

Expand Down
42 changes: 0 additions & 42 deletions src/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,23 +535,6 @@ export class Scope {
}
}

// shadow copy
copy(scope: Scope) {
scope.kind = this.kind;
scope.name = this.name;
scope.children = this.children;
scope.parent = this.parent;
scope.namedTypeMap = this.namedTypeMap;
scope.debugFilePath = this.debugFilePath;
scope.tempVarArray = this.tempVarArray;
scope.variableArray = this.variableArray;
scope.statementArray = this.statementArray;
scope.localIndex = this.localIndex;
scope.mangledName = this.mangledName;
scope.modifiers = this.modifiers;
if (this.genericOwner) scope.setGenericOwner(this.genericOwner);
}

// process generic specialization
specialize(scope: Scope) {
scope.kind = this.kind;
Expand Down Expand Up @@ -587,13 +570,6 @@ export class ClosureEnvironment extends Scope {
}
}

copy(scope: ClosureEnvironment) {
super.copy(scope);
scope.kind = this.kind;
scope.hasFreeVar = this.hasFreeVar;
scope.contextVariable = this.contextVariable;
}

specialize(scope: ClosureEnvironment) {
super.specialize(scope);
scope.kind = this.kind;
Expand Down Expand Up @@ -752,17 +728,6 @@ export class FunctionScope extends ClosureEnvironment {
return this._className !== '';
}

copy(funcScope: FunctionScope) {
super.copy(funcScope);
funcScope.kind = this.kind;
funcScope.parameterArray = this.parameterArray;
funcScope.functionType = this.functionType;
funcScope._className = this._className;
funcScope.realParamCtxType = this.realParamCtxType;
funcScope.oriFuncName = this.oriFuncName;
funcScope.debugLocations = this.debugLocations;
}

specialize(funcScope: FunctionScope) {
super.specialize(funcScope);
funcScope.kind = this.kind;
Expand Down Expand Up @@ -815,13 +780,6 @@ export class ClassScope extends Scope {
return this._classType;
}

copy(classScope: ClassScope) {
super.copy(classScope);
classScope.kind = this.kind;
classScope.name = this.name;
classScope._classType = this._classType;
}

specialize(classScope: ClassScope) {
super.specialize(classScope);
classScope.kind = this.kind;
Expand Down
10 changes: 0 additions & 10 deletions src/variable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,16 +254,6 @@ export class VariableScanner {
if (variableType instanceof TSEnum) {
variableType = variableType.memberType;
}
/* Sometimes the variable's type is inferred as a TSFunction with
isDeclare == true, we need to treat it as non declare function
here to keep the same calling convention for closure */
if (
variableType instanceof TSFunction &&
variableType.isDeclare
) {
variableType = variableType.clone();
(variableType as TSFunction).isDeclare = false;
}

const variable = new Variable(
variableName,
Expand Down
60 changes: 60 additions & 0 deletions tests/samples/class_accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,4 +311,64 @@ export function test15() {
const i3: I3 = new Z(1);
i3.ref = 2;
console.log(i3.ref);
}

class OnlySetter {
a = 1;

constructor(a: number) {
this.a = a;
this.foo();
this.bar();
}

foo() {
console.log('invoke foo');
}

set value(a: number) {
this.a = a;
}

bar() {
console.log('invoke bar');
}
}

export function testOnlySetter() {
const obj = new OnlySetter(10);
console.log(obj.a);
obj.a = 100;
console.log(obj.a);
}

class OnlyGetter {
a = 1;

constructor(a: number) {
this.a = a;
this.foo();
this.bar();
}

foo() {
console.log('invoke foo');
}


get value() : number {
return this.a;
}


bar() {
console.log('invoke bar');
}
}

export function testOnlyGetter() {
const obj = new OnlyGetter(10);
console.log(obj.value);
obj.a = 100;
console.log(obj.value);
}
Loading

0 comments on commit f9ae25c

Please sign in to comment.