Skip to content

Commit 8aac0c1

Browse files
committed
[js] Implement nqp::readint and nqp::readuint
1 parent 9217d68 commit 8aac0c1

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

src/vm/js/Operations.nqp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,8 @@ class QAST::OperationsJS {
19231923

19241924
add_simple_op('writeint', $T_VOID, [$T_OBJ, $T_INT, $T_INT, $T_INT], :side_effects);
19251925
add_simple_op('writeuint', $T_VOID, [$T_OBJ, $T_INT, $T_UINT32, $T_INT], :side_effects);
1926+
add_simple_op('readint', $T_INT, [$T_OBJ, $T_INT, $T_INT]);
1927+
add_simple_op('readuint', $T_UINT32, [$T_OBJ, $T_INT, $T_INT]);
19261928

19271929
method add_hll_unbox($hll, $type, $method_name) {
19281930
unless nqp::existskey(%hll_unbox, $hll) {

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

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,42 +1122,50 @@ const BINARY_SIZE_16_BIT = 4;
11221122
const BINARY_SIZE_32_BIT = 8;
11231123
const BINARY_SIZE_64_BIT = 12;
11241124

1125-
const isBigEndian = new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12;
1125+
const isNativelyBigEndian = new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12;
11261126

1127-
1128-
function writeIntToBuffer(isSigned, buffer, offset, value, flags) {
1127+
function isBigEndianFromFlags(flags) {
11291128
const endianFlags = flags & BINARY_ENDIAN_MASK;
1130-
const sizeFlags = flags & ~BINARY_ENDIAN_MASK;
1131-
1132-
let sizeInBytes;
1129+
return (endianFlags === BINARY_ENDIAN_BIG || (endianFlags == 0 && isBigEndian));
1130+
}
11331131

1132+
function sizeFromFlags(flags) {
1133+
const sizeFlags = flags & ~BINARY_ENDIAN_MASK;
11341134
if (sizeFlags == BINARY_SIZE_8_BIT) {
1135-
sizeInBytes = 1;
1135+
return 1;
11361136
} else if (sizeFlags == BINARY_SIZE_16_BIT) {
1137-
sizeInBytes = 2;
1137+
return 2;
11381138
} else if (sizeFlags == BINARY_SIZE_32_BIT) {
1139-
sizeInBytes = 4;
1139+
return 4;
11401140
} else if (sizeFlags == BINARY_SIZE_64_BIT) {
11411141
throw new NQPException('64bit writeint is not supported');
11421142
} else {
11431143
throw new NQPException('unsupported flags: ' + flags);
11441144
}
1145+
}
11451146

1147+
function writeIntToBuffer(isSigned, buffer, offset, value, flags) {
1148+
1149+
const sizeInBytes = sizeFromFlags(flags);
11461150
const lowlevelBuffer = Buffer.alloc(sizeInBytes);
11471151

1152+
const isBigEndian = isBigEndianFromFlags(flags);
1153+
11481154
const shift = 32 - sizeInBytes * 8;
11491155

1150-
if (endianFlags === BINARY_ENDIAN_BIG || (endianFlags == 0 && isBigEndian)) {
1151-
if (isSigned) {
1152-
lowlevelBuffer.writeIntBE((value << shift >> shift), 0, sizeInBytes);
1156+
if (isSigned) {
1157+
const wrapped = value << shift >> shift;
1158+
if (isBigEndian) {
1159+
lowlevelBuffer.writeIntBE(wrapped, 0, sizeInBytes);
11531160
} else {
1154-
lowlevelBuffer.writeUIntBE((value << shift >>> shift), 0, sizeInBytes);
1161+
lowlevelBuffer.writeIntLE(wrapped, 0, sizeInBytes);
11551162
}
1156-
} else if (endianFlags === BINARY_ENDIAN_LITTLE || (endianFlags == 0 && !isBigEndian)) {
1157-
if (isSigned) {
1158-
lowlevelBuffer.writeIntLE((value << shift >> shift), 0, sizeInBytes);
1163+
} else {
1164+
const wrapped = value << shift >>> shift;
1165+
if (isBigEndian) {
1166+
lowlevelBuffer.writeUIntBE(wrapped, 0, sizeInBytes);
11591167
} else {
1160-
lowlevelBuffer.writeUIntLE((value << shift >>> shift), 0, sizeInBytes);
1168+
lowlevelBuffer.writeUIntLE(wrapped, 0, sizeInBytes);
11611169
}
11621170
}
11631171

@@ -1172,6 +1180,12 @@ op.writeuint = function(buffer, offset, value, flags) {
11721180
writeIntToBuffer(false, buffer, offset, value, flags);
11731181
};
11741182

1183+
op.readuint = function(buffer, offset, flags) {
1184+
const sizeInBytes = sizeFromFlags(flags);
1185+
const rawData = rawSlice(buffer, offset, offset + sizeInBytes / byteSize(buffer));
1186+
return isBigEndianFromFlags(flags) ? rawData.readUIntBE(0, sizeInBytes) : rawData.readUIntLE(0, sizeInBytes);
1187+
};
1188+
11751189
op.encodeconf = function(str, encoding_, output, permissive) {
11761190
if (output.array.length) {
11771191
throw new NQPException('encode requires an empty array');
@@ -1222,14 +1236,18 @@ op.encoderep = function(str, encoding, replacement, output) {
12221236
};
12231237

12241238
function toRawBuffer(buf) {
1239+
return rawSlice(buf, 0, buf.array.length);
1240+
}
1241+
1242+
function rawSlice(buf, start, end) {
12251243
const elementSize = byteSize(buf);
12261244
const isUnsigned = buf.$$STable.REPR.type.$$STable.REPR.isUnsigned;
12271245
const array = buf.array;
12281246

12291247
const buffer = Buffer.allocUnsafe(array.length * elementSize);
12301248

12311249
let offset = 0;
1232-
for (let i = 0; i < array.length; i++) {
1250+
for (let i = start; i < end; i++) {
12331251
if (isUnsigned) {
12341252
buffer.writeUIntLE(array[i], offset, elementSize);
12351253
} else {

0 commit comments

Comments
 (0)