diff --git a/src/vm/js/Chunk.nqp b/src/vm/js/Chunk.nqp index a33fbc1cea..ebbadd6b91 100644 --- a/src/vm/js/Chunk.nqp +++ b/src/vm/js/Chunk.nqp @@ -11,6 +11,9 @@ my $T_INT8 := 7; # We use a javascript number but always treat it as a 8bit inte my $T_RETVAL := 8; # Something that will be returned from a sub/method call +my $T_UINT16 := 9; # We use a javascript number but always treat it as a 16bit integer +my $T_UINT8 := 10; # We use a javascript number but always treat it as a 8bit 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 diff --git a/src/vm/js/Compiler.nqp b/src/vm/js/Compiler.nqp index 15ef4dd6bd..6cb398fcea 100644 --- a/src/vm/js/Compiler.nqp +++ b/src/vm/js/Compiler.nqp @@ -438,7 +438,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { my int $type := self.type_from_typeobj($param.returns); my str $suffix := self.suffix_from_type($type); my sub unpack($value) { - if $type == $T_INT8 || $type == $T_INT16 { + if self.is_fancy_int($type) { self.int_to_fancy_int($type, "nqp.arg_i($*CTX, $value)"); } else { @@ -530,20 +530,30 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { Chunk.new($T_NONVAL, nqp::join(',', @sig), @setup); } + method is_fancy_int(int $type) { + $type == $T_INT8 + || $type == $T_INT16 + || $type == $T_UINT8 + || $type == $T_UINT16; + } + #= Convert a 32bit integer which is a result of js expr $expr into integer type $type for storage method int_to_fancy_int(int $type, str $expr) { if $type == $T_INT8 || $type == $T_INT16 { my int $shift := 32 - self.bits($type); "($expr << $shift >> $shift)"; + } elsif $type == $T_UINT8 || $type == $T_UINT16 { + my int $shift := 32 - self.bits($type); + "($expr << $shift >>> $shift)"; } else { $expr; } } method bits(int $type) { - if $type == $T_INT8 { + if $type == $T_INT8 || $type == $T_UINT8 { 8 - } elsif $type == $T_INT16 { + } elsif $type == $T_INT16 || $type == $T_UINT16 { 16 } else { nqp::die("We can't determine the number of bits for $type"); @@ -552,7 +562,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { method coerce(Chunk $chunk, $desired) { my int $got := $chunk.type; - my int $got_int := $got == $T_INT || $got == $T_INT16 || $got == $T_INT8; + my int $got_int := $got == $T_INT || self.is_fancy_int($got); if $got != $desired { if $desired == $T_VOID { @@ -672,6 +682,8 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { %convert{$T_INT} := 'intToObj'; %convert{$T_INT8} := 'intToObj'; %convert{$T_INT16} := 'intToObj'; + %convert{$T_UINT8} := 'intToObj'; + %convert{$T_UINT16} := 'intToObj'; %convert{$T_NUM} := 'numToObj'; %convert{$T_STR} := 'strToObj'; %convert{$T_RETVAL} := 'retval'; @@ -690,7 +702,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { } } - if $desired == $T_INT8 || $desired == $T_INT16 { + 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); } @@ -1526,11 +1538,12 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { my int $type := nqp::objprimspec($typeobj); if $type == 1 { my int $bits := nqp::objprimbits($typeobj); + my int $unsigned := nqp::objprimunsigned($typeobj); if $bits == 8 { - $T_INT8; + $unsigned ?? $T_UINT8 !! $T_INT8; } elsif $bits == 16 { - $T_INT16; + $unsigned ?? $T_UINT8 !! $T_INT16; } else { $T_INT; @@ -1543,7 +1556,7 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { my @suffix := ['', '_i', '_n', '_s']; method suffix_from_type($type) { - $type == $T_INT8 || $type == $T_INT16 ?? '_i' !! @suffix[$type]; + self.is_fancy_int($type) ?? '_i' !! @suffix[$type]; } multi method as_js(QAST::CompUnit $node, :$want) { @@ -1641,7 +1654,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'); + 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'); method declare_var(QAST::Var $node) { my int $type := self.type_from_typeobj($node.returns); @@ -1940,7 +1953,6 @@ class QAST::CompilerJS does DWIMYNameMangling does SerializeOnce { nqp::die('Cannot take a reference to a non-native lexical'); } - my int $is_fancy_int := $type == $T_INT8 || $type == $T_INT16; my str $suffix := self.suffix_from_type($type); my str $get := self.get_var($var); my str $set := self.set_var($var, self.int_to_fancy_int($type, 'value')); diff --git a/src/vm/js/Operations.nqp b/src/vm/js/Operations.nqp index 695014ac30..2849e8b830 100644 --- a/src/vm/js/Operations.nqp +++ b/src/vm/js/Operations.nqp @@ -867,6 +867,7 @@ class QAST::OperationsJS { add_simple_op('lexprimspec', $T_INT, [$T_OBJ, $T_STR]); add_simple_op('objprimspec', $T_INT, [$T_OBJ]); add_simple_op('objprimbits', $T_INT, [$T_OBJ]); + add_simple_op('objprimunsigned', $T_INT, [$T_OBJ]); add_simple_op('ctxouter', :!inlinable, $T_OBJ, [$T_OBJ]); @@ -1836,8 +1837,7 @@ class QAST::OperationsJS { %convert{$T_STR} := 'toStr'; %convert{$T_NUM} := 'toNum'; %convert{$T_INT} := 'toInt'; - my int $is_fancy_int := $desired == $T_INT8 || $desired == $T_INT16; - + my int $is_fancy_int := $comp.is_fancy_int($desired); nqp::die("Can't coerce OBJ to $desired") unless nqp::existskey(%convert, $desired) || $is_fancy_int; my str $rough_convert := 'nqp.' ~ %convert{$is_fancy_int ?? $T_INT !! $desired} ~ '(' ~ $chunk.expr ~ ", {$*CTX})"; diff --git a/src/vm/js/nqp-runtime/core.js b/src/vm/js/nqp-runtime/core.js index bae0768bad..606dc4f666 100644 --- a/src/vm/js/nqp-runtime/core.js +++ b/src/vm/js/nqp-runtime/core.js @@ -996,6 +996,10 @@ op.objprimbits = function(type) { return type._STable.REPR.bits; }; +op.objprimunsigned = function(type) { + return type._STable.REPR.isUnsigned ? 1 : 0; +}; + /* Parametricity operations. */ op.setparameterizer = function(ctx, type, parameterizer) { const st = type._STable; diff --git a/src/vm/js/nqp-runtime/runtime.js b/src/vm/js/nqp-runtime/runtime.js index 56e6111eaa..560d896fe0 100644 --- a/src/vm/js/nqp-runtime/runtime.js +++ b/src/vm/js/nqp-runtime/runtime.js @@ -539,6 +539,8 @@ const chunkNamesToTypes = { T_INT16: 6, T_INT8: 7, T_RETVAL: 8, + T_INT16: 9, + T_UINT8: 10, T_VOID: -1, T_NONVAL: -2,