Skip to content

Commit

Permalink
[js] Very basic int64 and uint64 support
Browse files Browse the repository at this point in the history
  • Loading branch information
pmurias committed Oct 11, 2018
1 parent 21a7529 commit 788b1cc
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 12 deletions.
10 changes: 10 additions & 0 deletions src/core/NativeTypes.nqp
Expand Up @@ -18,13 +18,23 @@ my module EXPORTHOW {
nqp::scwbenable();
}

#?if js
my native int is repr('P6int') is nativesize(32) { }
#?endif
#?if !js
my native int is repr('P6int') { }
#?endif
my native int64 is repr('P6int') is nativesize(64) { }
my native int32 is repr('P6int') is nativesize(32) { }
my native int16 is repr('P6int') is nativesize(16) { }
my native int8 is repr('P6int') is nativesize( 8) { }

#?if js
my native uint is repr('P6int') is nativesize(32) is unsigned { }
#?endif
#?if !js
my native uint is repr('P6int') is unsigned { }
#?endif
my native uint64 is repr('P6int') is nativesize(64) is unsigned { }
my native uint32 is repr('P6int') is nativesize(32) is unsigned { }
my native uint16 is repr('P6int') is nativesize(16) is unsigned { }
Expand Down
3 changes: 3 additions & 0 deletions src/vm/js/Chunk.nqp
Expand Up @@ -15,6 +15,9 @@ my $T_UINT16 := 9; # We use a javascript number but always treat it as a 16bit i
my $T_UINT8 := 10; # We use a javascript number but always treat it as a 8bit integer
my $T_UINT32 := 11; # We use a javascript number but always treat it as a unsigned 32bit integer

my $T_INT64 := 12; # We use a BigInt but treat it as a signed 64bit integer
my $T_UINT64 := 13; # We use a BigInt but treat it as a unsigned 64bit integer

my $T_VOID := -1; # Value of this type shouldn't exist, we use a "" as the expr
my $T_NONVAL := -2; # something that is not a nqp value

Expand Down
32 changes: 27 additions & 5 deletions src/vm/js/Compiler.nqp
Expand Up @@ -677,7 +677,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
}

if $desired == $T_STR {
if $got_int || $got == $T_UINT32 {
if $got_int || $got == $T_UINT32 || $got == $T_INT64 || $got == $T_UINT64 {
return Chunk.new($T_STR, $chunk.expr ~ '.toString()', $chunk);
}
elsif $got == $T_NUM {
Expand Down Expand Up @@ -714,9 +714,11 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
%convert{$T_INT} := 'intToObj';
%convert{$T_INT8} := 'intToObj';
%convert{$T_INT16} := 'intToObj';
%convert{$T_INT64} := 'int64ToObj';
%convert{$T_UINT8} := 'intToObj';
%convert{$T_UINT16} := 'intToObj';
%convert{$T_UINT32} := 'intToObj';
%convert{$T_UINT64} := 'int64ToObj';
%convert{$T_NUM} := 'numToObj';
%convert{$T_STR} := 'strToObj';
%convert{$T_RETVAL} := 'retval';
Expand All @@ -735,6 +737,18 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
}
}

if $desired == $T_UINT64 {
if $got == $T_INT64 {
return Chunk.new($T_UINT64, "BigInt.asUintN(64, {$chunk.expr})", $chunk);
}
}

if $desired == $T_INT64 {
if $got == $T_UINT64 {
return Chunk.new($T_INT64, "BigInt.asIntN(64, {$chunk.expr})", $chunk);
}
}

if self.is_fancy_int($desired) {
my $int_chunk := $got == $T_INT ?? $chunk !! self.coerce($chunk, $T_INT);
return Chunk.new($desired, self.int_to_fancy_int($desired, $int_chunk.expr) , $int_chunk);
Expand Down Expand Up @@ -1399,7 +1413,12 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {


multi method as_js(QAST::IVal $node, :$want) {
Chunk.new($T_INT,'('~$node.value()~')', :$node);
if $want == $T_INT64 || $want == $T_UINT64 {
Chunk.new($want,'('~$node.value()~'n)', :$node);
} else {
# TODO think about 64bit values
Chunk.new($T_INT,'('~$node.value()~')', :$node);
}
}

multi method as_js(QAST::NVal $node, :$want) {
Expand Down Expand Up @@ -1614,7 +1633,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
}


my @types := [$T_OBJ, $T_INT, $T_NUM, $T_STR];
my @types := [$T_OBJ, $T_INT, $T_NUM, $T_STR, $T_INT64, $T_UINT64];
method type_from_typeobj($typeobj) {
my int $type := nqp::objprimspec($typeobj);
if $type == 1 {
Expand All @@ -1632,12 +1651,15 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
else {
$T_INT;
}
} else {
}
else {
@types[$type];
}
}

my @suffix := ['', '_i', '_n', '_s'];
@suffix[$T_INT64] := '_i64';
@suffix[$T_UINT64] := '_u64';

method suffix_from_type($type) {
self.is_fancy_int($type) ?? '_i' !! @suffix[$type];
Expand Down Expand Up @@ -1747,7 +1769,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
Chunk.void($check, "if (!{$check.expr}) return nqp.paramcheckfailed(HLL, $*CTX, Array.prototype.slice.call(arguments));\n");
}

my %default_value := nqp::hash($T_OBJ, 'nqp.Null', $T_INT, '0', $T_NUM, '0', $T_STR, 'nqp.null_s', $T_INT16, '0', $T_INT8, '0', $T_UINT8, '0', $T_UINT16, '0', $T_UINT32, '0');
my %default_value := nqp::hash($T_OBJ, 'nqp.Null', $T_INT, '0', $T_NUM, '0', $T_STR, 'nqp.null_s', $T_INT16, '0', $T_INT8, '0', $T_UINT8, '0', $T_UINT16, '0', $T_UINT32, '0', $T_UINT64, '0n', $T_INT64, '0n');

method declare_var(QAST::Var $node) {
my int $type := self.type_from_typeobj($node.returns);
Expand Down
9 changes: 9 additions & 0 deletions src/vm/js/Operations.nqp
Expand Up @@ -147,6 +147,8 @@ class QAST::OperationsJS {

method OBJ() { $T_OBJ }
method INT() { $T_INT }
method INT64() { $T_INT64 }
method UINT64() { $T_UINT64 }
method STR() { $T_STR }
method NUM() { $T_NUM }
method BOOL() { $T_BOOL }
Expand Down Expand Up @@ -182,6 +184,8 @@ class QAST::OperationsJS {
add_assign_op('assign_n', $T_NUM);
add_assign_op('assign_s', $T_STR);

add_assign_op('assign_i64', $T_INT64);
add_assign_op('assign_u64', $T_UINT64);

add_simple_op('decont', $T_OBJ, [$T_OBJ], :method_call, :ctx, :await);

Expand Down Expand Up @@ -256,6 +260,11 @@ class QAST::OperationsJS {
add_simple_op('gcd_i', $T_INT, [$T_INT, $T_INT]);
add_simple_op('lcm_i', $T_INT, [$T_INT, $T_INT]);


# 64 bit integer arithmetic
add_simple_op('add_i64', $T_INT64, [$T_INT64, $T_INT64], sub ($a, $b) {"BigInt.asIntN(64, $a + $b)"});
add_simple_op('sub_i64', $T_INT64, [$T_INT64, $T_INT64], sub ($a, $b) {"BigInt.asIntN(64, $a - $b)"});

add_op('chain', sub ($comp, $node, :$want) {
my str $ret := $*BLOCK.add_tmp;

Expand Down
48 changes: 48 additions & 0 deletions src/vm/js/nqp-runtime/container-specs.js
Expand Up @@ -248,6 +248,54 @@ class NativeRef {
this.set(value.$$getStr());
}
});
} else if (primitiveType == 4) { // int64
this.STable.addInternalMethods(class {
$$iscont_s() {
return 1;
}

$$iscont() {
return 1;
}

$$isrwcont() {
return 1;
}

$$assign_i64(ctx, value) {
this.set(value);
}

$$assign_u64(ctx, value) {
this.set(value);
}

$$getStr() {
return this.get().toString();
}

$$getInt64() {
return this.get();
}

$$getUint64() {
return BigInt.asUintN(64, this.get());
}

$$decont(ctx) {
let hll = STable.hllOwner;
if (hll === undefined) {
hll = ctx.codeRef().staticCode.hll;
}

const type = hll.get('int_box');

const repr = type._STable.REPR;
const obj = repr.allocate(type._STable);
obj.$$setInt64(this.get());
return obj;
}
});
} else {
throw 'incorrect type of NativeRef: ' + primitiveType;
}
Expand Down
14 changes: 13 additions & 1 deletion src/vm/js/nqp-runtime/core.js
Expand Up @@ -206,6 +206,18 @@ const intToObj = exports.intToObj = function(currentHLL, i) {
}
};

exports.int64ToObj = function(currentHLL, i) {
const type = currentHLL.get('int_box');
if (!type) {
return new NQPInt(i);
} else {
const repr = type._STable.REPR;
const obj = repr.allocate(type._STable);
obj.$$setInt64(i);
return obj;
}
};

const numToObj = exports.numToObj = function(currentHLL, n) {
const type = currentHLL.get('num_box');
if (!type) {
Expand Down Expand Up @@ -1159,7 +1171,7 @@ op.objprimspec = function(obj) {
} else if (obj instanceof NQPStr) {
return 3;
} else {
return (obj._STable && obj._STable.REPR.boxedPrimitive ? obj._STable.REPR.boxedPrimitive : 0);
return (obj._STable && obj._STable.REPR.boxedPrimitive ? obj._STable.REPR.boxedPrimitive() : 0);
}
} else {
throw new NQPException(`objprimspec can't handle things of type: ${typeof obj}`);
Expand Down
14 changes: 14 additions & 0 deletions src/vm/js/nqp-runtime/refs.js
Expand Up @@ -106,6 +106,20 @@ helpers.lexRef_i = function(currentHLL, get, set) {
return ref;
};

helpers.lexRef_i64 = function(currentHLL, get, set) {
const refType = currentHLL.get('int64_lex_ref');
if (refType === undefined) {
throw 'No int64 lexical reference type registered for current HLL';
}
const STable = refType._STable;
const ref = STable.REPR.allocate(STable);
ref.get = get;
ref.set = set;
return ref;
};

helpers.lexRef_u64 = helpers.lexRef_i64;

helpers.lexRef_s = function(currentHLL, get, set) {
const refType = currentHLL.get('str_lex_ref');
if (refType === undefined) {
Expand Down

0 comments on commit 788b1cc

Please sign in to comment.