Skip to content

Commit 9217d68

Browse files
committed
[js] Implement nqp::writeint and nqp::writeuint and supporting contants
1 parent 86dbca4 commit 9217d68

File tree

4 files changed

+76
-5
lines changed

4 files changed

+76
-5
lines changed

src/vm/js/Operations.nqp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,9 @@ class QAST::OperationsJS {
19211921
add_simple_op('getjsattr', $T_OBJ, [$T_OBJ, $T_STR], :decont(0), :ctx);
19221922
add_simple_op('setjsattr', $T_OBJ, [$T_OBJ, $T_STR, $T_OBJ], :decont(0, 2), :ctx, :side_effects);
19231923

1924+
add_simple_op('writeint', $T_VOID, [$T_OBJ, $T_INT, $T_INT, $T_INT], :side_effects);
1925+
add_simple_op('writeuint', $T_VOID, [$T_OBJ, $T_INT, $T_UINT32, $T_INT], :side_effects);
1926+
19241927
method add_hll_unbox($hll, $type, $method_name) {
19251928
unless nqp::existskey(%hll_unbox, $hll) {
19261929
%hll_unbox{$hll} := nqp::hash();

src/vm/js/const_map.nqp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,12 @@ my %const_map := nqp::hash(
7777
'NORMALIZE_NFD', 2,
7878
'NORMALIZE_NFKC', 3,
7979
'NORMALIZE_NFKD', 4,
80+
81+
'BINARY_ENDIAN_LITTLE', 1,
82+
'BINARY_ENDIAN_BIG', 2,
83+
84+
'BINARY_SIZE_8_BIT', 0,
85+
'BINARY_SIZE_16_BIT', 4,
86+
'BINARY_SIZE_32_BIT', 8,
87+
'BINARY_SIZE_64_BIT', 12,
8088
);

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

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,19 +1099,79 @@ function byteSize(buf) {
10991099

11001100
exports.byteSize = byteSize;
11011101

1102-
function writeBuffer(highLevel, lowLevel) {
1102+
function writeBuffer(highLevel, highLevelOffset, lowLevel) {
11031103
const elementSize = byteSize(highLevel);
11041104
const isUnsigned = highLevel.$$STable.REPR.type.$$STable.REPR.isUnsigned;
11051105

11061106
let offset = 0;
11071107
for (let i = 0; i < lowLevel.length / elementSize; i++) {
1108-
highLevel.array[i] = isUnsigned ? lowLevel.readUIntLE(offset, elementSize) : lowLevel.readIntLE(offset, elementSize);
1108+
highLevel.array[highLevelOffset + i] = isUnsigned ? lowLevel.readUIntLE(offset, elementSize) : lowLevel.readIntLE(offset, elementSize);
11091109
offset += elementSize;
11101110
}
11111111
}
11121112

11131113
exports.writeBuffer = writeBuffer;
11141114

1115+
const BINARY_ENDIAN_LITTLE = 1;
1116+
const BINARY_ENDIAN_BIG = 2;
1117+
1118+
const BINARY_ENDIAN_MASK = BINARY_ENDIAN_LITTLE | BINARY_ENDIAN_BIG;
1119+
1120+
const BINARY_SIZE_8_BIT = 0;
1121+
const BINARY_SIZE_16_BIT = 4;
1122+
const BINARY_SIZE_32_BIT = 8;
1123+
const BINARY_SIZE_64_BIT = 12;
1124+
1125+
const isBigEndian = new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12;
1126+
1127+
1128+
function writeIntToBuffer(isSigned, buffer, offset, value, flags) {
1129+
const endianFlags = flags & BINARY_ENDIAN_MASK;
1130+
const sizeFlags = flags & ~BINARY_ENDIAN_MASK;
1131+
1132+
let sizeInBytes;
1133+
1134+
if (sizeFlags == BINARY_SIZE_8_BIT) {
1135+
sizeInBytes = 1;
1136+
} else if (sizeFlags == BINARY_SIZE_16_BIT) {
1137+
sizeInBytes = 2;
1138+
} else if (sizeFlags == BINARY_SIZE_32_BIT) {
1139+
sizeInBytes = 4;
1140+
} else if (sizeFlags == BINARY_SIZE_64_BIT) {
1141+
throw new NQPException('64bit writeint is not supported');
1142+
} else {
1143+
throw new NQPException('unsupported flags: ' + flags);
1144+
}
1145+
1146+
const lowlevelBuffer = Buffer.alloc(sizeInBytes);
1147+
1148+
const shift = 32 - sizeInBytes * 8;
1149+
1150+
if (endianFlags === BINARY_ENDIAN_BIG || (endianFlags == 0 && isBigEndian)) {
1151+
if (isSigned) {
1152+
lowlevelBuffer.writeIntBE((value << shift >> shift), 0, sizeInBytes);
1153+
} else {
1154+
lowlevelBuffer.writeUIntBE((value << shift >>> shift), 0, sizeInBytes);
1155+
}
1156+
} else if (endianFlags === BINARY_ENDIAN_LITTLE || (endianFlags == 0 && !isBigEndian)) {
1157+
if (isSigned) {
1158+
lowlevelBuffer.writeIntLE((value << shift >> shift), 0, sizeInBytes);
1159+
} else {
1160+
lowlevelBuffer.writeUIntLE((value << shift >>> shift), 0, sizeInBytes);
1161+
}
1162+
}
1163+
1164+
writeBuffer(buffer, offset, lowlevelBuffer);
1165+
};
1166+
1167+
op.writeint = function(buffer, offset, value, flags) {
1168+
writeIntToBuffer(true, buffer, offset, value, flags);
1169+
};
1170+
1171+
op.writeuint = function(buffer, offset, value, flags) {
1172+
writeIntToBuffer(false, buffer, offset, value, flags);
1173+
};
1174+
11151175
op.encodeconf = function(str, encoding_, output, permissive) {
11161176
if (output.array.length) {
11171177
throw new NQPException('encode requires an empty array');
@@ -1127,7 +1187,7 @@ op.encodeconf = function(str, encoding_, output, permissive) {
11271187
buffer = Buffer.from(str, encoding);
11281188
}
11291189

1130-
writeBuffer(output, buffer);
1190+
writeBuffer(output, 0, buffer);
11311191

11321192

11331193
return output;
@@ -1152,7 +1212,7 @@ op.encoderepconf = function(str, encoding_, replacement, output, permissive) {
11521212
throw new NQPException('encoding unsupported in encoderep');
11531213
}
11541214

1155-
writeBuffer(output, buffer);
1215+
writeBuffer(output, 0, buffer);
11561216

11571217
return output;
11581218
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ op.serialize = function(sc, sh) {
10021002
op.serializetobuf = function(sc, sh, type) {
10031003
const writer = new SerializationWriter(sc, sh.array);
10041004
const buffer = type.$$STable.REPR.allocate(type.$$STable);
1005-
core.writeBuffer(buffer, writer.serialize());
1005+
core.writeBuffer(buffer, 0, writer.serialize());
10061006
return buffer;
10071007
};
10081008

0 commit comments

Comments
 (0)