Skip to content

Commit 788b1cc

Browse files
committed
[js] Very basic int64 and uint64 support
1 parent 21a7529 commit 788b1cc

File tree

9 files changed

+186
-12
lines changed

9 files changed

+186
-12
lines changed

src/core/NativeTypes.nqp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,23 @@ my module EXPORTHOW {
1818
nqp::scwbenable();
1919
}
2020

21+
#?if js
22+
my native int is repr('P6int') is nativesize(32) { }
23+
#?endif
24+
#?if !js
2125
my native int is repr('P6int') { }
26+
#?endif
2227
my native int64 is repr('P6int') is nativesize(64) { }
2328
my native int32 is repr('P6int') is nativesize(32) { }
2429
my native int16 is repr('P6int') is nativesize(16) { }
2530
my native int8 is repr('P6int') is nativesize( 8) { }
2631

32+
#?if js
33+
my native uint is repr('P6int') is nativesize(32) is unsigned { }
34+
#?endif
35+
#?if !js
2736
my native uint is repr('P6int') is unsigned { }
37+
#?endif
2838
my native uint64 is repr('P6int') is nativesize(64) is unsigned { }
2939
my native uint32 is repr('P6int') is nativesize(32) is unsigned { }
3040
my native uint16 is repr('P6int') is nativesize(16) is unsigned { }

src/vm/js/Chunk.nqp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ my $T_UINT16 := 9; # We use a javascript number but always treat it as a 16bit i
1515
my $T_UINT8 := 10; # We use a javascript number but always treat it as a 8bit integer
1616
my $T_UINT32 := 11; # We use a javascript number but always treat it as a unsigned 32bit integer
1717

18+
my $T_INT64 := 12; # We use a BigInt but treat it as a signed 64bit integer
19+
my $T_UINT64 := 13; # We use a BigInt but treat it as a unsigned 64bit integer
20+
1821
my $T_VOID := -1; # Value of this type shouldn't exist, we use a "" as the expr
1922
my $T_NONVAL := -2; # something that is not a nqp value
2023

src/vm/js/Compiler.nqp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
677677
}
678678

679679
if $desired == $T_STR {
680-
if $got_int || $got == $T_UINT32 {
680+
if $got_int || $got == $T_UINT32 || $got == $T_INT64 || $got == $T_UINT64 {
681681
return Chunk.new($T_STR, $chunk.expr ~ '.toString()', $chunk);
682682
}
683683
elsif $got == $T_NUM {
@@ -714,9 +714,11 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
714714
%convert{$T_INT} := 'intToObj';
715715
%convert{$T_INT8} := 'intToObj';
716716
%convert{$T_INT16} := 'intToObj';
717+
%convert{$T_INT64} := 'int64ToObj';
717718
%convert{$T_UINT8} := 'intToObj';
718719
%convert{$T_UINT16} := 'intToObj';
719720
%convert{$T_UINT32} := 'intToObj';
721+
%convert{$T_UINT64} := 'int64ToObj';
720722
%convert{$T_NUM} := 'numToObj';
721723
%convert{$T_STR} := 'strToObj';
722724
%convert{$T_RETVAL} := 'retval';
@@ -735,6 +737,18 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
735737
}
736738
}
737739

740+
if $desired == $T_UINT64 {
741+
if $got == $T_INT64 {
742+
return Chunk.new($T_UINT64, "BigInt.asUintN(64, {$chunk.expr})", $chunk);
743+
}
744+
}
745+
746+
if $desired == $T_INT64 {
747+
if $got == $T_UINT64 {
748+
return Chunk.new($T_INT64, "BigInt.asIntN(64, {$chunk.expr})", $chunk);
749+
}
750+
}
751+
738752
if self.is_fancy_int($desired) {
739753
my $int_chunk := $got == $T_INT ?? $chunk !! self.coerce($chunk, $T_INT);
740754
return Chunk.new($desired, self.int_to_fancy_int($desired, $int_chunk.expr) , $int_chunk);
@@ -1399,7 +1413,12 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
13991413

14001414

14011415
multi method as_js(QAST::IVal $node, :$want) {
1402-
Chunk.new($T_INT,'('~$node.value()~')', :$node);
1416+
if $want == $T_INT64 || $want == $T_UINT64 {
1417+
Chunk.new($want,'('~$node.value()~'n)', :$node);
1418+
} else {
1419+
# TODO think about 64bit values
1420+
Chunk.new($T_INT,'('~$node.value()~')', :$node);
1421+
}
14031422
}
14041423

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

16161635

1617-
my @types := [$T_OBJ, $T_INT, $T_NUM, $T_STR];
1636+
my @types := [$T_OBJ, $T_INT, $T_NUM, $T_STR, $T_INT64, $T_UINT64];
16181637
method type_from_typeobj($typeobj) {
16191638
my int $type := nqp::objprimspec($typeobj);
16201639
if $type == 1 {
@@ -1632,12 +1651,15 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce {
16321651
else {
16331652
$T_INT;
16341653
}
1635-
} else {
1654+
}
1655+
else {
16361656
@types[$type];
16371657
}
16381658
}
16391659

16401660
my @suffix := ['', '_i', '_n', '_s'];
1661+
@suffix[$T_INT64] := '_i64';
1662+
@suffix[$T_UINT64] := '_u64';
16411663

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

1750-
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');
1772+
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');
17511773

17521774
method declare_var(QAST::Var $node) {
17531775
my int $type := self.type_from_typeobj($node.returns);

src/vm/js/Operations.nqp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ class QAST::OperationsJS {
147147

148148
method OBJ() { $T_OBJ }
149149
method INT() { $T_INT }
150+
method INT64() { $T_INT64 }
151+
method UINT64() { $T_UINT64 }
150152
method STR() { $T_STR }
151153
method NUM() { $T_NUM }
152154
method BOOL() { $T_BOOL }
@@ -182,6 +184,8 @@ class QAST::OperationsJS {
182184
add_assign_op('assign_n', $T_NUM);
183185
add_assign_op('assign_s', $T_STR);
184186

187+
add_assign_op('assign_i64', $T_INT64);
188+
add_assign_op('assign_u64', $T_UINT64);
185189

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

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

263+
264+
# 64 bit integer arithmetic
265+
add_simple_op('add_i64', $T_INT64, [$T_INT64, $T_INT64], sub ($a, $b) {"BigInt.asIntN(64, $a + $b)"});
266+
add_simple_op('sub_i64', $T_INT64, [$T_INT64, $T_INT64], sub ($a, $b) {"BigInt.asIntN(64, $a - $b)"});
267+
259268
add_op('chain', sub ($comp, $node, :$want) {
260269
my str $ret := $*BLOCK.add_tmp;
261270

src/vm/js/nqp-runtime/container-specs.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,54 @@ class NativeRef {
248248
this.set(value.$$getStr());
249249
}
250250
});
251+
} else if (primitiveType == 4) { // int64
252+
this.STable.addInternalMethods(class {
253+
$$iscont_s() {
254+
return 1;
255+
}
256+
257+
$$iscont() {
258+
return 1;
259+
}
260+
261+
$$isrwcont() {
262+
return 1;
263+
}
264+
265+
$$assign_i64(ctx, value) {
266+
this.set(value);
267+
}
268+
269+
$$assign_u64(ctx, value) {
270+
this.set(value);
271+
}
272+
273+
$$getStr() {
274+
return this.get().toString();
275+
}
276+
277+
$$getInt64() {
278+
return this.get();
279+
}
280+
281+
$$getUint64() {
282+
return BigInt.asUintN(64, this.get());
283+
}
284+
285+
$$decont(ctx) {
286+
let hll = STable.hllOwner;
287+
if (hll === undefined) {
288+
hll = ctx.codeRef().staticCode.hll;
289+
}
290+
291+
const type = hll.get('int_box');
292+
293+
const repr = type._STable.REPR;
294+
const obj = repr.allocate(type._STable);
295+
obj.$$setInt64(this.get());
296+
return obj;
297+
}
298+
});
251299
} else {
252300
throw 'incorrect type of NativeRef: ' + primitiveType;
253301
}

src/vm/js/nqp-runtime/core.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,18 @@ const intToObj = exports.intToObj = function(currentHLL, i) {
206206
}
207207
};
208208

209+
exports.int64ToObj = function(currentHLL, i) {
210+
const type = currentHLL.get('int_box');
211+
if (!type) {
212+
return new NQPInt(i);
213+
} else {
214+
const repr = type._STable.REPR;
215+
const obj = repr.allocate(type._STable);
216+
obj.$$setInt64(i);
217+
return obj;
218+
}
219+
};
220+
209221
const numToObj = exports.numToObj = function(currentHLL, n) {
210222
const type = currentHLL.get('num_box');
211223
if (!type) {
@@ -1159,7 +1171,7 @@ op.objprimspec = function(obj) {
11591171
} else if (obj instanceof NQPStr) {
11601172
return 3;
11611173
} else {
1162-
return (obj._STable && obj._STable.REPR.boxedPrimitive ? obj._STable.REPR.boxedPrimitive : 0);
1174+
return (obj._STable && obj._STable.REPR.boxedPrimitive ? obj._STable.REPR.boxedPrimitive() : 0);
11631175
}
11641176
} else {
11651177
throw new NQPException(`objprimspec can't handle things of type: ${typeof obj}`);

src/vm/js/nqp-runtime/refs.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ helpers.lexRef_i = function(currentHLL, get, set) {
106106
return ref;
107107
};
108108

109+
helpers.lexRef_i64 = function(currentHLL, get, set) {
110+
const refType = currentHLL.get('int64_lex_ref');
111+
if (refType === undefined) {
112+
throw 'No int64 lexical reference type registered for current HLL';
113+
}
114+
const STable = refType._STable;
115+
const ref = STable.REPR.allocate(STable);
116+
ref.get = get;
117+
ref.set = set;
118+
return ref;
119+
};
120+
121+
helpers.lexRef_u64 = helpers.lexRef_i64;
122+
109123
helpers.lexRef_s = function(currentHLL, get, set) {
110124
const refType = currentHLL.get('str_lex_ref');
111125
if (refType === undefined) {

0 commit comments

Comments
 (0)